romez777 0 19 ноября, 2004 Опубликовано 19 ноября, 2004 · Жалоба Приветствую. Продолжаю разборки с atmega162. Вот такой кусок кода, использующий прерывание и таймер (использую WinAVR и AVRstudio для отладки): #include <inttypes.h> #include <interrupt.h> #include <io.h> #include <sig-avr.h> SIGNAL(SIG_OUTPUT_COMPARE1A) { // далее обработка ...... // ......... } void Timer1_Init(void) { SREG = (1 << SREG_I); // enable global interrupt TCCR1A = 0x00; TCCR1B = 0x04; // set prescale TCCR1B = (1 << CS10) | (1 << WGM12); TIMSK = (1 << OCIE1A); // load value TCNT1H = 0xFE; TCNT1L = 0x7A; // set compare register for 50ms OCR1AH = 0x01; OCR1AL = 0x86; } int main(void) { Timer1_Init(); // DDRB = 0xFF; while (1) ; return 1; } На первый взгляд все правильно, но не сдается мне что не получаю я задержки в 50мсек, а проверить в симуляторе, как предложил IgorKossak, не могу (симулятор не позволяет). Вообщем, я окончательно запутался :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Alex2172 0 19 ноября, 2004 Опубликовано 19 ноября, 2004 · Жалоба А осциллографа то нет под рукой? (Ну или хотябы светодиода) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
romez777 0 19 ноября, 2004 Опубликовано 19 ноября, 2004 · Жалоба А осциллографа то нет под рукой? (Ну или хотябы светодиода) осциллографа нет, в на глаз IMHO сложно заметить мерцание светодиода каждые 50мсек :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Styv 0 19 ноября, 2004 Опубликовано 19 ноября, 2004 · Жалоба Попробуй подели генерируемую частоту (~50мс) на 20 и подай этот сигнал на светодиод. Будет мигать с частотой 1 Гц (1с), а это уже можно на глаз определить - сам так делал. А если нодо определить болле точно, то без осцила не обойтись! Или замени осцил например компом: подавай свой сигнал на LPT-порт и смотри с помощью ентой проги твой сигнал dlpt.zip Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 0 19 ноября, 2004 Опубликовано 19 ноября, 2004 · Жалоба А зачем при инициализации таймера в TCNT писать 0xFE7A? Это конечно понятно что это -0x186 но зачем это делать? И еще при инициализации корректнее с начала выставлять OCR и TCNT и самым последним писать TCCR1B иначе можно получить ложное прерываение Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
lamerok 0 19 ноября, 2004 Опубликовано 19 ноября, 2004 · Жалоба void InitTimer (void) { TCCR1A = 0; TCCR1B = ((1<<CS10)|(1<<CS12)); //делим на 1024; TCNT1H = TCNT1L = 0; TIFR |= (1<<OCF1B); Temp.B[0]=TCNT1L; Temp.B[1]=TCNT1H; Temp.I += PERIOD; OCR1BH = TimerOn2Char1.B[1]; OCR1BL = TimerOn2Char1.B[0]; TIMSK |= (1<<OCIE1B); /*разрешаем прерывание по сравнению для таймера на 2 символов*/ } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
lamerok 0 19 ноября, 2004 Опубликовано 19 ноября, 2004 · Жалоба Блин нечаяно нажалось, первое не смотрите.... Вот это код будет все время генерить период в сколько надо, задается PERIODом #define PERIOD 0x186 #pragma vector = TIMER1_COMPB_vect __interrupt void CompareB(void) { union {unsigned char B[2];unsigned int I} Temp; Temp.B[0]=TCNT1L; Temp.B[1]=TCNT1H; Temp.I +=PERIOD; OCR1BH = Temp.B[1]; OCR1BL = Temp.B[0]; TIFR |= (1<<OCF1B); } void InitTimer (void) { union {unsigned char B[2];unsigned int I} Temp; Temp.I = 0; TCCR1A = 0; TCCR1B = ((1<<CS10)|(1<<CS12)); //делим на 1024; TIFR |= (1<<OCF1B); Temp.I = PERIOD; TCNT1H = TCNT1L = 0; OCR1BH = Temp.B[1]; OCR1BL = Temp.B[0]; TIMSK |= (1<<OCIE1B); } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
lamerok 0 19 ноября, 2004 Опубликовано 19 ноября, 2004 · Жалоба Еще поправим маленько. Вечер глучу малость :blink: #pragma vector = TIMER1_COMPB_vect __interrupt void CompareB(void) { union {unsigned char B[2];unsigned int I} Temp; Temp.B[0]=OCR1BL; Temp.B[1]=OCR1BH; Temp.I +=PERIOD; OCR1BH = Temp.B[1]; OCR1BL = Temp.B[0]; TIFR |= (1<<OCF1B); } Вот теперь точно все правильно :) :P Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
romez777 0 22 ноября, 2004 Опубликовано 22 ноября, 2004 · Жалоба А зачем при инициализации таймера в TCNT писать 0xFE7A? Это конечно понятно что это -0x186 но зачем это делать? И еще при инициализации корректнее с начала выставлять OCR и TCNT и самым последним писать TCCR1B иначе можно получить ложное прерываение Приветствую. Так вот с этим пунктом у меня и была изначально непонятность... Я считал, что в TCNT _обязательно_ нужно заносить инициализационное значение для отсчета тиков (c output compare либо без него). А потом - либо по переполнению, либо при match значения в OCR регистре. Так получается, что если работаем в compare режиме, то TCNT уже обнулен и начинает считать сам по себе, без моего вмешательства? И мне достаточно только проинициализировать OCR ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
romez777 0 22 ноября, 2004 Опубликовано 22 ноября, 2004 · Жалоба Блин нечаяно нажалось, первое не смотрите.... Вот это код будет все время генерить период в сколько надо, задается PERIODом Приветствую. Спасибо за пример. Есть вопросы по нему: 1) почему используется union а не structure. Это связано с особенностями генерации кода или только в целях экономии памяти? 2) зачем устанавливать принудительно OCF1B, как я понял этот флаг выставится сам при возникновении события совпадения ? И опять же при отладен в студии, этот флаг не выставляется (баг студии?)... 3) почему используется B-compare канал, а не A ? 4) при прогоне и отладке этого кода в AVR studio я не наблюдаю увеличения счетчика в TCNT... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 0 22 ноября, 2004 Опубликовано 22 ноября, 2004 · Жалоба Так получается, что если работаем в compare режиме, то TCNT уже обнулен и начинает считать сам по себе, без моего вмешательства? И мне достаточно только проинициализировать OCR ? 4) при прогоне и отладке этого кода в AVR studio я не наблюдаю увеличения счетчика в TCNT... Изначально TCNT=0. при работе Clear Timer on Compare or CTC mode таймер считает от 0 до OCR1A потом сбрасывается. Действительно нужно проинициализироать только OCR. И запустить таймер в нужном режиме и прерывание будет выполнятся переодически По поводу величения счетчика в TCNT в AVR studio - это скорее всего из-за прескалера в 1024 надо ждать 1024 такта А вообще на мой взглад у lamerok слишком навороченный пример. Я бы написал так инициализация таймера OCR1A=Fclk / 20; // 20 HZ TCCR1B= (1 << CS10) | (1 << WGM12); TIMSK = (1 << OCIE1A); после этого разрешить прерывания и обработчик будет вызываться каждые 50 мсек (20HZ)! в обработчике регистры таймера трогать не надо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
romez777 0 22 ноября, 2004 Опубликовано 22 ноября, 2004 · Жалоба Изначально TCNT=0. при работе Clear Timer on Compare or CTC mode таймер считает от 0 до OCR1A потом сбрасывается. Действительно нужно проинициализироать только OCR. И запустить таймер в нужном режиме и прерывание будет выполнятся переодически По поводу величения счетчика в TCNT в AVR studio - это скорее всего из-за прескалера в 1024 надо ждать 1024 такта А вообще на мой взглад у lamerok слишком навороченный пример. Я бы написал так инициализация таймера OCR1A=Fclk / 20; // 20 HZ TCCR1B= (1 << CS10) | (1 << WGM12); TIMSK = (1 << OCIE1A); после этого разрешить прерывания и обработчик будет вызываться каждые 50 мсек (20HZ)! в обработчике регистры таймера трогать не надо. Таймер заработал в режиме compare, при достижении значения в OCR, вызывается ISR. Но вот такой момент: в процедуре обработки прерывания таймер продолжает тикать. И если значение в счетчике достигает OCR, то ISR уже не вызывется :) IMHO это неправильно и таймер нужно остановить после вызова ISR? Вот нынешний код: SIGNAL(SIG_OUTPUT_COMPARE1A) { //... } void Timer1_Init(void) { union { unsigned char B[2]; unsigned int I; } Temp; Temp.I = 0; TCCR1A = 0; TCCR1B = (1 << CS11) | (1 << WGM12); Temp.I = PERIOD; TCNT1L = 0; TCNT1H = 0; OCR1AH = Temp.B[1]; OCR1AL = Temp.B[0]; TIMSK |= (1 << OCIE1A); } int main(void) { Timer1_Init(); sei(); while (1) ; return 1; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 0 22 ноября, 2004 Опубликовано 22 ноября, 2004 · Жалоба Но вот такой момент: в процедуре обработки прерывания таймер продолжает тикать. И если значение в счетчике достигает OCR, то ISR уже не вызывется :) Так и должно быть! Таймер должен тикать иначе прерывание будет вызваться реже чем 50 мс! А вот если значение в счетчике достигнет OCR то после выхода из прерывания (разрешения прерываний) прерывание вызовется сново, т.к флаг очищается при входе в обработчик. Но в любом случае обработчик прерывания который работает больше 50 мс это не правильно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
romez777 0 22 ноября, 2004 Опубликовано 22 ноября, 2004 · Жалоба Так и должно быть! Таймер должен тикать иначе прерывание будет вызваться реже чем 50 мс! А вот если значение в счетчике достигнет OCR то после выхода из прерывания (разрешения прерываний) прерывание вызовется сново, т.к флаг очищается при входе в обработчик. Но в любом случае обработчик прерывания который работает больше 50 мс это не правильно. Приветствую. А если в обработчике стоит цикл while (...) {...} и нет гарантии что он будет работать меньше 50 мс, как быть? Отказываться от while и искать другую концепцию? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 0 22 ноября, 2004 Опубликовано 22 ноября, 2004 · Жалоба Так и должно быть! Таймер должен тикать иначе прерывание будет вызваться реже чем 50 мс! А вот если значение в счетчике достигнет OCR то после выхода из прерывания (разрешения прерываний) прерывание вызовется сново, т.к флаг очищается при входе в обработчик. Но в любом случае обработчик прерывания который работает больше 50 мс это не правильно. Приветствую. А если в обработчике стоит цикл while (...) {...} и нет гарантии что он будет работать меньше 50 мс, как быть? Отказываться от while и искать другую концепцию? А как можно делать действие каждые 50 мс если длительность самого дейстивя больше 50 мс? они же будут перекрываться. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться