Страница 329 из 421
Re: CodeVision AVR в вопросах и ответах
Добавлено: Пн дек 15, 2014 16:14:37
COKPOWEHEU
pokk писал(а):
Код: Выделить всё
#define crBegin static int state=0; switch(state) { case 0:
#define crReturn(i,x) do { state=i; return x; case i:; } while (0)
#define crFinish }
Вот это макросы! А не секрет, как эта магия работает? Особенно восхищает вот эта конструкция (смысловые блоки выделил форматированием).
Код: Выделить всё
switch(state){
case 0:
do{state=i; return x;
case 1:;
}while(0);
}
Удивительно, но оно работает!
Re: CodeVision AVR в вопросах и ответах
Добавлено: Пн дек 15, 2014 17:57:06
BCluster
Pink-Pank писал(а):Вообще не понимаю, зачем там do while, если в условии стоит 0?
Код: Выделить всё
#define smthToDo(ptr) do { \
ptr++;
ptr->destroy = 0; \
} while (0)
if (x)
smthToDo(x);
else
return x;
Попробуйте скомпилировать этот код без do...while(0)
точка с запятой перед else вызовет ошибку компиляции, придется писать уже так:
Код: Выделить всё
#define smthToDo(ptr) { \
ptr++;
ptr->destroy = 0; }
if (x)
smthToDo(x)
else
return x;
чтобы не думать в каких случаях писать ";", а в каких нет, заключают в цикл do...while(0)
pokk писал(а):#define crBegin static int state=0; switch(state) { case 0:
#define crReturn(i,x) do { state=i; return x; case i:; } while (0)
#define crFinish }
а вот это, простите, уже слишком. Бред, имхо
Re: CodeVision AVR в вопросах и ответах
Добавлено: Пн дек 15, 2014 19:16:48
ARV
а с каких пор точка с запятой перед else вызывает ошибку?!
Re: CodeVision AVR в вопросах и ответах
Добавлено: Пн дек 15, 2014 20:30:19
Pink-Pank
Попробуйте так писать - в этом случае Вам не страшен ни какой макрос и ни какие запятые.

И при этом Вы четко видите границы каждого блока, входящего в ту или иную часть условия/цикла.
Или ленитесь пару лишних скобок поставить? )
Кстати, Вы в макросе после ptr++; забыли поставить знак переноса строки - может поэтому у Вас и не компилируется.

Re: CodeVision AVR в вопросах и ответах
Добавлено: Пн дек 15, 2014 22:32:23
COKPOWEHEU
а с каких пор точка с запятой перед else вызывает ошибку?!
Всегда при использовании обычных фигурных скобок
Re: CodeVision AVR в вопросах и ответах
Добавлено: Вт дек 16, 2014 07:08:42
Pink-Pank
Это если у вас if не вложенный. А если вложенный в другой if, то может и скомпилиться, только программа будет работать не правильно.

