Таймеры/счётчики в AVR

Обсуждаем контроллеры компании Atmel.
dgrett
Вымогатель припоя
Сообщения: 615
Зарегистрирован: Вс дек 28, 2014 21:54:05

Re: Таймеры/счётчики в AVR

Сообщение dgrett »

Привет всем, у меня вопрос такой: можно ли "склеить" 2 таймера на Меге8 - таймер1 и таймер2 с расчётом получить 24 битный таймер? Необязательно напрямую, можно через прерывания, например, таймер2 по переполнению а таймер1 работал бы в режиме СТС?. Просто нехватает точности 16-разрядного. Мне нужен 1-секундный интервал. Сейчас имею: частота ядра 16Мгц от внешнего генератора SG51P, предделитель 1/256, считаем до 62500. Получаю слишком длинную секунду. При 62499 - слишком короткую. Вот и думаю, если выключить прескалер и склеить таймеры, можно было бы иметь секунду с точностью 0,0625 мкс. Или есть способ попроще? Типа сделать секунду короче и выключить на некоторое время таймер1? Но нехочется делать тупых задержек. Подскажите, пожалуйста.

ПС. Питание стабильное, температура-тоже. Пишу в Студии на асме
Я всё-всё узнAю и стану профессором.
akl
Друг Кота
Сообщения: 4444
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: Таймеры/счётчики в AVR

Сообщение akl »

Расширить Т1 дополнительной регистровой парой, в которой считать число переполнений. Т1 без предделителя, после 244 переполнений досчитать ещё 9'216 тактов.
Последний раз редактировалось akl Пн июл 18, 2016 10:12:54, всего редактировалось 1 раз.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Таймеры/счётчики в AVR

Сообщение ARV »

что мешает использовать предделитель 1024 и CTC на значение 15625?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
dgrett
Вымогатель припоя
Сообщения: 615
Зарегистрирован: Вс дек 28, 2014 21:54:05

Re: Таймеры/счётчики в AVR

Сообщение dgrett »

akl писал(а):Расширить Т1 дополнительной регистровой парой, в которой считать число переполнений. Т1 без предделителя.
Ну блин!!, А что сам-то не додумался? Этож надо- на ровном месте! Спасибо, akl! :)))
ARV, и Вам спасибо, только с 16-разрядным счётчиком как ни крути, а точность интервала зависит только от точности генератора и его частоты., Я уже пробовал всякие варианты. Вывод - надо увеличить разрядность счётчика
Я всё-всё узнAю и стану профессором.
dgrett
Вымогатель припоя
Сообщения: 615
Зарегистрирован: Вс дек 28, 2014 21:54:05

Re: Таймеры/счётчики в AVR

Сообщение dgrett »

Ну вот и программка, ещё не симулял. Это если я правильно понял. Зае заразмножался с подсчётом что надо (в идеале) подсунуть в регистр Sekunda. И я не уверен, что подсчитал правильно, наверно, в железе надо будет тестить.
Спойлер

Код: Выделить всё

.cseg
.org   0
   rjmp   reset
.org   OC1Aaddr
   rjmp   MatchT1
.org   OVF1addr
   rjmp   OvfT1

.equ   Sekunda   =   9216   ;4321 counted manually
   
.def   temp   r16
.def   cnt1   r17
.def   cnt2   r18
.def   ;...............
reset:
   ldi      temp,Low(RAMEND)
   out      SPL,temp
   ldi      temp,High(RAMEND)
   out      SPH,temp
   ;PORT ini....
   ;other settings
   clr      temp
   out      TCCR1A,temp
   ldi      temp,1<<CS10
   out      TCCR1B,temp
   
   ldi      temp,1<<TOIE1
   out      TIMSK,temp
   ldi      cnt1,244
   sei
main:
   rjmp   main
   
