C для AVR -- пишем аккуратно.

Обсуждаем контроллеры компании Atmel.
Artos
Встал на лапы
Сообщения: 108
Зарегистрирован: Пт мар 04, 2011 13:06:42
Откуда: Украина, Ахтырка
Контактная информация:

Re: C для AVR -- пишем аккуратно.

Сообщение Artos »

shads писал(а):Гы..... С трудом узнал свою программу.....
Даже не верилось что она заработает, НО..... она работает.....
Спасибо за уделенное внимание. Хотя для понимания она стала сложнее (по крайней мере для меня, т.к. я тока начал писать на С), но надо будет обязательно разобраться, чего это вы там такого понаписали :)


А она разве работает?
Что то не пойму.. мне кажется код не рабочий...

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

void Receive(void)
{
    static unsigned char Step = 0,      //переменная шагов алгоритма
        BitHiPartCoun = 0,      //счетчик времени приема высокой части полу бита
        BitLoPartCoun = 0,      //счетчик времени приема низкой части полу бита
        BitCounter = 0;         //счетчик принятых бит

    //Step==0 инициализация приема серии
    if (Step == 0)
        BitCounter = 0;

    //Step==1 начало основного цикла приема бита
    if (Step < 2) {
        BitHiPartCoun = 0;
        BitLoPartCoun = 0;
    }
    //Step==2 обработка высокого уровня полубита
    if (Step < 3) {
        if (ReceivePort & ReceivePin) {
            Step = 2;
            if (BitHiPartCoun < 50)     //Подсчитываем длительность высокого уровня сигнала в линии
                BitHiPartCoun++;  // вот это как может инкрементироваться?
            return;
        }
    }


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

Re: C для AVR -- пишем аккуратно.

Сообщение ARV »

меня привлекла данная тема названием и автором - такое сочетание для меня равносильно указанию читать немедля. прочел всю тему.

сделал выводы:
1. avreal - красавчик, не перестаю удивляться. продолжайте в том же духе!
2. тема должна бы по идее называться не "пишем аккуратно", а как-то вроде "tips&triks avr-gcc" - тогда и пустопорожней "критики" было бы меньше.

сам я очень люболю и интересуюсь всякими возможностями сделать код не только красивым и понятным, но еще и максимально оптимальным. многие вещи, сказанные avreal, я знал, некоторые явились откровением. но уж во всяком случае по поводу пользы static у меня нет и не было никаких сомнений - вообще не понимаю тех, кто пытается с этим спорить!
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
ИС-пытатель
Вымогатель припоя
Сообщения: 577
Зарегистрирован: Ср июн 19, 2013 08:10:48
Откуда: Москва, СПб, Липецк, Рязань

Re: C для AVR -- пишем аккуратно.

Сообщение ИС-пытатель »

Тема интересная. Можно я тоже свой маленький вклад сделаю? )
Можно написать свой прологовый код в отдельном файле и подключить его при компиляции. Тогда КОТ еще уменьшится. )
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Re: C для AVR -- пишем аккуратно.

Сообщение shads »

ИС-пытатель писал(а):Тема интересная. Можно я тоже свой маленький вклад сделаю? )
Можно написать свой прологовый код в отдельном файле и подключить его при компиляции. Тогда КОТ еще уменьшится. )
Это как?..... Примерчик какой нить покажи...


Artos писал(а):А она разве работает?
Что то не пойму.. мне кажется код не рабочий...
Как может инкрементироваться счетчик, если мы вначале функции присваиваем переменным значения? :)
И код не полный... отсутствует закрывающая функцию скобка...
Насчет этого, чел сразу не разобрался... потом оказалось что все норм...
а так разговор тут начался http://forum.cxem.net/index.php?showtop ... try1846507
Аватара пользователя
ИС-пытатель
Вымогатель припоя
Сообщения: 577
Зарегистрирован: Ср июн 19, 2013 08:10:48
Откуда: Москва, СПб, Липецк, Рязань

Re: C для AVR -- пишем аккуратно.

Сообщение ИС-пытатель »

Это как?..... Примерчик какой нить покажи...


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

Re: C для AVR -- пишем аккуратно.

Сообщение DX168B »

Я бы к этому всему прибавил бы еще и заметки о переносимости и кроссплатформенности кода.
Причем обеспечить при этом и оптимальность в плане производительности, размеров и масштабируемость.

