Страница 229 из 386
Re: Вопросы по С/С++ (СИ)
Добавлено: Вт окт 27, 2015 13:40:08
Alpout
аа, да точно. Спасибо!
Re: Вопросы по С/С++ (СИ)
Добавлено: Вс ноя 29, 2015 21:15:17
Волосатый
Доброго всем вечера!
Не первый день бьюсь с такой неприятной проблемой. Имеем STM32F1xx c подключенной по I2C EEPROM 24c02 (она 256 байт). Для того, что бы писать в нее всякие настраиваемые параметры устройства (это переменные типа uint8_t, uint16_t, uint32_t) завел union вида:
Спойлер
Код: Выделить всё
union param_type{
uint8_t raw[8];
struct{
uint8_t param_1;
uint8_t param_2;
uint16_t param_3_16;
uint32_t param_4_32;
} param;
};
Далее после включения эта структура заполняется из EEPROM и программа с ними работает. Раз в час текущие значения заносятся в EEPROM для поддержания их актуальности. Запись и чтение происходит передачей в функцию работы с I2C указателя на param.raw.
Я заметил, что перед переменой типа uint16_t в EEPROM одна пустая ячейка (она не перезаписывается), перед переменной uint32_t две ячейки. И само собой, от param_4_32 в EEPROM пишется только младший байт. Насколько я понял, считывается из EEPROM туда куда надо. Конечно можно докинуть на объединение еще 3 байта и успокоится, но это будет неэффективное использование EEPROM.
Что это за прикол и как его можно устранить?
Re: Вопросы по С/С++ (СИ)
Добавлено: Вс ноя 29, 2015 21:48:36
WiseLord
http://habrahabr.ru/post/142662/ почитайте про выравнивание структур.
Re: Вопросы по С/С++ (СИ)
Добавлено: Пн ноя 30, 2015 02:29:08
Волосатый
Спасибо, хорошая статья. Сделал выравнивание, стало как надо

Re: Вопросы по С/С++ (СИ)
Добавлено: Ср дек 09, 2015 11:45:39
pokk
Добрый день, подскажите можно ли программно в текущей функции определить уровень её вложения?
Думал создать переменную и при входе в функцию её инкрементировать, а при выходе декрементировать.
Но выходов может быть много так что не вариант везде ставить. Хочу это по пробовать к отладке прикрутить что бы в Usart выдавался проход программы и можно было визуально видеть что функция завершается корректно.
Код: Выделить всё
function1=START
function2=START
function3=START
function3=END
function2=END
function1=END
Re: Вопросы по С/С++ (СИ)
Добавлено: Ср дек 09, 2015 12:30:02
ARV
что мешает сделать ОДИН выход из функции, как того требует модульный стиль программирования?
Re: Вопросы по С/С++ (СИ)
Добавлено: Ср дек 09, 2015 15:40:54
Siarzhuk
pokk писал(а):подскажите можно ли программно в текущей функции определить уровень её вложения?
Запоминаем адрес локальной переменной из main, в функциях берем адрес местной локальной переменной и чешем по стеку от этого адреса до адреса переменной в main, прикидывая может-ли текущее значение стека быть адресом возврата функции - т.е. лежит-ли оно в сегменте кода. Ну или добавлять всем функциям фейковый параметр с уникальным паттерном и считать количество встреченных паттернов в стеке.
PS: Впрочем, в каждой шутке есть доля шутки.

Re: Вопросы по С/С++ (СИ)
Добавлено: Ср дек 09, 2015 19:47:03
Pnjom-Penb
Siarzhuk писал(а):... прикидывая может-ли текущее значение стека быть адресом возврата функции.
Напоминает басню "Волк и ягненок" - "
Ты виноват уж потому, что хочется мне кушать смахиваешь на адрес возврата!". В общем - плюс/минус, пальцем в небо.
Если ТСу почему-то не удается ограничиться одним выходом из функции, то он мог бы заменить многофайловым поиском с подстановкой все
return'ы на, скажем,
RETURN'ы или
_return'ы, а их уже определить макросом, который раскрывается либо в
return, либо в оператор декремента уровня вложенности, плюс
return, в зависимости от того, что выдает "
#ifdef _DEBUG_".
Re: Вопросы по С/С++ (СИ)
Добавлено: Ср дек 09, 2015 20:30:16
ARV
в GCC можно для отладки выводить символьное имя текущей функции: см.
https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html
Re: Вопросы по С/С++ (СИ)
Добавлено: Чт дек 10, 2015 04:05:08
pokk
Благодарю всех за ответ и за __func__ полезная штука.
ARV писал(а):что мешает сделать ОДИН выход из функции, как того требует модульный стиль программирования?
В том что программа написана в стиле КА, вот я и хочу отслеживать КА дошёл по последнего состояния или нет. Ну и смотреть как будет осуществляться доступ из нескольких КА к одному ресурсу.
Походу изначально то что я хотел было обреченно на провал. Так как два работающих параллельных КА будут напрочь рушить мою таблицу. Выход придумал только один написать свою терминальную программку которая будут выводить так как мне надо