OvfT1:
   in      r1,sreg                           ;1
   dec      cnt1                                   ;1
   brne           exit1                                  ;2/1
   ldi      temp,high(Sekunda)   ;prepare timer1    ;1
   out      OCR1AH,temp         ;to count in CTC mode           ;1
   ldi      temp,low(Sekunda)                          ;1
   out      OCR1AL,temp                        ;1
   ldi      temp,(1<<WGM12)|(1<<CS10)                    ;1
   out      TCCR1B,temp                        ;1
   clr      temp         ;do I need this "clr"?                           ;1
   ldi      temp,1<<OCIE1A                     ;1
   out      TIMSK,temp                        ;1
exit1:
   out      sreg,r1                           ;1   
   reti                                 ;4
   ;total OvfT1:   8/17 cycles or 0,5/1,0625 uS @16MHz approx.+rjmp=2*244+reti=4*244
   ;14/23, with rjmp/reti, timer1=65536+2+4=65542
   ;243*(65542+14)+65542+23+6=15995679 uS
   ;Sekunda=4321
MatchT1:
   in      r1,sreg         ;1
   ldi      cnt1,244              ;1
   clr      temp                 ;1
   out      TCCR1A,temp      ;1
   ldi      temp,1<<CS10           ;1
   out      TCCR1B,temp      ;1   =6 ticks=0,375 uS, timer starts here
   ldi      temp,1<<TOIE1     ;1
   out      TIMSK,temp      ;1
   
;   Have 1 Second here...

   out      sreg,r1
   reti
Я всё-всё узнAю и стану профессором.
akl
Друг Кота
Сообщения: 4444
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: Таймеры/счётчики в AVR

Сообщение akl »

Вы правильно поняли. Правда, код с недостатками.
Спойлер

Код: Выделить всё

.INCLUDE "m8DEF.INC"

.cseg
.org   0
   rjmp   reset
.org   OC1Aaddr
   SET
   RET
;   rjmp   MatchT1
.org   OVF1addr
OvfT1:
   in      r1,sreg                           ;1
   dec      cnt1                                   ;1
   brne           exit1                                  ;2/1

   ldi      temp,(1<<WGM12)|(1<<CS10)                    ;1
   out      TCCR1B,temp                        ;1
   ldi      temp,1<<OCIE1A                     ;1
   out      TIMSK,temp                        ;1
;*************
   OUT   TIFR,TEMP
;*************
exit1:
   out      sreg,r1                           ;1   
   reti                                 ;4
;   rjmp   OvfT1
;*************************************************
.equ   Sekunda   =   9216   ;4321 counted manually
   
.def   temp =  r16
.def   cnt1 = r17
.def   cnt2 = r18
;.def   ;...............
reset:
   ldi      temp,Low(RAMEND)
   out      SPL,temp
   ldi      temp,High(RAMEND)
   out      SPH,temp
   ;PORT ini....
   ;other settings
GO:
   CLI
   ldi      temp,high(Sekunda-1)   ;prepare timer1    ;1
   out      OCR1AH,temp         ;to count in CTC mode           ;1
   ldi      temp,low(Sekunda-1)                          ;1
   out      OCR1AL,temp                        ;1

   ldi      temp,1<<CS10
   out      TCCR1B,temp
   
   ldi      temp,1<<TOIE1
   out      TIMSK,temp
   OUT   TIFR,temp
   ldi      cnt1,244
   CLT
   sei
main:
   BRTC   main
   RJMP   GO
;   rjmp   main
   
   ;total OvfT1:   8/17 cycles or 0,5/1,0625 uS @16MHz approx.+rjmp=2*244+reti=4*244
   ;14/23, with rjmp/reti, timer1=65536+2+4=65542
   ;243*(65542+14)+65542+23+6=15995679 uS
   ;Sekunda=4321
;MatchT1:
;   in      r1,sreg         ;1
;   ldi      cnt1,244              ;1
;   clr      temp                 ;1
;   out      TCCR1A,temp      ;1
;   ldi      temp,1<<CS10           ;1
;   out      TCCR1B,temp      ;1   =6 ticks=0,375 uS, timer starts here
;   ldi      temp,1<<TOIE1     ;1
;   out      TIMSK,temp      ;1
   
