WinAvr в вопросах и ответах
Переходит не по очереди 357,358, 370 а в произвольном порядке. Как на дизасме все идет, а ни как в листинге Си. То есть очередность команд нарушается. Сначала присваивается значение переменной, потом идет (не известно почему) InvBit(test), потом возвращается назад и потом только по очереди.
Как зачем мне голова?! Я ей ем!!!
- Реклама
Код: Выделить всё
1) _rfid_i = 0x08;
do{
2) _rfid_i--;
3) _rfid_j = 0x08;
4) _byte_key = *((unsigned char *)&_rfid_to_sent_array + _rfid_i - 1);
do{
_rfid_j--;
if((_byte_key & 0x80) == 0x80) {ClrBit(TEST); NOP;}
else {SetBit(TEST); NOP;}
InvBit(TEST);
NOP;
_byte_key = _byte_key << 1;
}
}
Код: Выделить всё
1)_rfid_i = 0x08;
2) _rfid_j = 0x08;
3) InvBit(TEST);
4) _rfid_i--;
5) _rfid_j = 0x08;
Как зачем мне голова?! Я ей ем!!!
судя по всему, вас вводит в смущение работа оптимизатора. кроме этого, неизвестно, как там определены ваши переменные и что с ними происходит, поэтому оптимизатор может кое-что сделать по-своему, не нарушив при этом общей логики программы.
отключите оптимизацию, и вы увидите, что порядок исполнения "правильный". кажущийся неправильным порядок исполнения оптимизированного кода приведет к правильному результату - бояться не стоит. а если программа у вас работает не так, как надо - это означает, что вы где-то допустили ошибку.
отключите оптимизацию, и вы увидите, что порядок исполнения "правильный". кажущийся неправильным порядок исполнения оптимизированного кода приведет к правильному результату - бояться не стоит. а если программа у вас работает не так, как надо - это означает, что вы где-то допустили ошибку.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Самое интересное, что с любой оптимизацией и "чистым" мейкфайлом ни чего не меняется. Проблема "уходит", когда из тела функции выкидываю все циклы и тогда все идет как надо. Вообще это функция выплевывания кода карточки EM-marine в порт... Простейшая вроде бы задача когда все готово и остается только вывести результат.... Но вот такой затык произошел...
Еще как вариант, возможно ли, что такое возникает от неправильного (ну или еще какого-то) определения и пользования указателей? Хотя тогда причем тут циклы?... Я в недоумении...
Ах да, Из-за этих "оптимизаций" компилятора половина кода на выдаче съедается.... Т.е. начинается обработка функции, код начинает скакать, но потом видимо попадает в нужное место и все идет пучком.
P.S. Запрещаю все прерывания на время выполнения функции..
Полностью со всеми используемыми переменными функция выглядит так:
Сильно не бить если где накосячил, у меня глаз замылен совсем...
Еще как вариант, возможно ли, что такое возникает от неправильного (ну или еще какого-то) определения и пользования указателей? Хотя тогда причем тут циклы?... Я в недоумении...
Ах да, Из-за этих "оптимизаций" компилятора половина кода на выдаче съедается.... Т.е. начинается обработка функции, код начинает скакать, но потом видимо попадает в нужное место и все идет пучком.
P.S. Запрещаю все прерывания на время выполнения функции..
Полностью со всеми используемыми переменными функция выглядит так:
Код: Выделить всё
volatile unsigned char _rfid_timer_owf = 0x00; //переполнение таймера произошло N -раз
unsigned char _byte_key = 0; //побайтное чтение из ключа
unsigned char _rfid_i = 0, _rfid_j = 0, _rfid_k = 0; //глобальные счетчики
#define _rfid_def_timer 0xFF00; //стартовое значение таймера до переполнения 16 us при 16 МГц
#define Timer_CS TCCR3B = _BV(CS30) //предделитель на 1 (start)
#define Timer_Def TCNT3 = _rfid_def_timer //0xFFFF = ~30.02 us owerflow для freq = 7.3728 MHz
#define Timer_TOIE_ON TIMSK = _BV(TOIE3) //разрешить прерывание по переполнению
#define Timer_TOIE_OFF TIMSK &= ~TOIE3 //запретить прерывание по переполнению
#define Timer_Start {Timer_Def; Timer_CS;_rfid_timer_owf = 0x00; NOP;} //присваиваю начальное значение таймера, обнуляю счетчик переполнений таймера и пускаю таймер
#define Timer_Stop TCCR3B = 0x00 //предделитель на 0 (stop)
#define _rfid_mod_time ((_rfid_time[0] + _rfid_time[1]) >> 1)
#define _rfid_white_delay {while(_rfid_timer_owf < _rfid_mod_time){if(_rfid_timer_owf == _rfid_mod_time) _rfid_timer_owf = 0;}}
void EEPROM_Read_Long(unsigned int addr, unsigned char * new_value){
i = 8;
do{
i--;
*(new_value+i) = EEPROM_Read_Byte((unsigned int)(addr+i));
}while(i > 0);
NOP;
}
void RFID_Sent_Key(void){
Timer_TOIE_OFF; //запретить прерывание по переполнению
cli();
EEPROM_Read_Long((unsigned int)&_rfid_to_sent_EEPROM, (unsigned char *)&_rfid_to_sent_array); //записываю адрес ключа в еепром
sei(); //разрешаю все прерывания
Timer_TOIE_ON; //разрешить прерывание по переполнению
Timer_Start; //запускаю счетчик на переполнение
_rfid_i = 0x08;
do{
_rfid_i--;
_rfid_j = 0x08;
_byte_key = *((unsigned char *)&_rfid_to_sent_array + _rfid_i - 1);
do{
_rfid_j--;
if((_byte_key & 0x80) == 0x80) {ClrBit(TEST); NOP;}
else {SetBit(TEST); NOP;}
_rfid_white_delay;
InvBit(TEST);
NOP;
_rfid_white_delay;
_byte_key = _byte_key << 1;
}while(_rfid_j > 0x00);
}while(_rfid_i > 0x00);
Timer_TOIE_OFF; //запретить прерывание по переполнению
}
Сильно не бить если где накосячил, у меня глаз замылен совсем...
Последний раз редактировалось MOHOXPOM Вт июн 22, 2010 12:23:07, всего редактировалось 1 раз.
Как зачем мне голова?! Я ей ем!!!
лень вникать, но что сразу бросается в глаза:
...
#define Timer_TOIE_ON TIMSK = _BV(TOIE3) //разрешить прерывание по переполнению
если прерывание единственное, то ничего страшного (надо TIMSK |= _BV(TOIE3))
#define Timer_TOIE_OFF TIMSK ^= _BV(TOIE3) //запретить прерывание по переполнению
не запретить а "проинвертировать"
надо: TIMSK &= ~_BV(TOIE3)
...
void RFID_Sent_Key(void){
получается, что здесь разрешаем...
Timer_TOIE_OFF; //запретить прерывание по переполнению
...
здесь опять разрешаем...
Timer_TOIE_ON; //разрешить прерывание по переполнению
...
здесь запрещаем
Timer_TOIE_OFF; //запретить прерывание по переполнению
}
...
#define Timer_TOIE_ON TIMSK = _BV(TOIE3) //разрешить прерывание по переполнению
если прерывание единственное, то ничего страшного (надо TIMSK |= _BV(TOIE3))
#define Timer_TOIE_OFF TIMSK ^= _BV(TOIE3) //запретить прерывание по переполнению
не запретить а "проинвертировать"
надо: TIMSK &= ~_BV(TOIE3)
...
void RFID_Sent_Key(void){
получается, что здесь разрешаем...
Timer_TOIE_OFF; //запретить прерывание по переполнению
...
здесь опять разрешаем...
Timer_TOIE_ON; //разрешить прерывание по переполнению
...
здесь запрещаем
Timer_TOIE_OFF; //запретить прерывание по переполнению
}
- Реклама
Ну вы правы прерывание не единственное, так что надо ^ делать. Отключение, включение а потом снова отключение из-за того, что тот же таймер работает на обработку приема кода. И тайминги новые заводить не было смысла.
Как зачем мне голова?! Я ей ем!!!
Ваш первый "вызов" макро Timer_TOIE_OFF как раз ВКЛЮЧАЕТ прерывание.MOHOXPOM писал(а):Ну вы правы прерывание не единственное, так что надо ^ делать. Отключение, включение а потом снова отключение из-за того, что тот же таймер работает на обработку приема кода. И тайминги новые заводить не было смысла.
операция XOR, она-же "исключающее ИЛИ", т.е. оператор "^" в Си в данном случае просто меняет 0 на 1 и наоборот.
Если надо установить бит - пишем: <РЕГИСТР> |= <НУЖНЫЙ БИТ, СДВИНУТЫЙ КУДА НАДО>, т.е. по "ИЛИ", не "портя" остальные биты.
если надо сбросить бит - пишем: <РЕГИСТР> &= ~ <СДВИНУТЫЙ БИТ, КУДА НАДО>.
В Вашем примере, как я написал изначально, Timer_TOIE_OFF просто меняет разрешение на запрещение прерывания при каждом "вызове", и наоборот. т.е. в Вашем случае:
func(){
Timer_TOIE_OFF; // включили прерывание
Timer_TOIE_OFF; // выключили прерывание
Timer_TOIE_OFF; // включили прерывание
Timer_TOIE_OFF; // выключили прерывание
...
}
не путайте битовые ИЛИ - |, И - & и ИСКЛЮЧАЮЩЕЕ ИЛИ - ^.
еще вопрос: а зачем куча NOP'ов?
Ну в принципе, я использую сначала ON и потом OFF. Так что один раз ставлю бит, а потом его инвертирую. А NOPы округляют задержку до 17.5 us при данном значении кварца и устаканивается значение в порту. Т.е. следующее действие при работе с портом хоть как сразу не даст его изменить. Ну примерно так:
default PB0 = 0
1) Set PB0 - NOP - Clr PB0
будет 0 - 1 - (держим такт) - 0
2) Set PB0 - Clr PB0
будет 0 - 1 - 0
и тут оптимизация пройдет... и PB0 останется без изменений, т.е. = 0
default PB0 = 0
1) Set PB0 - NOP - Clr PB0
будет 0 - 1 - (держим такт) - 0
2) Set PB0 - Clr PB0
будет 0 - 1 - 0
и тут оптимизация пройдет... и PB0 останется без изменений, т.е. = 0
Как зачем мне голова?! Я ей ем!!!
Но проблема этим не решилась и решиться не могла...
Вопрос еще. Как организовать задержку в функции на несколько переполнений таймера? Может есть отточенное решение? А то я через while() делаю в теле функции, который сравнивает значение каунтера декрементируемого в обработчике прерывания по переполнению счетчика.
Вопрос еще. Как организовать задержку в функции на несколько переполнений таймера? Может есть отточенное решение? А то я через while() делаю в теле функции, который сравнивает значение каунтера декрементируемого в обработчике прерывания по переполнению счетчика.
Как зачем мне голова?! Я ей ем!!!
не понял... вы хотите сказать, что участок кодаMOHOXPOM писал(а):2) Set PB0 - Clr PB0
будет 0 - 1 - 0
и тут оптимизация пройдет... и PB0 останется без изменений, т.е. = 0
Код: Выделить всё
PORTB |= _BV(PB0);
PORTB &= ~_BV(PB0);этого не может быть, т.к. PORTB определен в WinAVR как volatile, поэтому никогда не будет затронут оптимизатором.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
я все пытаюсь сказать, что нужно написать вот так:
а не так, как в приведенном исходном тексте:
а то получается, что Timer_TOIE_OFF первым вызовом РАЗРЕШАЕТ прерывание
Код: Выделить всё
#define Timer_TOIE_ON TIMSK |= _BV(TOIE3); //разрешить прерывание по переполнению
#define Timer_TOIE_OFF TIMSK &= ~_BV(TOIE3); //запретить прерывание по переполнению
Код: Выделить всё
#define Timer_TOIE_ON TIMSK = _BV(TOIE3) //разрешить прерывание по переполнению
#define Timer_TOIE_OFF TIMSK ^= _BV(TOIE3) //запретить прерывание по переполнению
Да поменял уже говорю. В предыдущем посте описал.
Как зачем мне голова?! Я ей ем!!!
В симуляторе и при трассировке в протеусе получаются иногда очень интересные и разные вариантыARV писал(а):не понял... вы хотите сказать, что участок кода
Код: Выделить всё
DDRB = 0xFF; NOP;
PORTB = 0xFF; NOP;
PORTB = 0x00; NOP;
PORTB = 0xFF; NOP;
PORTB = 0x00; NOP;
Код: Выделить всё
DDRB = 0xFF;
PORTB = 0xFF;
PORTB = 0x00;
PORTB = 0xFF;
PORTB = 0x00;
Как зачем мне голова?! Я ей ем!!!
уважаемый МОНОХРОМ! я не стану маяться ерундой, проверяя в симуляторе то, в чем уверен на 100% - не первый день работаю с WinAVR и никогда не сталкивался с тем, чтобы работа с портом искажалась оптимизатором или чем-либо еще! думаю, и никто не сталкивался с этим. на всякий случай, сообщите, какая версия WinAVR у вас? у меня 20100110, но и с тремя предыдущими никаких проблем не было!
кстати, на счет порядка исполнения строк. в протеусе вчера сам видел чудо: есть static-функция, которая вызывается при очень хитром условии из глубины основного цикла. однако в протеусе при пошаговом выполнении я вижу. что содержимое этой функции "выполняется" едва ли не самым первым, еще до входа в главный цикл. тем не менее переменные, которые эта функция изменяет, остаются неизменными, а просмотр ассемблерных команд показывает, что на самом деле исполняются НЕ ЭТИ операторы. то есть из-за работы оптимизатора произошло такое сильное перемешивание ассемблерных команд, что сопоставить им строку в исходнике на Си не вышло - и строка программы выводится отладчиком неверно. разумеется, все сигналы программа выдает правильно, хотя по отладчику этого не заметно. бывали случаи и неожиданного исполнения цикла while не с первого оператора, а откуда-то из середины - тем не менее все работает верно, это особенность работы отладчика после оптимизатора.
кстати, на счет порядка исполнения строк. в протеусе вчера сам видел чудо: есть static-функция, которая вызывается при очень хитром условии из глубины основного цикла. однако в протеусе при пошаговом выполнении я вижу. что содержимое этой функции "выполняется" едва ли не самым первым, еще до входа в главный цикл. тем не менее переменные, которые эта функция изменяет, остаются неизменными, а просмотр ассемблерных команд показывает, что на самом деле исполняются НЕ ЭТИ операторы. то есть из-за работы оптимизатора произошло такое сильное перемешивание ассемблерных команд, что сопоставить им строку в исходнике на Си не вышло - и строка программы выводится отладчиком неверно. разумеется, все сигналы программа выдает правильно, хотя по отладчику этого не заметно. бывали случаи и неожиданного исполнения цикла while не с первого оператора, а откуда-то из середины - тем не менее все работает верно, это особенность работы отладчика после оптимизатора.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Вот! Спасибо за ответ. Попробую переписать по другому, так как и на выходе тоже не то что должно быть. Вернее не все 
А на счет исполнения по портам я и не спрашивал
Всем спасибо за ответы на мой бред 
А на счет исполнения по портам я и не спрашивал
Как зачем мне голова?! Я ей ем!!!
- Сообщения: 7518
- Зарегистрирован: Вс мар 29, 2009 22:09:05
Товарищи, прошу не сильно кидать в меня подручными предметами, но вопрос такой - как рассчитать время (в тактах), затрачиваемое на выполнение участка кода на С? Есть ли какие-нибудь данные относительно того, за сколько тактов выполняется, скажем, присваивание, вызов подпрограммы, и постоянны ли эти значения вообще? Или просто надо анализировать дизассемблированный листинг, и другого пути нет?
Разница между теорией и практикой на практике гораздо больше, чем в теории.
разумеется, кроме анализа ассемблерного листинга ничего не поможет
кроме протеуса или другого отладчика
только надо быть осторожным, т.к. точки останова не всегда ставятся в начале какого-то оператора 
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
столкнулся я с такой загогулиной, программа измеряет 4 напряжения преобразует и выводит на 7-сегментный индикатор. в дебагере все работает так как надо. в протеусе когда симулируется то в переменной adc[] значения располагаются 3-0-1-2 а должны так 0-1-2-3 (номера-каналы АЦП), соответственно значения преобразуются не правильно и наиндикатор выводится ересь. Итак вопрос: это глюки протеуса и в железе все будет ОК или я налагал в проге. Критика программы очень уместна, так как мне кажется она написана через Ж, так что советы как написать ее компактней, оптимальней и просто красивее очень даже не помешают.
WinAVR-20090313.
WinAVR-20090313.
- Вложения
-
- 8.c
- (2.42 КБ) 394 скачивания
Последний раз редактировалось Callous Пн июл 05, 2010 23:45:23, всего редактировалось 1 раз.
Код - вложением! Правила читаем, нет? 
Оптимизм х (Опыт + Знания) = const