Долго ошибку искать будете. Особенно используя макросы.
Пример:
if(y)
if (x) smthToDo(x)
; // Здесь точка с запятой завершает внутренний условный блок (наш макрос) и компилятор считает, что следующее за выражением
else относится к внешнему условному блоку.
else return x;
З.Ы. Не так давно 2 дня искал в программе ошибку.. Работала не так, как надо. Оказалось прошляпил точку с запятой после цикла while.. Думал, компилятор взбесился..
Re: CodeVision AVR в вопросах и ответах
Добавлено: Вт дек 16, 2014 09:50:40
pokk
Вот это макросы! А не секрет, как эта магия работает?
COKPOWEHEU,Я где-то приводил ссылку откуда их взял.
Если вкратце, то весь код должен находится внутри макросов crBegin crFinish
макрос crReturn(1,0); позволяет выйти из функции с сохранением место выхода и после вызова функции ещё раз мы перейдём в сохранённое место.
Если смотреть на тот код который приводил выше то функция Process_scan_Key_FSM крутится в главном цикле с аналогичными функциями т.е 1 итерация главного цикла примерно 200-700 тактов
Спойлер
Код: Выделить всё
unsigned char Process_scan_Key_FSM(unsigned char *data){
unsigned char temp;
//------------INIT---------------
crBegin *data=0; // Вход
Set_but_OK // выставляем на мультиплексоре адрес кнопки ОК
crReturn(1,0); // Выходим из функции с сохранением точки выхода
//>>>>>>>>Выход>>>>>>>>>>>>>>>>>>
// При следующем заходе в функцию переместимся суда
// при этом произойдёт задержка(на 1 проход главного цикла) на переключение мультиплексора.
Key_code2.OK=CTR_IN; // Считаем установившееся значение
Set_but_ESC // выставляем на мультиплексоре адрес кнопки ESC
crReturn(2,0); // Выходим из функции с сохранением точки выхода
//>>>>>>>>Выход>>>>>>>>>>>>>>>>>>
Key_code2.ESC=CTR_IN;
Set_but_UP
crReturn(3,0);
//>>>>>>>>Выход>>>>>>>>>>>>>>>>>>
Key_code2.UP=CTR_IN;
Set_but_DW
crReturn(4,0);
//>>>>>>>>Выход>>>>>>>>>>>>>>>>>>
Key_code2.DW=CTR_IN;
//-------------------------------
crFinish
*data=1;
return Key_code2;
}
По переменной *data я смотрю когда произойти полный опрос всех кнопок тогда же можно и начинать работать с переменной Key_code2 (правда в данной реализации у меня сделано всё наоборот по хорошему через return надо смотреть о завершении работы функции а через data выдавать данные)
Если развернуть все макросы то получится обычный switch case
Спойлер
Код: Выделить всё
unsigned char Process_scan_Key_FSM(unsigned char *data){
unsigned char temp;
static int state=0;
switch(state) {
case 0: *data=0;
Set_but_OK // выставляем на мультиплексоре адрес кнопки ОК
state=1; //crReturn(1,0)
return 0; //crReturn(1,0)
//>>>>>>>>Выход>>>>>>>>>>>>>>>>>>
case 1: //crReturn(1,0)
Key_code2.OK=CTR_IN; // Считаем установившееся значение
Set_but_ESC // выставляем на мультиплексоре адрес кнопки ESC
state=2; //crReturn(2,0)
return 0; //crReturn(2,0)
//>>>>>>>>Выход>>>>>>>>>>>>>>>>>>
case 2: //crReturn(2,0)
Key_code2.ESC=CTR_IN;
Set_but_UP
state=3; //crReturn(3,0)
return 0; //crReturn(3,0)
//>>>>>>>>Выход>>>>>>>>>>>>>>>>>>
case 3: //crReturn(3,0)
Key_code2.ESC=CTR_IN;
Set_but_UP
state=4;
return 0;
//>>>>>>>>Выход>>>>>>>>>>>>>>>>>>
//......case 4:
} //crFinish
//----------------------------------
*data=1;
return Key_code2;
}
Можно ещё заменить в макросе i на номер строки __LINE__ тогда можно вообще забыть про индексы case
Код: Выделить всё
#define crReturn(x) do { state=__LINE__; return x; case __LINE__:; } while (0)
Самое полезное что я нашёл если передавать в функцию структуру с state. То получается можно запустить одну и туже функцию на параллельную обработку разных данных.
Код: Выделить всё
#define ccrBegin(pt) switch((pt)->lc) { case 0:
#define ccrReturn(x) do { (pt)->lc=__LINE__; return x; case __LINE__:; } while (0)
#define ccrFinish } (pt)->lc=0;
Хотя такое можно сделать и без макросов
Re: CodeVision AVR в вопросах и ответах
Добавлено: Вт дек 16, 2014 16:58:34
BCluster
Pink-Pank писал(а):Кстати, Вы в макросе после ptr++; забыли поставить знак переноса строки - может поэтому у Вас и не компилируется.
да, забыл, но я говорил о другом же
Pink-Pank писал(а):if (x)
{
smthToDo(x);
}
можно так писать. А если кто другой твой макрос попробует использовать без {} будет капец )
Я вообще их стараюсь не использовать, но иногда это оправдано, и тогда do...while(0) самый надёжный вариант
Re: CodeVision AVR в вопросах и ответах
Добавлено: Ср дек 17, 2014 07:36:43
Pink-Pank
А если кто другой твой макрос попробует использовать без {} будет капец
Да, Ваш вариант с этой точки зрения надежнее, но человек, который не ставит фигурных скобок нарвется на ошибку где-то еще. )
Поэтому я себя приучил ставить их повсеместно в условных блоках и циклах, даже если внутри них всего один оператор. Так еще более надежно, да и нагляднее! )
Да и прежде, чем что-то использовать - желательно разобраться, как оно работает. )
Re: CodeVision AVR в вопросах и ответах
Добавлено: Ср дек 17, 2014 10:31:19
Аlex
Pink-Pank писал(а):Поэтому я себя приучил ставить их повсеместно в условных блоках и циклах, даже если внутри них всего один оператор. Так еще более надежно, да и нагляднее! )
Это всё частный случай привычки.
Я, например, стараюсь не ставить лишних скобок, по этому макросы всегда заключаю в
do{}while(0).
Ну а что касается остальных макросов ТС'а , это уже, имхо, - перебор

