Вопросы по С/С++ (СИ)
Re: Вопросы по С/С++ (СИ)
аа, да точно. Спасибо!
- Волосатый
- Сверлит текстолит когтями
- Сообщения: 1288
- Зарегистрирован: Пн апр 14, 2008 12:54:35
- Откуда: Город ГЕРОЙ Ленинград
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Доброго всем вечера!
Не первый день бьюсь с такой неприятной проблемой. Имеем STM32F1xx c подключенной по I2C EEPROM 24c02 (она 256 байт). Для того, что бы писать в нее всякие настраиваемые параметры устройства (это переменные типа uint8_t, uint16_t, uint32_t) завел union вида:
Далее после включения эта структура заполняется из EEPROM и программа с ними работает. Раз в час текущие значения заносятся в EEPROM для поддержания их актуальности. Запись и чтение происходит передачей в функцию работы с I2C указателя на param.raw.
Я заметил, что перед переменой типа uint16_t в EEPROM одна пустая ячейка (она не перезаписывается), перед переменной uint32_t две ячейки. И само собой, от param_4_32 в EEPROM пишется только младший байт. Насколько я понял, считывается из EEPROM туда куда надо. Конечно можно докинуть на объединение еще 3 байта и успокоится, но это будет неэффективное использование EEPROM.
Что это за прикол и как его можно устранить?
Не первый день бьюсь с такой неприятной проблемой. Имеем 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;
};Я заметил, что перед переменой типа uint16_t в EEPROM одна пустая ячейка (она не перезаписывается), перед переменной uint32_t две ячейки. И само собой, от param_4_32 в EEPROM пишется только младший байт. Насколько я понял, считывается из EEPROM туда куда надо. Конечно можно докинуть на объединение еще 3 байта и успокоится, но это будет неэффективное использование EEPROM.
Что это за прикол и как его можно устранить?
Опыт приходит сразу после того, как он был нужен...
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
http://habrahabr.ru/post/142662/ почитайте про выравнивание структур.
- Волосатый
- Сверлит текстолит когтями
- Сообщения: 1288
- Зарегистрирован: Пн апр 14, 2008 12:54:35
- Откуда: Город ГЕРОЙ Ленинград
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Спасибо, хорошая статья. Сделал выравнивание, стало как надо 