Чаще всего в этом плане стоит избегать использование переменных, таких как int в тех местах, где размер int критичен.
Ведь на разных платформах, этот тип имеет разную длину.
По умолчанию для восьмибитных архитектур:

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


int 
= short int = 16bit
short int 
= int = 16bit
long int 
= long int = 32bit


По умолчанию для 16-тибитных архитектур:

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


int 
= short int = 16bit
short int 
= int = 16bit
long int 
= long int = 32bit


По умолчанию для 32-хбитных архитектур:

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


int 
= long int = 32bit
short int 
= short int = 16bit
long int 
= long int = 32bit


Для решения этих проблем были придуманы иные типы и файл inttypes.h

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


int8_t 
= char = 8bit
int16_t 
= short int =16bit
int32_t 
= long int = 32bit
int64_t 
= __int64 = 64bit

Рекомендуется пользоваться ими, так как они четко указывают размер
типа для любой архитектуры и так-же могут сыграть роль и в размерах кода и его производительности.
К примеру, нет смысла применять в AVR uint32_t в цикле, где количество итераций этого цикла фиксированное
и меньше 255-ти. Там лучше применить uint8_t.

Структуры:
Недавно где-то читал статью, что допустим такой код:

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


uint8_t data
[4] = {1, 2, 3, 4};
......
uint32_t reg = ((data[3]<<24)|(data[2]<<16)|(data[1]<<8)| data[0]);
 

будет более затратным, чем применение union-структур. Даже были приведены тесты.
В таком случае, операции с union будут гарантированно сведены к простому копированию байт с одних ячеек
ОЗУ в другие (для распространенных архитектур). Сам не проверял, прошу знающих прокомментировать.

Сами структуры в AVR-ках стоит паковать директивой #pragma pack(1) перед определением структуры
или запускать компиляцию с ключом -fpack-struct
Эти приемы превращают структуру в сплошной массив и тем самым экономится память.
К примеру структура:

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


typedef struct _PackUartRcv
{
    uint16_t address;
    uint8_t cmd;
    uint32_t flags;
    uint16_t crc16;
}
PackUartRcv, *pPackUartRcv;
 

съест 16 байт, так как возникают пустоты в полях с типами меньшей длинны (когда-то я на эти грабли наступил)
А структура:

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

#pragma pack(1)
typedef struct _PackUartRcv
{
    uint16_t address;
    uint8_t cmd;
    uint32_t flags;
    uint16_t crc16;
}
PackUartRcv, *pPackUartRcv;
#pragma pack()
 

съест свои положенные 9 байт.
Плюс к этому, так можно разбирать принятые пакеты сразу в переменные,
если структуру при приеме использовать, как простой массив их uint8_t переменных.

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


uint8_t UART_Rcv
(uint8_t *buff, uint8_t sz_buff, uint16_t tmout);
...................
PackUartRcv PacketStruct;
.................
if(!
UART_Rcv((uint8_t*)&PacketStruct, sizeof(PackUartRcv), RCV_TIMEOUT))
{
    //пакет принят и тупо работаем с ним, как с полями структуры
    if(PacketStruct.crc16 != CRC16_Calc((uint8_t*)&PacketStruct,  sizeof(PackUartRcv), CRC_CONSTANT))
    {
        return ERROR_CRC;
    }
    //если все нормально, то работаем аналогично с данными пакета
    ........
    ........
}
 


И да. Статьи avreal ценны. Советую написать статью в разделы статей РадиоКота.
Материал полезный. :) :beer:
I am DX168B and this is my favourite forum on internet!
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: C для AVR -- пишем аккуратно.

Сообщение ARV »

что-то вы, DX168B, по поводу размеров типов написали странное... int обычно равен "родному размеру" архитектуры, пожтому для 32-битных int будет 32 бита, long int 64 бита, а short int 16...

и еще, uint8_t это unsigned char для 8-битных архитектур (т.е. char тоже платформозависимый тип и теоретически может быть более 8 бит)
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
FreshMan
Друг Кота
Сообщения: 6296
Зарегистрирован: Пн ноя 22, 2010 00:57:15
Откуда: Ukraine

Re: C для AVR -- пишем аккуратно.

Сообщение FreshMan »

ARV писал(а):int обычно равен "родному размеру" архитектуры, пожтому для 32-битных int будет 32 бита,