Re: Вопросы по С/С++ (СИ)
Добавлено: Чт дек 10, 2015 08:35:02
ARV
не вижу абсолютно никаких проблем сделать конечный автомат с одним входом и одним выходом.
изменил состояние КА - и на выход, напечатал новое состояние.
Код: Выделить всё
switch(state){
case STATE_1:
state = STATE_5;
break;
case STATE_2:
state = STATE_1;
break;
...
default:
state = STATE_0;
}
debug_output(state);
Re: Вопросы по С/С++ (СИ)
Добавлено: Пт дек 18, 2015 05:29:20
pokk
Добрый день, решил тут библиотеку шим для светодиодов написать.
Так как количество ШИМ изначально неизвестно, по этому решил сделать легкое создание нового шима (редактированием или добавлением define).
Так вот при создании нового ШИМ надо что бы прошла инициализации настроенных портов. В принципе через указатели можно это сделать, но не особо желаю (падает скорость работы с портом).
Пока выглядите это всё примерно так:
Код: Выделить всё
unsigned char* Mas_PORTx[MAX_PWM]={&PORTB,&PORTB,&PORTD,&PORTC};
unsigned char* Mas_DDRx[MAX_PWM]={&DDRB,&DDRB,&DDRD,&DDRC};
unsigned char Mas_Pin[MAX_PWM]={0,1,2,3};
for(i=0;i<MAX_PWM;i++){
ClearBit(*Mas_PORTx[i],Mas_Pin[i]);
SetBit(*Mas_DDRx[i],Mas_Pin[i]);
}
Можно ли как нибудь без указателей это сделать?
Re: Вопросы по С/С++ (СИ)
Добавлено: Вт дек 22, 2015 08:44:55
levaclaus
в часах стоит ds1307. При старте проводится проверка
rtc_get_time(&hour,&minute,&second);
if ((hour>24)||(minute>60)||(second>60))
rtc_set_time(15,35,0);
rtc_get_date(0,&date,&month,&year);
if ((date>31)||(month>12)||(year>99))
rtc_set_date(0,2,12,15);
При выполнении этого кода ещё ни разу не был верно записан год, с чего бы это?
Re: Вопросы по С/С++ (СИ)
Добавлено: Пт дек 25, 2015 09:08:11
shads
Ех... давненько я не встречал засад в "вопросах по С" )))
Но вот вчерась уперся в феномен непонятный...
Суть в том, что есть модуль ADC который автоматом замеряет данные и пишет их в кольцевой 16 словный буфер.
Когда мне нужно, я вызываю процедурку, которая суммирует весь буфер и делит на те же 16... ну тобиш усреднение какое никакое...
Так вот прикол в том, что это при одном написании программы работает, а при другом (очевидной разницы абсолютно не наблюдаю) не работает...
Можно конечно чуть поменять конструкцию в главном файле, тогда начинает работать... но мне интересно почему именно в таком виде не работает???
Пример: Именно вот в таком виде - не работает, но если раскомментировать задержки по 1 мкс то начинает работать
Код: Выделить всё
//настройки
#define F_CPU 1000000
#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
uint16_t AdcGet (void); //объявление
uint16_t AdcBuf [16]; //буфер накопитель
//Главный файл
int main (void)
{
//инит ADC
ADMUX = (0<<REFS1)| (1<<REFS0)| //в кач-ве ИОН питание контроллера
(0<<MUX3)| (0<<MUX2)| (0<<MUX1)| (0<<MUX0)| //канал ADC0
(0<<ADLAR); //выровнять вправо
ADCSRA = (1<<ADEN)| //вкл АЦП
(1<<ADFR)| //FREE RUNNING
(1<<ADIE)| //прерывание по завершению преобразования
(1<<ADPS2)| (1<<ADPS1)| (1<<ADPS0); //предделитель
ADCSR |= (1<<ADSC); //запустить преобразование
//настройка светика
DDRB |= (1<<6);
//главный цикл
sei ();
while(1){
uint16_t Adc = AdcGet();
//_delay_us (1);
if (Adc < 224){
PORTB |= (1<<6); //если ниже порога - включаем светик
while (1){
Adc = AdcGet();
//_delay_us (1);
if (Adc > 224) break;
}
PORTB &= ~(1<<6); //если выше порога - выключаем светик
}
}
}
//функция чтения усредненных данных ADC
uint16_t AdcGet (void)
{
uint16_t data = 0;
for (uint8_t i=0; i<16; i++)
data += AdcBuf [i];
return (data / 16);
}
//функция циклического опроса ADC
ISR (ADC_vect)
{
sei ();
static uint8_t counter;
AdcBuf [counter] = ADC;
if (++counter >= 16)
counter = 0;
}
ЗЫ Добавил файлы проекта и протеуса
Re: Вопросы по С/С++ (СИ)
Добавлено: Пт дек 25, 2015 09:14:10
Аlex
Первым, что бросается в глаза - отсутствие атомарного доступа к данным буфера.
Видимо, с задержками, как то подгоняется к нормальному доступу.
Re: Вопросы по С/С++ (СИ)
Добавлено: Пт дек 25, 2015 09:33:02
shads
Аlex писал(а):Первым, что бросается в глаза - отсутствие атомарного доступа к данным буфера.
Видимо, с задержками, как то подгоняется к нормальному доступу.
Кажется вы правы ))))))))))))
Доработал чтение буфера с учетом атомарного доступа и все заработало
Спасибо за столь быстрый и столь правильный пинок
Код: Выделить всё
//функция чтения усредненных данных ADC
uint16_t AdcGet (void)
{
uint16_t data = 0;
for (uint8_t i=0; i<16; i++){
cli ();
data += AdcBuf [i];
sei ();
}
return (data / 16);
}
Re: Вопросы по С/С++ (СИ)
Добавлено: Пт дек 25, 2015 10:25:35
Аlex
Лучше применить атомарный доступ ко всему буферу целиком, а не только отдельно к байтам в слове. Т.к. любая ячейка, как и байт в слове, может измениться в любой момент в прерывании, что может привести к неправильным расчётам.
Я бы запретил прерывания на время чтения всего буфера. Ну отложится ненадолго следующее преобразование, ничего страшного не случится...
И ещё, увидел sei в прерывании. Вы уверены, что всё делаете правильно ? Я, конечно, не знаю, как там и что сохраняется в АВРах при входе в обработчик, но всё-таки советую не делать таких финтов. Можно нарваться на неприятности.
Re: Вопросы по С/С++ (СИ)
Добавлено: Пт дек 25, 2015 15:14:07
ARV
Аlex писал(а):Лучше применить атомарный доступ ко всему буферу целиком, а не только отдельно к байтам в слове. Т.к. любая ячейка, как и байт в слове, может измениться в любой момент в прерывании, что может привести к неправильным расчётам.
маловероятно (хотя и не исключено полностью), что подсчет суммы буфера потребует времени больше, чем проходит между двумя циклическими преобразованиями АЦП, ведь АЦП обычно работает на довольно низкой скорости.
то есть за время суммирования в буфере может обновиться максимум 1 ячейка, что не приведет к погрешности при принятом способе усреднения, вероятность обновления сразу двух ячеек равна нулю... ну или почти равна (я ж не знаю частоты тактирования АЦП и ядра МК)
поэтому шансов получить неверный результат немного...
Re: Вопросы по С/С++ (СИ)
Добавлено: Пт дек 25, 2015 18:16:11
Pnjom-Penb
ARV писал(а):за время суммирования в буфере может обновиться максимум 1 ячейка, что не приведет к погрешности при принятом способе усреднения, ...
Вообще-то, буфер - кольцевой, то есть, может наступить себе на радиоя*ца только в результате алгоритмической ошибки.

