|
|
  |
Глюк с таймером-1 на AVR AT90USB162 |
|
|
|
May 24 2009, 11:53
|
Местный
  
Группа: Участник
Сообщений: 322
Регистрация: 28-05-05
Пользователь №: 5 512

|
В общем жизнь приказала использовать таймер-1. Инициализировал, написал функции по запуску и останову. Вот: Код void Timers_Init() { // Инициализация Таймеров // Timer/Counter 0 initialization, Clock source: System Clock, Clock value: Timer 0 Stopped, Mode: Normal top=FFh, OC0A output: Disconnected, OC0B output: Disconnected TCCR0A=0x00; TCCR0B=0x00; TCNT0=0x00; OCR0A=0x00; OCR0B=0x00;
// Timer/Counter 1 initialization, Clock source: System Clock, Clock value: Timer 1 Stopped, Mode: Normal top=FFFFh, OC1A output: Discon.,OC1B output: Discon, OC1C output: Discon., Noise Canceler: Off, Input Capture on Falling Edge, Timer 1 Overflow Interrupt: Off, Input Capture Interrupt: Off, Compare A Match Interrupt: Off, Compare B Match Interrupt: Off, Compare C Match Interrupt: Off TCCR1A=0x00; TCCR1B=0x00; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; OCR1CH=0x00; OCR1CL=0x00; TMR1_CURRENT_VALUE_S=0; TMR0_BUSY=0; TMR1_BUSY=0; };
void Timers_Interrupt_Init() { // Инициализация прерываний от таймеров // Timer/Counter 0 Interrupt(s) initialization TIMSK0=0x01; // Timer/Counter 1 Interrupt(s) initialization TIMSK1=0x01; }; // Функции управления таймером-1 void TMR1_START(uint16 value, uint8 clkd) { TCCR1B=clkd; TCNT1H= value>>8; TCNT1L= value & 0x00FF; } // переполнение через каждую 1мс если считать до 125 и clkd=3 // переполнение будет через каждую 1с если считать до 31250 и clkd=4 void TMR1_STOP(void) { TCCR1B = 0; TCNT1H=0; TCNT1L=0; } Смысл в том, если в программе забито TMR1_START(0xFF00,4) то прерывание по переполнению счетчика возникает очень быстро. А должно через T=0xFF00/31250 = 2.08 сек. Дальше - интереснее. Если же в программе забито TMR1_START(0x00FF,4) то прерывание по переполнению счетчика возникает не через Т=0x00FF/31250=0.008 сек а через 2 секунды. Т.е. все происходит с точностью до наоборот. Думал ошибка в файле 90USB162.h - нет, там всё согласно свежей версии даташита на МЦУ. Вот что в файле: Код #define TCNT1L (*(unsigned char *) 0x84) #define TCNT1H (*(unsigned char *) 0x85) В доке смещения для регистров TCNT1L и TCNT1H cоответственно 0x84 и 0x85. Никто не подскажет что за глюк такой? Ах, да, частота кварца 8МГц, фьюз CLKDIV не активирован.
|
|
|
|
|
May 24 2009, 13:57
|
Частый гость
 
Группа: Участник
Сообщений: 149
Регистрация: 2-06-08
Из: Москва
Пользователь №: 38 003

|
Цитата(Halfback @ May 24 2009, 15:53)  В общем жизнь приказала использовать таймер-1. .... Никто не подскажет что за глюк такой? Ах, да, частота кварца 8МГц, фьюз CLKDIV не активирован. Никакого глюка. TMR1_START(0хFF00, 4) запускает таймер с записью в TCNT значения 0хFF00, таймер считает до 0хFFFF, переполняется на след. клоке, следовательно время до переполнения (0x10000-0xFF00)*8/Fclk, где 8 это делитель, который Вы передает функции запуска (приведенный код устанавливает делитель именно в 8, надеюсь Вы не будете спрашивать почему). Если у Вас тактовая 8 МГц, то прерывание будет через 256 мкс. Во втором случае то же самое, только в формулу нужно подставлять 0x00FF и время получится 65281 мкс. Если во втором случае оно у Вас возникает через 2 с, то это что-то странное, по идее даже если CLKDIV запрограммирован то должно приблизительно чере пол-секунды возникать. Вобщем код в студию. Да, еще я бы в функции запуска таймера сначал значения в него записывал, а потом запускал, т. е. так. Код void TMR1_START(uint16 value, uint8 clkd) { TCNT1H= value>>8; TCNT1L= value & 0x00FF; TCCR1B=clkd; }
Сообщение отредактировал smac - May 24 2009, 13:58
|
|
|
|
|
May 24 2009, 14:38
|
Местный
  
Группа: Участник
Сообщений: 322
Регистрация: 28-05-05
Пользователь №: 5 512

|
smacСпасибо что откликнулись. На счет того, почему у меня получается всё с точностью до наоборот вот что: 1. Когда мне надо чтобы таймер считал 2 сек я его стартую с параметрами TMR1_START(0xF424,4). Но реально в железе считает за какие-то миллисекунды. Думается вот почему: счетчик начинает считать не ДО значения 0хF424 а с значения 0xF424 и когда доходит до 0xFFFF возникает прерывание по переполнению. Это время равно T=(0xFFFF-0xF424)/31250=0.09 сек. 2. Когда мне надо чтобы таймер считал до 2мсек то я его стартую с параметрами TMR1_START(0x3E,4). Согласно п.1 получается что счетчик считает до T=(0xFFFF-0x003E)/31250=2.1 сек. И в общем походу дела так оно и происходит т.к. всё сходиться. Цитата Да, еще я бы в функции запуска таймера сначал значения в него записывал, а потом запускал согласен на все 100, мой косяк. Чтобы ничего не переделывать вот вариант исправленой функции где всё работает как надо: Код // Функции управления таймером-1 void TMR1_START(uint16 value,uint8 clkd) { value= (uint16) (0xFFFF-value); TCNT1H= value>>8; TCNT1L= value & 0x00FF; TCCR1B=clkd; } Кстати вопрос: почему если вместо value= (uint16) (0xFFFF-value); написать без приведения к типу value= 0xFFFF-value; то не работает как надо?
Сообщение отредактировал Halfback - May 24 2009, 15:11
|
|
|
|
|
May 24 2009, 17:11
|
Частый гость
 
Группа: Участник
Сообщений: 149
Регистрация: 2-06-08
Из: Москва
Пользователь №: 38 003

|
Цитата(Halfback @ May 24 2009, 18:38)  ... Думается вот почему: счетчик начинает считать не ДО значения 0хF424 а с значения 0xF424 и когда доходит до 0xFFFF возникает прерывание по переполнению. ...
Кстати вопрос: почему если вместо value= (uint16) (0xFFFF-value); написать без приведения к типу value= 0xFFFF-value; то не работает как надо? Ну собственно, что счетчик считае с записанного в него значения это очевидно, по-моему. Прерывание возникает не при значении 0xFFFF, а при следующем , т. е. 0x10000( при этом TCNT, естественно, становится равным 0x0000), поэтому я бы заменил в вашей функции 0xFFFF на 0x10000 для пущей точности. Почему не работает без приведения типа - наверное какое-то расширение типов при вычислении выражений. В-общем, мне легче ответить, если на асм. листинг посмотреть, поэтому если не лень можете выложить, хотя гуру наверное Вам и так ответят.
|
|
|
|
|
May 24 2009, 19:12
|
Местный
  
Группа: Участник
Сообщений: 322
Регистрация: 28-05-05
Пользователь №: 5 512

|
smacВ асме я не силен, но сгенерированный CAVR код в двух случаях (с приведением к типи и без) одинаков. Считал для HEX-файла md5 - одинакова. Наверное по горячке глаз замылися. Код ;// Функции управления таймером-1 ;void TMR1_START(uint16 value,uint8 clkd) { _TMR1_START: ;value= (uint16) (0xFFFF-value); ; value -> Y+1 ; clkd -> Y+0 LDD R26,Y+1 LDD R27,Y+1+1 LDI R30,LOW(65535) LDI R31,HIGH(65535) SUB R30,R26 SBC R31,R27 STD Y+1,R30 STD Y+1+1,R31 ;TCNT1H= value>>8; LDD R30,Y+2 STS 133,R30 ;TCNT1L= value & 0x00FF; LDD R30,Y+1 LDD R31,Y+1+1 STS 132,R30 ;TCCR1B=clkd; LD R30,Y STS 129,R30 ;} JMP _0x2060003
;void TMR1_STOP(void) { ;void TMR1_STOP(void) { _TMR1_STOP: ;TCCR1B = 0; CALL SUBOPT_0x25 ; TCNT1H=0; ;TCNT1L=0; ; } RET
Сообщение отредактировал Halfback - May 24 2009, 19:24
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|