;   Have 1 Second here...

;   out      sreg,r1
;   reti
.EXIT
Так можно формировать секунду для любого кварца.
Спойлер

Код: Выделить всё

.INCLUDE "m8DEF.INC"

.equ    Fo=16012344

.equ    OVER=Fo/65536

.equ   Sekunda=Fo-OVER*65536
   
.def   temp =  r16
.def   cnt1 = r17
.def   cnt2 = r18

.cseg
.org   0
   rjmp   reset
.org   OC1Aaddr
   SET
   RET
.org   OVF1addr
OvfT1:
 ;  in      r1,sreg                           ;1
   dec      cnt1                                   ;1
   brne           exit1                                  ;2/1

   ldi      temp,(1<<WGM12)|(1<<CS10)                    ;1
   out      TCCR1B,temp                        ;1
   ldi      temp,1<<OCIE1A                     ;1
   out      TIMSK,temp                        ;1
;*************
   OUT   TIFR,TEMP
;*************
exit1:
  ; out      sreg,r1                           ;1   
   reti                                 ;4
;*************************************************
reset:
   ldi      temp,Low(RAMEND)
   out      SPL,temp
   ldi      temp,High(RAMEND)
   out      SPH,temp
   ;PORT ini....
   ;other settings
GO:
   CLI

   LDI   R22,(1<<SE)
   OUT   MCUCR,R22      ; режим SLEEP IDLE

   ldi      temp,high(Sekunda-1)   ;prepare timer1    ;1
   out      OCR1AH,temp         ;to count in CTC mode           ;1
   ldi      temp,low(Sekunda-1)                          ;1
   out      OCR1AL,temp                        ;1

   ldi      temp,1<<CS10
   out      TCCR1B,temp
   
   ldi      temp,1<<TOIE1
   out      TIMSK,temp
   OUT   TIFR,temp
   LDI      cnt1,OVER
;   ldi      cnt1,244
   CLT
   sei
main:
   SLEEP
   BRTC   main
   RJMP   GO
.EXIT
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Таймеры/счётчики в AVR

Сообщение ARV »

akl писал(а):Так можно формировать секунду для любого кварца.
наверное, можно, не вникал. но принципиально - зачем это может быть необходимо? все-таки достаточно "частые" прерывания по считающему на 16МГц таймеру - это весьма приличная нагрузка на ядро - оно действительно необходимо?

например, человечество не заморачивается с тем, что Земля облетает Солнце не ровно за 365 дней... а просто раз в 4 года добавляют сутки, и все. если у вас кварц не точный, то, например, для часов было бы достаточно каждую, допустим, 12845-ю секунду увеличивать счетчик секунд не на 1, а на 2, или наоборот, пропускать инкремент счетчика - и точность хода часов была бы 1 секунда в год.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
dgrett
Вымогатель припоя
Сообщения: 615
Зарегистрирован: Вс дек 28, 2014 21:54:05

Re: Таймеры/счётчики в AVR

Сообщение dgrett »

Ув. ARV, в системах охраны так и сделано (DSC). Есть ячейка, в которой записано количество секунд последней в сутках минуты. По дефолту там 60. Но.. надо так..
akl, спасибо Вам, сейчас разбираюсь как и что в Вашем коде (в перерывах между основной работой :) ).
Ещё не понял, почему Sekunda-1 и зачем писать в TIFR?. По даташиту :

• Bit 4 – OCIE1A: Timer/Counter1, Output Compare A Match Interrupt Enable
When this bit is written to one, and the I-flag in the Status Register is set (interrupts globally
enabled), the Timer/Counter1 Output Compare A match interrupt is enabled. The corresponding
Interrupt Vector (see “Interrupts” on page 46) is executed when the OCF1A Flag, located in
TIFR, is set.


