Таймеры-счётчики AVR
Как устроены таймеры-счётчики классических AVR: три таймера ATmega328P, их режимы и таблицы битов WGM, предделители, формулы частоты для CTC и ШИМ, 16-битный Timer1 с регистром ICR1 и захватом, асинхронный Timer2 с часовым кварцем. С примерами на C: прерывание раз в миллисекунду, ШИМ 20 кГц и сигнал для сервопривода.
Обновлено Редакция GAW
Таймер-счётчик — это счётчик, который увеличивается от тактового сигнала через предделитель, сравнивается с регистрами сравнения и по этим событиям вызывает прерывания и формирует сигналы на выводах. У ATmega328P их три: 8-битные Timer0 и Timer2 и 16-битный Timer1. Ниже — по даташиту DS40002061B (главы 15–18): режимы, биты, формулы и примеры. Готовые значения предделителя и регистров для нужной частоты считают калькулятор таймера и калькулятор ШИМ Arduino.
Коротко
- Timer0 — 8 бит, каналы OC0A (PD6) и OC0B (PD5), внешний вход T0 (PD4), предделители 1, 8, 64, 256, 1024.
- Timer1 — 16 бит, каналы OC1A (PB1) и OC1B (PB2), захват ICP1 (PB0), внешний вход T1 (PD5), 15 режимов, TOP из ICR1 или OCR1A.
- Timer2 — 8 бит, каналы OC2A (PB3) и OC2B (PD3), предделители 1, 8, 32, 64, 128, 256, 1024, асинхронный режим от кварца 32,768 кГц на TOSC1/TOSC2.
- Режимы: Normal, CTC, Fast PWM, Phase Correct PWM, у Timer1 ещё Phase and Frequency Correct.
- Формулы: CTC с переключением вывода — f_clk / (2 · N · (1 + OCR)), Fast PWM — f_clk / (N · (1 + TOP)), Phase Correct — f_clk / (2 · N · TOP).
Как устроен таймер
Счётчик TCNTn считает импульсы clk_T — частоту ввода-вывода, поделённую предделителем, или внешние импульсы на входе Tn. Регистры сравнения OCRnA и OCRnB постоянно сравниваются со счётчиком; при совпадении устанавливается флаг OCFnx, может вызываться прерывание и меняться состояние вывода OCnx. Флаг TOVn ставится при переполнении. Максимальное значение счётчика называется MAX (0xFF или 0xFFFF), нижнее — BOTTOM (0), а TOP — значение, на котором счёт поворачивает или сбрасывается: в зависимости от режима это MAX, фиксированное 0x00FF, 0x01FF, 0x03FF или содержимое регистра OCRnA или ICR1.
Режим работы задают биты WGMn — генерации сигнала, а поведение вывода — биты COMnx1:0: в режимах без ШИМ вывод по совпадению устанавливается, сбрасывается или переключается, в режимах ШИМ — неинвертирующий (COMnx = 10) или инвертирующий (11) сигнал. Сигнал попадает на вывод, только если тот настроен на выход в DDRx.
Предделитель
| CSn2:0 | Timer0 и Timer1 | Timer2 |
|---|---|---|
| 000 | таймер остановлен | таймер остановлен |
| 001 | clk / 1 | clk / 1 |
| 010 | clk / 8 | clk / 8 |
| 011 | clk / 64 | clk / 32 |
| 100 | clk / 256 | clk / 64 |
| 101 | clk / 1024 | clk / 128 |
| 110 | внешний вход Tn, спад | clk / 256 |
| 111 | внешний вход Tn, фронт | clk / 1024 |
Timer0 и Timer1 делят один предделитель, а у Timer2 свой, с дополнительными коэффициентами 32 и 128 (таблицы 15-9, 16-5 и 18-9). Таймер запускается записью ненулевого кода в CSn2:0.
Режимы Timer0 и Timer2
| Режим | WGM2:0 | Описание | TOP | Обновление OCR | Флаг TOV |
|---|---|---|---|---|---|
| 0 | 000 | Normal | 0xFF | сразу | MAX |
| 1 | 001 | Phase Correct PWM | 0xFF | TOP | BOTTOM |
| 2 | 010 | CTC | OCRA | сразу | MAX |
| 3 | 011 | Fast PWM | 0xFF | BOTTOM | MAX |
| 5 | 101 | Phase Correct PWM | OCRA | TOP | BOTTOM |
| 7 | 111 | Fast PWM | OCRA | BOTTOM | TOP |
Режимы 4 и 6 зарезервированы (таблица 15-8, у Timer2 — 18-8 с теми же кодами). В режимах 5 и 7 TOP задаёт OCRnA, поэтому частота ШИМ настраивается, но ШИМ с регулируемой скважностью остаётся только у канала B, а вывод OCnA может лишь переключаться по совпадению.
- Normal — счёт от 0 до 0xFF с переполнением; время отмеряют прерыванием по переполнению или по совпадению с OCRnx.
- CTC — счётчик сбрасывается при совпадении с OCRnA, период задаётся точно. Переключение вывода OCnA при каждом совпадении (COMnA = 01) даёт меандр с частотой f_clk / (2 · N · (1 + OCRnA)), до f_clk / 2 при OCRnA = 0. Регистр OCRnA здесь не буферизован: если записать значение меньше текущего TCNTn, совпадение пропустится и счётчик дойдёт до 0xFF.
- Fast PWM — однонаклонный счёт от BOTTOM до TOP. Частота f_clk / (N · 256) при TOP = 0xFF; при 16 МГц и N = 64 это 976,6 Гц — частота ШИМ Arduino на выводах 5 и 6.
- Phase Correct PWM — счёт вверх и вниз, частота вдвое ниже: f_clk / (N · 510) при TOP = 0xFF, но импульс симметричен относительно середины периода, что предпочтительно для управления двигателями.
Timer1: 16 бит и 15 режимов
| Режим | WGM13:0 | Описание | TOP | Обновление OCR1x | Флаг TOV1 |
|---|---|---|---|---|---|
| 0 | 0000 | Normal | 0xFFFF | сразу | MAX |
| 1 | 0001 | Phase Correct PWM, 8 бит | 0x00FF | TOP | BOTTOM |
| 2 | 0010 | Phase Correct PWM, 9 бит | 0x01FF | TOP | BOTTOM |
| 3 | 0011 | Phase Correct PWM, 10 бит | 0x03FF | TOP | BOTTOM |
| 4 | 0100 | CTC | OCR1A | сразу | MAX |
| 5 | 0101 | Fast PWM, 8 бит | 0x00FF | BOTTOM | TOP |
| 6 | 0110 | Fast PWM, 9 бит | 0x01FF | BOTTOM | TOP |
| 7 | 0111 | Fast PWM, 10 бит | 0x03FF | BOTTOM | TOP |
| 8 | 1000 | Phase and Frequency Correct PWM | ICR1 | BOTTOM | BOTTOM |
| 9 | 1001 | Phase and Frequency Correct PWM | OCR1A | BOTTOM | BOTTOM |
| 10 | 1010 | Phase Correct PWM | ICR1 | TOP | BOTTOM |
| 11 | 1011 | Phase Correct PWM | OCR1A | TOP | BOTTOM |
| 12 | 1100 | CTC | ICR1 | сразу | MAX |
| 14 | 1110 | Fast PWM | ICR1 | BOTTOM | TOP |
| 15 | 1111 | Fast PWM | OCR1A | BOTTOM | TOP |
Режим 13 зарезервирован (таблица 16-4). Биты WGM11:10 находятся в TCCR1A, WGM13:12 — в TCCR1B. Для ШИМ с произвольной частотой удобнее всего режим 14: период задаёт ICR1, а оба канала OC1A и OC1B свободны для скважности. Phase and Frequency Correct отличается от Phase Correct тем, что новые OCR1x и TOP применяются в нижней точке счёта — период и импульс остаются симметричными даже при смене частоты на ходу.
Регистры TCNT1, OCR1A/B и ICR1 16-битные, а шина данных 8-битная, поэтому обращение к ним идёт через общий временный регистр: при записи сначала старший байт, затем младший, при чтении — наоборот, сначала младший (раздел 16.3). Компилятор C соблюдает этот порядок сам; если 16-битный регистр трогают и основная программа, и прерывание, доступ в основной программе делают при запрещённых прерываниях.
Захват
Блок захвата копирует TCNT1 в ICR1 по фронту или спаду на выводе ICP1 (выбирает бит ICES1) и ставит флаг ICF1. Так измеряют период и длительность импульсов: разность двух захваченных значений, умноженная на период clk_T, — это время между событиями. Бит ICNC1 включает подавитель шума: событие засчитывается после четырёх одинаковых выборок подряд, ценой задержки на четыре такта. Пока ICR1 используется как TOP (режимы 8, 10, 12, 14), захват недоступен.
Timer2 и часовой кварц
Timer2 устроен как Timer0, но может считать от отдельного генератора на выводах TOSC1 и TOSC2 с кварцем 32,768 кГц — для этого устанавливают бит AS2 в регистре ASSR. Тогда таймер работает и в режиме Power-save, отсчитывая время, пока кристалл спит, — получаются часы реального времени с током около микроампера (подробности — в статье о режимах сна AVR). Частота ядра при этом должна быть больше учетверённой частоты кварца.
В асинхронном режиме запись в TCNT2, OCR2x и TCCR2x попадает сначала во временный регистр и переносится в рабочий через два фронта TOSC1; о завершении переноса говорят биты TCN2UB, OCR2xUB и TCR2xUB в ASSR. Перед засыпанием после такой записи нужно дождаться сброса этих битов, иначе прерывание по совпадению может не прийти и кристалл не проснётся (раздел 18.9). При переключении между синхронным и асинхронным тактированием регистры таймера могут испортиться — их перезаписывают после смены AS2.
Примеры на C
Прерывание раз в 1 мс на Timer1 в режиме CTC при 16 МГц: N = 8, OCR1A = 16 000 000 / (8 · 1000) − 1 = 1999.
#include <avr/interrupt.h>
#include <avr/io.h>
volatile uint32_t ms;
ISR(TIMER1_COMPA_vect)
{
ms++;
}
void timer1_1ms(void)
{
TCCR1A = 0;
TCCR1B = (1 << WGM12) | (1 << CS11); /* CTC (mode 4), clk/8 */
OCR1A = 1999;
TIMSK1 = (1 << OCIE1A);
sei();
}
ШИМ 20 кГц на OC1A (PB1) в режиме 14: TOP = ICR1 = 16 000 000 / (1 · 20 000) − 1 = 799. В неинвертирующем Fast PWM выход находится в единице OCR1A + 1 тактов — недаром при OCR1A = 0 даташит описывает узкий импульс длиной в один такт, — поэтому для скважности 25 % OCR1A = 800 · 0,25 − 1 = 199.
void pwm_20khz(void)
{
DDRB |= (1 << PB1); /* OC1A as output */
ICR1 = 799; /* 20 kHz at 16 MHz */
OCR1A = 199; /* (199 + 1) / 800 = 25 % */
TCCR1A = (1 << COM1A1) | (1 << WGM11); /* non-inverting, mode 14 */
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10); /* clk/1 */
}
Сигнал для сервопривода — 50 Гц, импульс 1–2 мс — в том же режиме 14 с N = 8: такт таймера 0,5 мкс, ICR1 = 16 000 000 / (8 · 50) − 1 = 39 999, а импульс 1,5 мс — это 3000 тактов, то есть OCR1A = 2999.
void servo_50hz(void)
{
DDRB |= (1 << PB1);
ICR1 = 39999; /* 20 ms period */
OCR1A = 2999; /* 1.5 ms pulse, center */
TCCR1A = (1 << COM1A1) | (1 << WGM11);
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); /* clk/8 */
}
Таймеры других AVR устроены так же, но число таймеров, каналов и их выводы различаются — их перечисляют страницы кристаллов в разделе AVR, например ATmega328P. Общие формулы ШИМ без привязки к микроконтроллеру — в калькуляторе ШИМ.
Частые вопросы
Как рассчитать частоту ШИМ AVR?
Для Fast PWM: f = f_clk / (N · (1 + TOP)), для Phase Correct PWM: f = f_clk / (2 · N · TOP), где N — предделитель, TOP — 0xFF у 8-битного режима или значение OCR0A, OCR1A, ICR1. Например, Timer0 в Fast PWM при 16 МГц и N = 64 даёт 16 000 000 / (64 · 256) ≈ 976,6 Гц, а Timer1 в режиме 14 с ICR1 = 799 и N = 1 — ровно 20 кГц.
Какой таймер AVR выбрать для задачи?
Для точных интервалов, длинных периодов и ШИМ с произвольной частотой — 16-битный Timer1: у него TOP можно задать регистром ICR1, оставив оба канала сравнения свободными, и есть захват. Для коротких периодов хватит 8-битных Timer0 и Timer2. Timer2 единственный умеет считать от часового кварца 32,768 кГц и будить кристалл из режима Power-save. В Arduino учтите: Timer0 занят millis() и delay(), Timer1 — библиотекой Servo, Timer2 — функцией tone().
Почему ШИМ AVR не выходит на вывод?
Сигнал сравнения появляется на выводе, только если в COMnx1:0 выбран режим вывода и вывод настроен на выход в регистре DDRx. Кроме того, таймер должен быть запущен — в CSn2:0 выбран предделитель, а не 000. У Timer0 и Timer2 переключение вывода по совпадению (COMnA = 01) в режимах ШИМ работает только для канала A и только при WGMn2 = 1.
Как читать и писать 16-битные регистры Timer1?
Через общий временный регистр: при записи сначала старший байт, затем младший, при чтении — сначала младший, затем старший. Компилятор C делает это сам, когда вы пишете TCNT1 = 0 или читаете ICR1. Если же регистр читается и в основной программе, и в прерывании, доступ в основной программе выполняют при запрещённых прерываниях, иначе обработчик испортит временный регистр.
Источники
- Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet (DS40002061B) — гл. 15 — Timer/Counter0, таблицы 15-8 (WGM) и 15-9 (CS); гл. 16 — Timer/Counter1, доступ к 16-битным регистрам, захват, таблица 16-4; гл. 17 — предделители; гл. 18 — Timer/Counter2, асинхронный режим, таблица 18-9; назначение выводов OC0A–OC2B, ICP1, T0, T1
- Arduino. ArduinoCore-avr, коммит 11b9130, и библиотека Servo (github.com/arduino) — wiring.c — Timer0 в Fast PWM с делителем 64 и счёт millis(); Tone.cpp — tone() на Timer2 у Uno; Servo, src/avr/ServoTimers.h — Timer1 у ATmega328P
Нашли ошибку?
Смотрите также
- AVRATmega, ATtiny, AVR Dx/Ex: семейства, прошивка, инструменты
- Таймер AVR и STM32Предделитель, OCRnA, PSC и ARR под частоту, мёртвое время, энкодер
- Частота ШИМ ArduinoЧастоты analogWrite по таймерам, выводы, смена делителя, millis() и tone()
- ЦАП на ШИМПульсации после RC, установление, разрешение
- ATmega328PРаспиновка, фьюзы, Optiboot, периферия, питание, схема и код на C
- Режимы сна AVRIdle, Power-down, Power-save, Standby, BOD, PRR, ток и пример кода