Опыт приходит сразу после того, как он был нужен...
Re: Вопросы по С/С++ (СИ)
Добрый день, подскажите можно ли программно в текущей функции определить уровень её вложения?
Думал создать переменную и при входе в функцию её инкрементировать, а при выходе декрементировать.
Но выходов может быть много так что не вариант везде ставить. Хочу это по пробовать к отладке прикрутить что бы в Usart выдавался проход программы и можно было визуально видеть что функция завершается корректно.
Думал создать переменную и при входе в функцию её инкрементировать, а при выходе декрементировать.
Но выходов может быть много так что не вариант везде ставить. Хочу это по пробовать к отладке прикрутить что бы в Usart выдавался проход программы и можно было визуально видеть что функция завершается корректно.
Код: Выделить всё
function1=START
function2=START
function3=START
function3=END
function2=END
function1=END
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
что мешает сделать ОДИН выход из функции, как того требует модульный стиль программирования?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Re: Вопросы по С/С++ (СИ)
pokk писал(а):подскажите можно ли программно в текущей функции определить уровень её вложения?
Запоминаем адрес локальной переменной из main, в функциях берем адрес местной локальной переменной и чешем по стеку от этого адреса до адреса переменной в main, прикидывая может-ли текущее значение стека быть адресом возврата функции - т.е. лежит-ли оно в сегменте кода. Ну или добавлять всем функциям фейковый параметр с уникальным паттерном и считать количество встреченных паттернов в стеке.
PS: Впрочем, в каждой шутке есть доля шутки.
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! 
-
Pnjom-Penb
- Мучитель микросхем
- Сообщения: 469
- Зарегистрирован: Вс авг 30, 2015 03:52:59
Re: Вопросы по С/С++ (СИ)
Напоминает басню "Волк и ягненок" - "Ты виноват уж потому, что хочется мне кушать смахиваешь на адрес возврата!". В общем - плюс/минус, пальцем в небо.Siarzhuk писал(а):... прикидывая может-ли текущее значение стека быть адресом возврата функции.
Если ТСу почему-то не удается ограничиться одним выходом из функции, то он мог бы заменить многофайловым поиском с подстановкой все return'ы на, скажем, RETURN'ы или _return'ы, а их уже определить макросом, который раскрывается либо в return, либо в оператор декремента уровня вложенности, плюс return, в зависимости от того, что выдает "#ifdef _DEBUG_".
Последний раз редактировалось Pnjom-Penb Ср дек 09, 2015 21:50:34, всего редактировалось 1 раз.
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
в GCC можно для отладки выводить символьное имя текущей функции: см. https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Re: Вопросы по С/С++ (СИ)
Благодарю всех за ответ и за __func__ полезная штука.
В том что программа написана в стиле КА, вот я и хочу отслеживать КА дошёл по последнего состояния или нет. Ну и смотреть как будет осуществляться доступ из нескольких КА к одному ресурсу.
Походу изначально то что я хотел было обреченно на провал. Так как два работающих параллельных КА будут напрочь рушить мою таблицу. Выход придумал только один написать свою терминальную программку которая будут выводить так как мне надо
ARV писал(а):что мешает сделать ОДИН выход из функции, как того требует модульный стиль программирования?
В том что программа написана в стиле КА, вот я и хочу отслеживать КА дошёл по последнего состояния или нет. Ну и смотреть как будет осуществляться доступ из нескольких КА к одному ресурсу.
Походу изначально то что я хотел было обреченно на провал. Так как два работающих параллельных КА будут напрочь рушить мою таблицу. Выход придумал только один написать свою терминальную программку которая будут выводить так как мне надо
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
не вижу абсолютно никаких проблем сделать конечный автомат с одним входом и одним выходом.
изменил состояние КА - и на выход, напечатал новое состояние.
изменил состояние КА - и на выход, напечатал новое состояние.
Код: Выделить всё
switch(state){
case STATE_1:
state = STATE_5;
break;
case STATE_2:
state = STATE_1;
break;
...
default:
state = STATE_0;
}
debug_output(state);
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Re: Вопросы по С/С++ (СИ)
Добрый день, решил тут библиотеку шим для светодиодов написать.
Так как количество ШИМ изначально неизвестно, по этому решил сделать легкое создание нового шима (редактированием или добавлением define).
Так вот при создании нового ШИМ надо что бы прошла инициализации настроенных портов. В принципе через указатели можно это сделать, но не особо желаю (падает скорость работы с портом).
Пока выглядите это всё примерно так:
Можно ли как нибудь без указателей это сделать?
Так как количество ШИМ изначально неизвестно, по этому решил сделать легкое создание нового шима (редактированием или добавлением 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]);
}
Можно ли как нибудь без указателей это сделать?
- levaclaus
- Потрогал лапой паяльник
- Сообщения: 302
- Зарегистрирован: Пн янв 07, 2008 16:56:28
- Откуда: Минск
Re: Вопросы по С/С++ (СИ)
в часах стоит 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);
При выполнении этого кода ещё ни разу не был верно записан год, с чего бы это?
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: Вопросы по С/С++ (СИ)
Ех... давненько я не встречал засад в "вопросах по С" )))
Но вот вчерась уперся в феномен непонятный...
Суть в том, что есть модуль ADC который автоматом замеряет данные и пишет их в кольцевой 16 словный буфер.
Когда мне нужно, я вызываю процедурку, которая суммирует весь буфер и делит на те же 16... ну тобиш усреднение какое никакое...
Так вот прикол в том, что это при одном написании программы работает, а при другом (очевидной разницы абсолютно не наблюдаю) не работает...
Можно конечно чуть поменять конструкцию в главном файле, тогда начинает работать... но мне интересно почему именно в таком виде не работает???
Пример: Именно вот в таком виде - не работает, но если раскомментировать задержки по 1 мкс то начинает работать

