Вопросы по С/С++ (СИ)

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Alpout
Открыл глаза
Сообщения: 77
Зарегистрирован: Вт сен 27, 2011 09:27:40

Re: Вопросы по С/С++ (СИ)

Сообщение Alpout »

аа, да точно. Спасибо!
Аватара пользователя
Волосатый
Сверлит текстолит когтями
Сообщения: 1288
Зарегистрирован: Пн апр 14, 2008 12:54:35
Откуда: Город ГЕРОЙ Ленинград
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение Волосатый »

Доброго всем вечера!

Не первый день бьюсь с такой неприятной проблемой. Имеем 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.
Что это за прикол и как его можно устранить?
Опыт приходит сразу после того, как он был нужен...
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

http://habrahabr.ru/post/142662/ почитайте про выравнивание структур.
Аватара пользователя
Волосатый
Сверлит текстолит когтями
Сообщения: 1288
Зарегистрирован: Пн апр 14, 2008 12:54:35
Откуда: Город ГЕРОЙ Ленинград
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение Волосатый »

Спасибо, хорошая статья. Сделал выравнивание, стало как надо :beer:
Опыт приходит сразу после того, как он был нужен...
pokk
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Re: Вопросы по С/С++ (СИ)

Сообщение pokk »

Добрый день, подскажите можно ли программно в текущей функции определить уровень её вложения?
Думал создать переменную и при входе в функцию её инкрементировать, а при выходе декрементировать.
Но выходов может быть много так что не вариант везде ставить. Хочу это по пробовать к отладке прикрутить что бы в Usart выдавался проход программы и можно было визуально видеть что функция завершается корректно.

Код: Выделить всё

function1=START
   function2=START
      function3=START
      function3=END
   function2=END
function1=END
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение ARV »

что мешает сделать ОДИН выход из функции, как того требует модульный стиль программирования?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
Siarzhuk
Потрогал лапой паяльник
Сообщения: 353
Зарегистрирован: Вс янв 19, 2014 22:41:55

Re: Вопросы по С/С++ (СИ)

Сообщение Siarzhuk »

pokk писал(а):подскажите можно ли программно в текущей функции определить уровень её вложения?

Запоминаем адрес локальной переменной из main, в функциях берем адрес местной локальной переменной и чешем по стеку от этого адреса до адреса переменной в main, прикидывая может-ли текущее значение стека быть адресом возврата функции - т.е. лежит-ли оно в сегменте кода. Ну или добавлять всем функциям фейковый параметр с уникальным паттерном и считать количество встреченных паттернов в стеке.
PS: Впрочем, в каждой шутке есть доля шутки. ;)
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! ;-)
Pnjom-Penb
Мучитель микросхем
Сообщения: 469
Зарегистрирован: Вс авг 30, 2015 03:52:59

Re: Вопросы по С/С++ (СИ)

Сообщение Pnjom-Penb »

Siarzhuk писал(а):... прикидывая может-ли текущее значение стека быть адресом возврата функции.
Напоминает басню "Волк и ягненок" - "Ты виноват уж потому, что хочется мне кушать смахиваешь на адрес возврата!". В общем - плюс/минус, пальцем в небо. :)))

Если ТСу почему-то не удается ограничиться одним выходом из функции, то он мог бы заменить многофайловым поиском с подстановкой все return'ы на, скажем, RETURN'ы или _return'ы, а их уже определить макросом, который раскрывается либо в return, либо в оператор декремента уровня вложенности, плюс return, в зависимости от того, что выдает "#ifdef _DEBUG_".
Последний раз редактировалось Pnjom-Penb Ср дек 09, 2015 21:50:34, всего редактировалось 1 раз.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение ARV »

в GCC можно для отладки выводить символьное имя текущей функции: см. https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
pokk
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Re: Вопросы по С/С++ (СИ)

Сообщение pokk »

Благодарю всех за ответ и за __func__ полезная штука.
ARV писал(а):что мешает сделать ОДИН выход из функции, как того требует модульный стиль программирования?

В том что программа написана в стиле КА, вот я и хочу отслеживать КА дошёл по последнего состояния или нет. Ну и смотреть как будет осуществляться доступ из нескольких КА к одному ресурсу.

Походу изначально то что я хотел было обреченно на провал. Так как два работающих параллельных КА будут напрочь рушить мою таблицу. Выход придумал только один написать свою терминальную программку которая будут выводить так как мне надо :)
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение ARV »

не вижу абсолютно никаких проблем сделать конечный автомат с одним входом и одним выходом.
изменил состояние КА - и на выход, напечатал новое состояние.

Код: Выделить всё