Вот я почему-то и подумал, что флаг устанавливается аппаратно.

Где я сморозил?
Я всё-всё узнAю и стану профессором.
akl
Друг Кота
Сообщения: 4444
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: Таймеры/счётчики в AVR

Сообщение akl »

If TCNT equals OCR1x the comparator signals a match. A match will set the Output Compare Flag (OCF1x) at the next timer clock cycle. If enabled (OCIE1x = 1), the Output Compare Flag generates an Output Compare interrupt.
Следовательно, для точного сравнения нужно заносить значение на 1 меньшее требуемого.
dgrett писал(а):Вот я почему-то и подумал, что флаг устанавливается аппаратно.
Да, а вот сбрасываются они аппаратно при обработке прерывания или программной записью лог. 1. Флаги в AVR всегда расположены на той же позиции в регистре локально разрешающем оные.
Запись типа

Код: Выделить всё

   ldi      temp,1<<TOIE1
   out      TIMSK,temp
   OUT   TIFR,temp
означает разрешение прерывания переполнения и сброс флага.
Последний раз редактировалось akl Вт июл 19, 2016 08:28:04, всего редактировалось 1 раз.
dgrett
Вымогатель припоя
Сообщения: 615
Зарегистрирован: Вс дек 28, 2014 21:54:05

Re: Таймеры/счётчики в AVR

Сообщение dgrett »

Вот, теперь проясняется :) Читать и читать даташит. И чтоб не отвлекал никто :lol:
Я всё-всё узнAю и стану профессором.
dgrett
Вымогатель припоя
Сообщения: 615
Зарегистрирован: Вс дек 28, 2014 21:54:05

Re: Таймеры/счётчики в AVR

Сообщение dgrett »

Опять вопрос, хотя работает и так. Но может необязательно каждую секунду загружать OCR1A ? Можно его грузить единожды в общих настройках. Ведь менять я его не собираюсь в ходе программы? Или тут ещё какие камни под водой с острыми краями?
Я всё-всё узнAю и стану профессором.
akl
Друг Кота
Сообщения: 4444
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: Таймеры/счётчики в AVR

Сообщение akl »

В такой программе можно и единожды загружать OCR1A. Но, По возможности, подтверждать режим работы считаю более надежным решением. Или, например, программу можно переписать, используя только прерывание OC1A.
dgrett
Вымогатель припоя
Сообщения: 615
Зарегистрирован: Вс дек 28, 2014 21:54:05

Re: Таймеры/счётчики в AVR

Сообщение dgrett »

Спасибо, я тоже так подумал, для надёжности, ведь несколько доп. тактов (их количество не меняется в ходе программы) не "спасёт отца русской демократии".
Я всё-всё узнAю и стану профессором.
Аватара пользователя
hosturik
Потрогал лапой паяльник
Сообщения: 354
Зарегистрирован: Чт июл 24, 2014 23:09:23
Откуда: Киев

Re: Таймеры/счётчики в AVR

Сообщение hosturik »

Подскажите что может быть. Есть atmega 168, работает на
8 МГц, в Makefile тоже указано 8000000. Таймер с максимальным предделителем на 1024 срабатывает по переполнению, срабатывает в четыре раза медленнее чем нужно. Считал так.
1/(8 000 000/1 024/1 024)*1 000 = 131 мс
В реальности получается 32 миллисекунды
Что это за глюк и как с ним боротся?

Компилятор - Winavr 2010
akl
Друг Кота
Сообщения: 4444
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: Таймеры/счётчики в AVR

Сообщение akl »

1000000/8000000=0.125мкс. 0,125*1024*256=32768мкс или 32,768мс
Аватара пользователя
baron_P
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Вт сен 14, 2010 23:07:10
Откуда: Ростов

Re: Таймеры/счётчики в AVR

Сообщение baron_P »