Они только путают читающего его код...
Re: CodeVision AVR в вопросах и ответах
Добавлено: Пн дек 29, 2014 21:43:56
Alexen
Всем привет. Можете подсказать как сделать чтобы при прерывании INT0 сначала считывался eeprom а потом исходя из данных в нем выполнялся код в прерывании?
Re: CodeVision AVR в вопросах и ответах
Добавлено: Пн дек 29, 2014 21:55:41
COKPOWEHEU
Добавить в начало кода прерывания процедуру чтения. Либо подробнее опишите задачу. При возникновении прерывания контроллер сохраняет адрес возврата в стеке и прыгает по заданному адресу, где расположен прыжок на обработчик.
Re: CodeVision AVR в вопросах и ответах
Добавлено: Вт дек 30, 2014 14:10:15
Alexen
С этим более-менее разобрался. А посоветуйте, устройство будут выключать примерно 20 раз в день, и флаг состояния будет сохранятся в eeprom, соответственно 20 раз) на долго ли хватит памяти, и как увеличить её ресурс?
Re: CodeVision AVR в вопросах и ответах
Добавлено: Вт дек 30, 2014 17:56:22
Jack_A
Один из способов : "размазывать" запись по доступному свободному объему EEPROM . Но тогда к зписываемой информации добавится еще счетчик-указатель. При чтении : находим запись с самым большим номером, считываем информацию из этого блока. При записи : находим запись с самым большим номером, инкрементируем номер, запись делаем уже ПОСЛЕ найденного места. Естественно, учитываем, что буфер кольцевой. Достаточно сумбурно изложил ?

Re: CodeVision AVR в вопросах и ответах
Добавлено: Вт дек 30, 2014 18:06:42
Alexen
Да в принципе смысл понятен, осталось попробовать как то сделать:)
Re: CodeVision AVR в вопросах и ответах
Добавлено: Вт дек 30, 2014 20:10:24
COKPOWEHEU
Согласно даташиту, количество циклов перезаписи у EEPROM 100000. Если перезаписывать 20 раз в день, этого хватит на 100000 / 20 = 5000 дней > 13 лет. Это без учета программных извращений и это гарантируется производителем. На практике раза в 3 больше. Кроме того, можно организовать резервное питание на батарейках или конденсаторах, и на время отключения основного засыпать. Или использовать внешнее статическое ОЗУ с собственным резервным питанием.
Re: CodeVision AVR в вопросах и ответах
Добавлено: Ср дек 31, 2014 14:50:08
isx
С НАСТУПАЮЩИМ!!!
Ребят, укусила собака бешеная замутить стробоскоп в последний день. Ставлю в тиньку 13 единственный код, а она мне хрень выдаёт, хотя в протеусе всё пашет.
Код: Выделить всё
PORTB.0 = 1;
delay_ms(50);
PORTB.0 = 0;
delay_ms(125);
PORTB.0 = 1;
delay_ms(50);
PORTB.0 = 0;
delay_ms(65);
PORTB.0 = 1;
delay_ms(50);
PORTB.0 = 0;
delay_ms(25);
PORTB.0 = 1;
delay_ms(50);
PORTB.0 = 0;
delay_ms(125);
PORTB.0 = 1;
delay_ms(50);
PORTB.0 = 0;
delay_ms(25);
PORTB.0 = 1;
delay_ms(50);
PORTB.0 = 0;
delay_ms(25);
PORTB.0 = 1;
delay_ms(50);
PORTB.0 = 0;
delay_ms(65);
PORTB.0 = 1;
delay_ms(50);
PORTB.0 = 0;
delay_ms(25);
К порту B к нулевому пину подведён IRLR2905 через резюк в 130 Ом, а к нему СД 10W.
Проще некуда. Но мигает эта хрень только с одним интервалом, а не с разными, как указано в коде.
От чего такое может быть?
Re: CodeVision AVR в вопросах и ответах
Добавлено: Ср дек 31, 2014 19:16:31
WiseLord
Вы на глаз отличаете интервалы меньше 150мс? Может, всё работает именно как надо? Хорошо бы осциллографом на ножке посмотреть (DDRB.0, надеюсь, тоже выставлен на выход?).
Re: CodeVision AVR в вопросах и ответах
Добавлено: Пт янв 02, 2015 15:54:34
Combatos
Всем привет! Как организовать вывод данных в разные порты, разные биты посредством массива, типа array[]={PORTD.1, PORTC.0, PORTB.7} (но така работать не будет). А как иначе? Помогите, кто знает
Re: CodeVision AVR в вопросах и ответах
Добавлено: Пт янв 02, 2015 19:41:24
uk8amk
Никак.
Такой фокус не проканает, поскольку у AVR отдельные биты не адресуются.
Если для вас это очень важно - переходите на ARM(там есть bit-band).