ЗЫ Добавил файлы проекта и протеуса
Но вот вчерась уперся в феномен непонятный...
Суть в том, что есть модуль 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;
}ЗЫ Добавил файлы проекта и протеуса
- Вложения
-
- 111111111.png
- (18.02 КБ) 581 скачивание
-
- AVRST4_adc_test.7z
- (24.78 КБ) 142 скачивания
- Аlex
- Модератор
- Сообщения: 4614
- Зарегистрирован: Чт мар 18, 2010 23:09:57
- Откуда: Планета Земля
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Первым, что бросается в глаза - отсутствие атомарного доступа к данным буфера.
Видимо, с задержками, как то подгоняется к нормальному доступу.
Видимо, с задержками, как то подгоняется к нормальному доступу.
Re: Вопросы по С/С++ (СИ)
Кажется вы правы ))))))))))))А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);
}
- Аlex
- Модератор
- Сообщения: 4614
- Зарегистрирован: Чт мар 18, 2010 23:09:57
- Откуда: Планета Земля
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Лучше применить атомарный доступ ко всему буферу целиком, а не только отдельно к байтам в слове. Т.к. любая ячейка, как и байт в слове, может измениться в любой момент в прерывании, что может привести к неправильным расчётам.
Я бы запретил прерывания на время чтения всего буфера. Ну отложится ненадолго следующее преобразование, ничего страшного не случится...
И ещё, увидел sei в прерывании. Вы уверены, что всё делаете правильно ? Я, конечно, не знаю, как там и что сохраняется в АВРах при входе в обработчик, но всё-таки советую не делать таких финтов. Можно нарваться на неприятности.
Я бы запретил прерывания на время чтения всего буфера. Ну отложится ненадолго следующее преобразование, ничего страшного не случится...
И ещё, увидел sei в прерывании. Вы уверены, что всё делаете правильно ? Я, конечно, не знаю, как там и что сохраняется в АВРах при входе в обработчик, но всё-таки советую не делать таких финтов. Можно нарваться на неприятности.
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
маловероятно (хотя и не исключено полностью), что подсчет суммы буфера потребует времени больше, чем проходит между двумя циклическими преобразованиями АЦП, ведь АЦП обычно работает на довольно низкой скорости.Аlex писал(а):Лучше применить атомарный доступ ко всему буферу целиком, а не только отдельно к байтам в слове. Т.к. любая ячейка, как и байт в слове, может измениться в любой момент в прерывании, что может привести к неправильным расчётам.
то есть за время суммирования в буфере может обновиться максимум 1 ячейка, что не приведет к погрешности при принятом способе усреднения, вероятность обновления сразу двух ячеек равна нулю... ну или почти равна (я ж не знаю частоты тактирования АЦП и ядра МК)
поэтому шансов получить неверный результат немного...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
-
Pnjom-Penb
- Мучитель микросхем
- Сообщения: 469
- Зарегистрирован: Вс авг 30, 2015 03:52:59
Re: Вопросы по С/С++ (СИ)
Вообще-то, буфер - кольцевой, то есть, может наступить себе на радиоя*ца только в результате алгоритмической ошибки.ARV писал(а):за время суммирования в буфере может обновиться максимум 1 ячейка, что не приведет к погрешности при принятом способе усреднения, ...

- DX168B
- Друг Кота
- Сообщения: 4468
- Зарегистрирован: Вс янв 24, 2010 19:19:52
- Откуда: Главный Улей России (Moscow)
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Добрый день. Вопрос по C++
Имею класс с реализацией двусвязного списка со своими дополнениями.
Зовется он QLIST (не путать со сторонними библиотеками, так как он целиком и полностью является моим велосипедом)
Оперирует он структурами, типа:
ID нужен для того, чтобы можно было идентифицировать конкретный узел.
Указатели next и prev содержат адреса следующего и предыдущего узлов соответственно.
ptr - указатель типа void. В него собственно вкладывается адрес данных, ассоциированных с этим узлом.
А это деструктор класса:
Как видно, деструктор удаляет только узлы, а привязанные к узлам данные в памяти так и остаются.
Проблемы как бы нет, так как в программе я сначала перебираю весь список и удаляю привязанные данные,
за тем я удаляю сам объект класса. Но хотелось бы сделать так, чтобы деструктор класса удалял и данные.
Как я понимаю, этот механизм можно реализовать, пользуясь шаблонами классов.
Однако беда в том, что с шаблонами я совсем не дружу. Редко пишу на 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++ и раньше обходился без шаблонов.
Можно ли это реализовать через шаблоны и есть какая-нибудь удобоваримая литература по шаблонам?
I am DX168B and this is my favourite forum on internet!