8 битных мк сие не касается ?
Tell Me The Truth
Аватара пользователя
DX168B
Друг Кота
Сообщения: 4468
Зарегистрирован: Вс янв 24, 2010 19:19:52
Откуда: Главный Улей России (Moscow)
Контактная информация:

Re: C для AVR -- пишем аккуратно.

Сообщение DX168B »

Нууууу..... насколько я знаю, char - символьный тип и обычно имеет размер 8 бит.
Конечно, символы и строки могут кодироваться и Юникодом, где на символ выделено по два байта.
Но обычно это дополнительная функция языка и тип там уже wchar или wchar_t.
Так уже устоялось, что размер обычного char - 8 бит.

ЗЫ: Я в курсе, что uint8_t - это unsigned char. :)
И еще. К примеру intelовский компилятор (Visual Studio) показал следующее:

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

#include <stdio.h>
#include <stdlib.h>


int main(int argc, char **argv)
{
    printf("\n Char = %d\n"
        " Short = %d\n"
        " Long = %d\n"
        " Int = %d\n", 
        sizeof
(char), 
        sizeof
(short int), 
        sizeof
(long int), 
        sizeof
(int));

    for(;;);
}
 

СпойлерИзображение


Размеры в байтах.
Long - по стандарту имеет размет 32 бита. Ну а int - верно. Принимает размер, равный разрядности архитектуры.
Для восьмибиток (в частности AVR) сделано исключение. Int там 16-битный.
На момент разработки языка, 32-битные архитектуры были еще экзотикой.

Тоже раньше проверялось и на STM32. С коллегой у нас был спор на пиво. Предметом спора
были размеры переменных. В итоге вывели в консоль (через UART) размеры всех типов и результат
был таким-же, как и на этом скриншоте. Компилятор был IARовским (IAR 6.30)
I am DX168B and this is my favourite forum on internet!
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Re: C для AVR -- пишем аккуратно.

Сообщение shads »

А я уже полностью перешел на uint8_t и подобные... очень удобно... Единственное, мой AvrStudio4.18 их не подсвечивал... но и это решилось http://digitalchip.ru/podsvetka-sintaksisa-avr-studio
Так что теперь - красота.....
Аватара пользователя
Jack_A
Друг Кота
Сообщения: 6307
Зарегистрирован: Вт апр 24, 2007 07:45:40
Откуда: Minsk

Re: C для AVR -- пишем аккуратно.

Сообщение Jack_A »

DX168B писал(а): Статьи avreal ценны. Советую написать статью в разделы статей РадиоКота.
:beer:

Поскольку автор потерял интерес к этому форуму, то вряд ли.
Аватара пользователя
Pink-Pank
Опытный кот
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США
Контактная информация:

Re: C для AVR -- пишем аккуратно.

Сообщение Pink-Pank »

Не смотря на все уважение к avreal не могу умолчать то, что данный способ выжимания соков из компилятора может привести к трудно обнаружимым ошибкам. Как пример, недавно в одной программе я использовал совет по принудительному размещению переменных в регистрах. Т.к. в моем коде был участок с критичным временем выполнения, то пришлось делать ассемблерную вставку, в которой с двумя такими переменными-регистрами я работал напрямую. А после компиляции оказалось, что программа работает не правильно. Долго мучился с листингом, пока нашел ошибку. Оказалось, что компилятор перед моей вставкой (почему-то именно перед ней.. :dont_know: ) скопировал мои два регистра с переменными в другие два регистра (помните из поста avreal: I like to move it, move it!) и после вставки использовал для сравнения эти две копии (вместо оригинальных регистров, которые во вставке менялись). Поэтому результат сравнения был не корректным и программа работала не правильно. Объявление переменных с квалификатором volatile приводило к генерации предупреждения "optimization may eliminate reads and/or writes to register variables" (Дословно: оптимизация может убрать операции чтения/записи в регистровую переменную), и по сути не меняло поведение компилятора. Отключить оптимизацию не мог, т.к. пользовался библиотечными функциями задержек. Пришлось бы все их переписывать и рассчитывать вручную. Таким образом, переменные типа volatile помещать в регистры не стоит. Пришлось еще дописывать вставку на само сравнение.
Нет, я не в коем случае не призываю не пользоваться возможностями, описанными товарищем avreal. Я всего лишь призываю пользоваться ими с осторожностью. Особенно в сочетании с другими возможностями.
Fucking static initialization order fiasco
Ответить

Вернуться в «AVR»