switch(state){
case STATE_1:
   state = STATE_5;
   break;
case STATE_2:
   state = STATE_1;
   break;
...
default:
   state = STATE_0;
}
debug_output(state);
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
pokk
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Re: Вопросы по С/С++ (СИ)

Сообщение 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]);
   }

Можно ли как нибудь без указателей это сделать?
Аватара пользователя
levaclaus
Потрогал лапой паяльник
Сообщения: 302
Зарегистрирован: Пн янв 07, 2008 16:56:28
Откуда: Минск

Re: Вопросы по С/С++ (СИ)

Сообщение 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);

При выполнении этого кода ещё ни разу не был верно записан год, с чего бы это?
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Re: Вопросы по С/С++ (СИ)

Сообщение shads »

Ех... давненько я не встречал засад в "вопросах по С" )))
Но вот вчерась уперся в феномен непонятный...

Суть в том, что есть модуль ADC который автоматом замеряет данные и пишет их в кольцевой 16 словный буфер.
Когда мне нужно, я вызываю процедурку, которая суммирует весь буфер и делит на те же 16... ну тобиш усреднение какое никакое...

Так вот прикол в том, что это при одном написании программы работает, а при другом (очевидной разницы абсолютно не наблюдаю) не работает...
Можно конечно чуть поменять конструкцию в главном файле, тогда начинает работать... но мне интересно почему именно в таком виде не работает???
Пример: Именно вот в таком виде - не работает, но если раскомментировать задержки по 1 мкс то начинает работать :shock:

Код: Выделить всё

//настройки
#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: Вопросы по С/С++ (СИ)

Сообщение Аlex »

Первым, что бросается в глаза - отсутствие атомарного доступа к данным буфера.
Видимо, с задержками, как то подгоняется к нормальному доступу.
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Re: Вопросы по С/С++ (СИ)

Сообщение shads »

Аlex писал(а):Первым, что бросается в глаза - отсутствие атомарного доступа к данным буфера.
Видимо, с задержками, как то подгоняется к нормальному доступу.
Кажется вы правы ))))))))))))
Доработал чтение буфера с учетом атомарного доступа и все заработало :))
Спасибо за столь быстрый и столь правильный пинок :oops:

Код: Выделить всё

//функция чтения усредненных данных 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: Вопросы по С/С++ (СИ)

Сообщение Аlex »

Лучше применить атомарный доступ ко всему буферу целиком, а не только отдельно к байтам в слове. Т.к. любая ячейка, как и байт в слове, может измениться в любой момент в прерывании, что может привести к неправильным расчётам.
Я бы запретил прерывания на время чтения всего буфера. Ну отложится ненадолго следующее преобразование, ничего страшного не случится...

И ещё, увидел sei в прерывании. Вы уверены, что всё делаете правильно ? Я, конечно, не знаю, как там и что сохраняется в АВРах при входе в обработчик, но всё-таки советую не делать таких финтов. Можно нарваться на неприятности.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение ARV »

Аlex писал(а):Лучше применить атомарный доступ ко всему буферу целиком, а не только отдельно к байтам в слове. Т.к. любая ячейка, как и байт в слове, может измениться в любой момент в прерывании, что может привести к неправильным расчётам.
маловероятно (хотя и не исключено полностью), что подсчет суммы буфера потребует времени больше, чем проходит между двумя циклическими преобразованиями АЦП, ведь АЦП обычно работает на довольно низкой скорости.
то есть за время суммирования в буфере может обновиться максимум 1 ячейка, что не приведет к погрешности при принятом способе усреднения, вероятность обновления сразу двух ячеек равна нулю... ну или почти равна (я ж не знаю частоты тактирования АЦП и ядра МК)
поэтому шансов получить неверный результат немного...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Pnjom-Penb
Мучитель микросхем
Сообщения: 469
Зарегистрирован: Вс авг 30, 2015 03:52:59

Re: Вопросы по С/С++ (СИ)

Сообщение Pnjom-Penb »

ARV писал(а):за время суммирования в буфере может обновиться максимум 1 ячейка, что не приведет к погрешности при принятом способе усреднения, ...
Вообще-то, буфер - кольцевой, то есть, может наступить себе на радиоя*ца только в результате алгоритмической ошибки. :dont_know:
Аватара пользователя
DX168B
Друг Кота
Сообщения: 4468
Зарегистрирован: Вс янв 24, 2010 19:19:52
Откуда: Главный Улей России (Moscow)
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение 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++ и раньше обходился без шаблонов.
Можно ли это реализовать через шаблоны и есть какая-нибудь удобоваримая литература по шаблонам?
I am DX168B and this is my favourite forum on internet!
Ответить

Вернуться в «Разные вопросы по МК»