|
вызвать прерывание каждые 50мсек |
|
|
|
Nov 19 2004, 07:54
|
Местный
  
Группа: Свой
Сообщений: 292
Регистрация: 9-11-04
Пользователь №: 1 077

|
Приветствую. Продолжаю разборки с 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, не могу (симулятор не позволяет). Вообщем, я окончательно запутался
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 14)
|
Nov 19 2004, 08:25
|
Местный
  
Группа: Свой
Сообщений: 292
Регистрация: 9-11-04
Пользователь №: 1 077

|
Цитата(Alex2172 @ Nov 19 2004, 11:13 AM) А осциллографа то нет под рукой? (Ну или хотябы светодиода) осциллографа нет, в на глаз IMHO сложно заметить мерцание светодиода каждые 50мсек
|
|
|
|
|
Nov 19 2004, 08:59
|
Частый гость
 
Группа: Свой
Сообщений: 133
Регистрация: 16-08-04
Пользователь №: 504

|
Попробуй подели генерируемую частоту (~50мс) на 20 и подай этот сигнал на светодиод. Будет мигать с частотой 1 Гц (1с), а это уже можно на глаз определить - сам так делал. А если нодо определить болле точно, то без осцила не обойтись! Или замени осцил например компом: подавай свой сигнал на LPT-порт и смотри с помощью ентой проги твой сигнал
Прикрепленные файлы
dlpt.zip ( 431.38 килобайт )
Кол-во скачиваний: 92
|
|
|
|
|
Nov 19 2004, 12:07
|

Частый гость
 
Группа: Свой
Сообщений: 135
Регистрация: 22-06-04
Из: Челябинск
Пользователь №: 88

|
Блин нечаяно нажалось, первое не смотрите.... Вот это код будет все время генерить период в сколько надо, задается 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); }
|
|
|
|
|
Nov 19 2004, 12:10
|

Частый гость
 
Группа: Свой
Сообщений: 135
Регистрация: 22-06-04
Из: Челябинск
Пользователь №: 88

|
Еще поправим маленько. Вечер глучу малость Код #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
|
|
|
|
|
Nov 22 2004, 00:08
|
Местный
  
Группа: Свой
Сообщений: 292
Регистрация: 9-11-04
Пользователь №: 1 077

|
Цитата(KRS @ Nov 19 2004, 02:15 PM) А зачем при инициализации таймера в TCNT писать 0xFE7A? Это конечно понятно что это -0x186 но зачем это делать?
И еще при инициализации корректнее с начала выставлять OCR и TCNT и самым последним писать TCCR1B иначе можно получить ложное прерываение Приветствую. Так вот с этим пунктом у меня и была изначально непонятность... Я считал, что в TCNT _обязательно_ нужно заносить инициализационное значение для отсчета тиков (c output compare либо без него). А потом - либо по переполнению, либо при match значения в OCR регистре. Так получается, что если работаем в compare режиме, то TCNT уже обнулен и начинает считать сам по себе, без моего вмешательства? И мне достаточно только проинициализировать OCR ?
|
|
|
|
|
Nov 22 2004, 02:14
|
Местный
  
Группа: Свой
Сообщений: 292
Регистрация: 9-11-04
Пользователь №: 1 077

|
Цитата(lamerok @ Nov 19 2004, 03:07 PM) Блин нечаяно нажалось, первое не смотрите.... Вот это код будет все время генерить период в сколько надо, задается PERIODом Приветствую. Спасибо за пример. Есть вопросы по нему: 1) почему используется union а не structure. Это связано с особенностями генерации кода или только в целях экономии памяти? 2) зачем устанавливать принудительно OCF1B, как я понял этот флаг выставится сам при возникновении события совпадения ? И опять же при отладен в студии, этот флаг не выставляется (баг студии?)... 3) почему используется B-compare канал, а не A ? 4) при прогоне и отладке этого кода в AVR studio я не наблюдаю увеличения счетчика в TCNT...
|
|
|
|
|
Nov 22 2004, 10:27
|

Профессионал
    
Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555

|
Цитата(romez777 @ Nov 22 2004, 03:08 AM) Так получается, что если работаем в 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)! в обработчике регистры таймера трогать не надо.
|
|
|
|
|
Nov 22 2004, 10:48
|
Местный
  
Группа: Свой
Сообщений: 292
Регистрация: 9-11-04
Пользователь №: 1 077

|
Цитата(KRS @ Nov 22 2004, 01:27 PM) Изначально 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; }
|
|
|
|
|
Nov 22 2004, 11:52
|
Местный
  
Группа: Свой
Сообщений: 292
Регистрация: 9-11-04
Пользователь №: 1 077

|
Цитата(KRS @ Nov 22 2004, 02:19 PM) Так и должно быть! Таймер должен тикать иначе прерывание будет вызваться реже чем 50 мс! А вот если значение в счетчике достигнет OCR то после выхода из прерывания (разрешения прерываний) прерывание вызовется сново, т.к флаг очищается при входе в обработчик. Но в любом случае обработчик прерывания который работает больше 50 мс это не правильно. Приветствую. А если в обработчике стоит цикл while (...) {...} и нет гарантии что он будет работать меньше 50 мс, как быть? Отказываться от while и искать другую концепцию?
|
|
|
|
|
Nov 22 2004, 12:04
|

Профессионал
    
Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555

|
Цитата(romez777 @ Nov 22 2004, 02:52 PM) Цитата(KRS @ Nov 22 2004, 02:19 PM) Так и должно быть! Таймер должен тикать иначе прерывание будет вызваться реже чем 50 мс! А вот если значение в счетчике достигнет OCR то после выхода из прерывания (разрешения прерываний) прерывание вызовется сново, т.к флаг очищается при входе в обработчик. Но в любом случае обработчик прерывания который работает больше 50 мс это не правильно. Приветствую. А если в обработчике стоит цикл while (...) {...} и нет гарантии что он будет работать меньше 50 мс, как быть? Отказываться от while и искать другую концепцию? А как можно делать действие каждые 50 мс если длительность самого дейстивя больше 50 мс? они же будут перекрываться.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|