Re: Вопросы по С/С++ (СИ)
Добавлено: Вс янв 17, 2016 12:32:29
DX168B
Добрый день. Вопрос по C++
Имею класс с реализацией двусвязного списка со своими дополнениями.
Зовется он
QLIST (не путать со сторонними библиотеками, так как он целиком и полностью является моим велосипедом)
Оперирует он структурами, типа:
Код: Выделить всё
typedef struct _tag_Node
{
long int nodeId;
Node *next;
Node *prev;
void *ptr;
}Node, *pNode;
ID нужен для того, чтобы можно было идентифицировать конкретный узел.
Указатели next и prev содержат адреса следующего и предыдущего узлов соответственно.
ptr - указатель типа void. В него собственно вкладывается адрес данных, ассоциированных с этим узлом.
А это деструктор класса:
Код: Выделить всё
////////////////////////////////////////////////////////////////////////////
QLIST::~QLIST()
{ // Удаление всех записей по уничтожению объекта (деструктор класса QLIST)
NdPoint = NdFirst; // Присваиваем рабочему указателю адрес первого элемента
while(NdPoint != 0) // Цикл не выполнит ни одну итерацию, если список был пустым и прервется по удалению последнего элемента
{
NdFirst = NdPoint->next; // Присваиваем в качестве первого элемента следующий.
//Если там NULL, то он далее скопируется NdPoint и цикл завершится.
delete NdPoint; // Удаляем текущий
NdPoint = NdFirst; // Присваиваем первый элемент в качестве текущего.
}
}
Как видно, деструктор удаляет только узлы, а привязанные к узлам данные в памяти так и остаются.
Проблемы как бы нет, так как в программе я сначала перебираю весь список и удаляю привязанные данные,
за тем я удаляю сам объект класса. Но хотелось бы сделать так, чтобы деструктор класса удалял и данные.
Как я понимаю, этот механизм можно реализовать, пользуясь шаблонами классов.
Однако беда в том, что с шаблонами я совсем не дружу. Редко пишу на C++ и раньше обходился без шаблонов.
Можно ли это реализовать через шаблоны и есть какая-нибудь удобоваримая литература по шаблонам?