baron_P писал(а):Доброго времени суток.
Есть странный затуп с МК ATMega8. Хочу использовать для генерации ШИМ-сигнала Т/С1 в режиме FastPWM со счетом до ICR1.
...
Вся эта штука работает правильно, если выбран обычный FastPWM или, например, PhaseCorrectPWM c отсчетом до ICR1. А если выбрать нужный мне FastPWM с отсчетом до ICR1, то не работает функция считывания нажатия кнопок. Если режим переключить переменной, то все ок (запускается ШИМ и тд.), а включить вручную никак: состояние PINC (на котором висят кнопки и входные сигналы) ни в какую не хочет считываться.
Подскажите, пожалуйста, куда примерно думать. Что-то совсем не могу понять, как это может быть связано между собой.


Нашел проблему. При такой

Код: Выделить всё

TCCR1A |= (1 << COM1A1)
инициализации Т/С1, на соответствующем выводе при включении МК висит единица. А у меня дальше идет цикл ожидания нуля на этом выводе, который становится бесконечным из-за этого. Лечится инверсией состояния вывода

Код: Выделить всё

TCCR1A |= (1 << COM1A1) | (1 << COM1A1)
А скважность теперь можно задавать как разность максимума счета и требуемого задания скважности

Код: Выделить всё

OCR1A = ICR1 - PWM_ref
We do what we must because we can (c) GLaDOS
Аватара пользователя
hosturik
Потрогал лапой паяльник
Сообщения: 354
Зарегистрирован: Чт июл 24, 2014 23:09:23
Откуда: Киев

Re: Таймеры/счётчики в AVR

Сообщение hosturik »

Подскажите, можно ли так делить частоту прерываний, все работает, но правильно ли так делать?

ISR (TIMER2_OVF_vect) //32 миллисекунды
{
static char delenie_in_seven = 0;
if(++delenie_in_seven == 7) //Получаем нужную длительность такта 229 миллисекунд
{
delenie_in_seven = 0;
//Код
}
}
a5021
Друг Кота
Сообщения: 6452
Зарегистрирован: Пт сен 13, 2013 13:11:31

Re: Таймеры/счётчики в AVR

Сообщение a5021 »

Теоретически, никто не запрещает использовать статические переменные в обработчике прерывания. Единственное, я бы убрал начальную инициализацию, т.к. static по требованию стандарта зануляется перед первым употреблением. Оно, конечно, и в таком виде абсолютно законно, но несколько двусмысленно. По аналогии с обычными переменными возникает ассоциация, что переменная обнуляется при каждом входе в обработчик, что на самом деле не так.
kotriks
Грызет канифоль
Сообщения: 274
Зарегистрирован: Чт апр 28, 2011 15:08:58

Re: Таймеры/счётчики в AVR

Сообщение kotriks »

Помогите с таймером в меге168 1MHZ не срабатывает каждые 5 секунд.

Код: Выделить всё

    OCR2A = 0x1E85;

    TCCR2A |= (1 << WGM21);
    // Set to CTC Mode

    TIMSK2 |= (1 << OCIE2A);
    //Set interrupt on compare match

    TCCR2B |= (1 << CS21);

interrupt [TIM2_COMPA] void timer2_compa_isr(void)
{
unsigned char i;
  LED_ON;
  delay_us(400);
  LED_OFF;
 
}
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Re: Таймеры/счётчики в AVR

Сообщение COKPOWEHEU »

OCR2A = 0x1E85;
А ничего что у m168 таймер T2 восьмибитный?
Да и остальная логика на первый взгляд странная.
TCCR2A |= (1 << WGM21);
Чему равны остальные биты этого регистра? Лучше при настройке делать прямое присваивание.
TCCR2B |= (1 << CS21); делитель F_CPU/8 = 125 кГц
OCR2A = 0x1E85; если предположить, что этот регистр 16-битный, делитель равен 7814
Тогда прерывание возникает с частотой F_CPU/8/7814 = 16 Гц, то есть с интервалом 62,5 мс.
Ответить

Вернуться в «AVR»