Перейти к содержанию

Калькулятор таймера AVR и STM32

Задайте тактовую частоту и нужную частоту прерываний или ШИМ — калькулятор подберёт предделитель и значение регистра периода для таймеров ATmega328P и STM32, покажет фактическую частоту, ошибку и код настройки. Для STM32 он также считает поле DTG мёртвого времени комплементарных выходов TIM1 и TIM8 и отсчёты инкрементального энкодера, а частоты таймеров STM32F103 и STM32F407 подставляет из атласа.

Исходные данные

Микроконтроллер

16 МГц, 8 МГц, 1 МГц

Что задано

1 кГц, 38 кГц, 50 Гц

Результат

Предделитель и OCRnA
1 и 15999
CS = 001, режим CTC
Фактическая частота
1 кГцпериод 1 мс
Ошибка
0 %
Разрешение ШИМ
14 бит16000 шагов
Меандр на выводе OCnA
500 Гцпри переключении вывода в режиме CTC

Другие варианты:

  • N = 8, OCRnA = 1999 → 1 кГц (0 %)
  • N = 64, OCRnA = 249 → 1 кГц (0 %)
  • N = 256, OCRnA = 62 → 992,063 Гц (−0,794 %)
TCCR1A = 0;
TCCR1B = (1 << WGM12) | (1 << CS10);  // CTC, clk/1
OCR1A = 15999;
TIMSK1 = (1 << OCIE1A);         // ISR(TIMER1_COMPA_vect)

Расчёт выполнен по формулам и данным из источников, приведённых на этой странице, и не заменяет проверку: параметры компонентов у разных производителей и даже партий различаются. Перед применением сверяйте результат с документацией на конкретные детали.

Аппаратный таймер отсчитывает такты, поделённые предделителем, и формирует событие — прерывание или период ШИМ — каждые TOP + 1 отсчётов. Задача сводится к тому, чтобы подобрать предделитель и значение регистра периода так, чтобы частота событий была как можно ближе к нужной.

Формулы

Для ATmega328P в режиме CTC (сброс по совпадению) и в Fast PWM с регистром периода:

f=fclkN⋅(1+TOP),fOCnA=fclk2 N (1+OCRnA),f = \frac{f_{clk}}{N \cdot (1 + TOP)}, \qquad f_{OCnA} = \frac{f_{clk}}{2 \, N \, (1 + OCRnA)},

где N — предделитель, TOP — значение OCRnA (или ICR1 у Timer1), fOCnA — частота меандра на выводе OCnA, когда вывод переключается при каждом совпадении. У Timer0 и Timer1 предделители 1, 8, 64, 256 и 1024, у Timer2 добавлены 32 и 128.

Для таймера STM32 событие обновления происходит каждые (PSC + 1) · (ARR + 1) тактов:

f=fTIM(PSC+1)⋅(ARR+1).f = \frac{f_{TIM}}{(PSC + 1) \cdot (ARR + 1)} .

PSC и ARR 16-битные; у TIM2 и TIM5 во многих семействах ARR 32-битный.

Как выбирается предделитель

Калькулятор перебирает предделители и для каждого находит ближайшее значение регистра периода. Из вариантов с наименьшей ошибкой выбирается тот, где предделитель меньше: регистр периода тогда больше, а значит, у ШИМ больше шагов скважности. Остальные варианты показаны списком — иногда удобнее «круглый» отсчёт, например 1 МГц.

Пример: несущая 38 кГц для ИК-передатчика на выводе OC2A ATmega328P при 16 МГц. Меандр на выводе вдвое медленнее событий, поэтому нужна частота событий 76 кГц: предделитель 1, OCR2A = 210, на выводе получится 37 915 Гц — на 0,22 % ниже 38 кГц, что приёмники ИК-сигналов допускают.

Тактирование таймеров STM32

Частоту fTIM берите из настройки тактирования, а не из частоты ядра. Если делитель шины APB, к которой подключён таймер, больше 1, таймеры этой шины тактируются удвоенной частотой шины. У STM32F103 на 72 МГц шина APB1 работает на 36 МГц, а TIM2–TIM4 — на 72 МГц.

Селектор «Таймер из атласа» подставляет частоты таймеров STM32F103 и STM32F407 при обычной максимальной настройке тактирования: у F103 все таймеры получают 72 МГц, у F407 таймеры на шине APB2 (TIM1, TIM8–TIM11) — 168 МГц, на APB1 — 84 МГц, причём у TIM2 и TIM5 регистр ARR 32-битный (таблица 4 даташитов DS5319 и DS8626).

Все поля регистров таймера — PSC, ARR, режимы каналов в CCMR, ШИМ, захват, энкодер — разобраны на страницах регистров таймеров STM32F1 и STM32F4.

Мёртвое время TIM1 и TIM8

У расширенных таймеров TIM1 и TIM8 каналы 1–3 имеют комплементарные выходы CHxN для полумоста. Между выключением одного ключа и включением другого таймер выдерживает мёртвое время, которое задаёт поле DTG[7:0] регистра BDTR в периодах t_DTS (RM0008, 14.4.18):

DTG[7:5]Мёртвое времяШаг
0xxDTG[7:0] · t_DTSt_DTS
10x(64 + DTG[5:0]) · 2 · t_DTS2 · t_DTS
110(32 + DTG[4:0]) · 8 · t_DTS8 · t_DTS
111(32 + DTG[4:0]) · 16 · t_DTS16 · t_DTS

Период t_DTS — такт таймера, умноженный на 1, 2 или 4 по полю CKD регистра CR1, наибольшее мёртвое время — 1008 · t_DTS. Пример RM0008 для t_DTS = 125 нс: 0–15 875 нс с шагом 125 нс, 16–31,75 мкс с шагом 250 нс, 32–63 мкс с шагом 1 мкс и 64–126 мкс с шагом 2 мкс — он служит эталоном тестов калькулятора.

Калькулятор выбирает наименьшее DTG, при котором мёртвое время не короче заданного: для силовых ключей короткая пауза опаснее длинной. Макрос __LL_TIM_CALC_DEADTIME из драйвера LL STM32Cube отбрасывает дробную часть и может дать значение на шаг меньше — если результаты расходятся, калькулятор это показывает. Подробнее о комплементарных выходах, BRK и MOE — в статье о таймерах STM32.

Энкодер

В режиме энкодера таймер считает фронты двух сигналов A и B, подключённых к входам TI1 и TI2, а направление определяет по их порядку (RM0008, раздел 14.3.16 и таблица 81). В режимах 1 и 2 считаются фронты одного входа — 2 отсчёта на период сигнала, в режиме 3 (SMS = 011) — фронты обоих, 4 отсчёта. Энкодер с N периодами на оборот даёт 2N или 4N отсчётов; если записать в ARR число отсчётов на оборот минус 1, счётчик будет проходить ровно круг за оборот.

Калькулятор показывает частоту сигналов на входах при наибольшей скорости и время, за которое счётчик проходит круг 0…ARR. Если читать CNT реже, чем за половину этого круга, по разности двух отсчётов уже нельзя однозначно понять, в какую сторону и на сколько повернулся вал.

Пример для ATmega328P

#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint32_t ms_ticks;

ISR(TIMER1_COMPA_vect)
{
    ms_ticks++;                        /* called every 1 ms */
}

int main(void)
{
    TCCR1A = 0;
    TCCR1B = (1 << WGM12) | (1 << CS11);   /* CTC, clk/8 */
    OCR1A = 1999;                          /* 16 MHz / 8 / 2000 = 1 kHz */
    TIMSK1 = (1 << OCIE1A);
    sei();
    for (;;) {
    }
}

Типичные ошибки

  • Забыли глобально разрешить прерывания (sei()): таймер считает, флаг совпадения ставится, но обработчик не вызывается.
  • Заняли таймер Arduino. Timer0 используют millis() и delay(), Timer1 — библиотека Servo, Timer2 — tone(). Перенастройка ломает эти функции.
  • Не тот режим. В обычном режиме (Normal) счётчик досчитывает до максимума, и OCRnA задаёт только момент совпадения, а не период.
  • Неверная частота таймера STM32 из-за удвоения на шине APB — частота получается вдвое выше или ниже ожидаемой.
  • Ошибка частоты из-за кварца. Расчёт точен настолько, насколько точна тактовая частота; на внутреннем RC-генераторе ошибка доходит до процентов. Подбор конденсаторов для кварца — в калькуляторе конденсаторов для кварца, скорость UART — в калькуляторе скорости UART.

Частые вопросы

Как настроить прерывание таймера раз в 1 мс на ATmega328P при 16 МГц?

Timer1 в режиме CTC: предделитель 1 и OCR1A = 15999 или предделитель 8 и OCR1A = 1999 — оба варианта дают ровно 1 кГц. Для 8-битного Timer0 подходит предделитель 64 и OCR0A = 249. Учтите, что в Arduino Timer0 занят функциями millis() и delay().

Как рассчитать PSC и ARR для STM32?

Частота события f = fTIM / ((PSC + 1) · (ARR + 1)), где fTIM — частота тактирования таймера. Для 1 кГц при 72 МГц произведение (PSC + 1) · (ARR + 1) должно быть 72 000: например, PSC = 71 и ARR = 999 (счёт идёт с частотой 1 МГц) или PSC = 1 и ARR = 35 999 — так у ШИМ больше шагов.

Почему частота таймера STM32 вдвое больше частоты шины APB?

Так устроено тактирование: если делитель шины APB больше 1, таймеры на этой шине получают удвоенную частоту. Например, у STM32F103 на 72 МГц шина APB1 работает на 36 МГц, а таймеры TIM2–TIM4 тактируются от 72 МГц.

Как рассчитать мёртвое время STM32 (поле DTG)?

Мёртвое время задаётся в периодах t_DTS: такт таймера, умноженный на 1, 2 или 4 по полю CKD. Значения DTG до 0x7F дают DTG · t_DTS, от 0x80 — (64 + DTG[5:0]) · 2 · t_DTS, от 0xC0 — (32 + DTG[4:0]) · 8 · t_DTS, от 0xE0 — (32 + DTG[4:0]) · 16 · t_DTS (RM0008, 14.4.18). Для 1 мкс на STM32F103 с таймером 72 МГц это DTG = 72 (0x48), на TIM1 STM32F407 при 168 МГц — 0x94.

Чем режим CTC отличается от переполнения таймера?

При переполнении счётчик всегда досчитывает до максимума — 255 или 65 535, — и частота выбирается только предделителем. В CTC счётчик сбрасывается при совпадении с OCRnA, и период задаётся точно, с шагом в один такт после предделителя.

Источники

  1. Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet (DS40002061B) — Timer/Counter0, 1 и 2: режим CTC, частота на выводе OCnA, Fast PWM, коды предделителя CSn2:0
  2. STMicroelectronics. RM0008 Reference manual STM32F101xx–STM32F107xx — предделитель PSC и регистр ARR таймеров, частота тактирования таймеров от шины APB; 14.4.18 — кодирование DTG[7:0] и пример диапазонов при t_DTS = 125 нс (эталон тестов); 14.3.16 и таблица 81 — режимы энкодера
  3. STMicroelectronics. STM32CubeF1: драйвер LL (stm32f1xx_ll_tim.h) — макрос __LL_TIM_CALC_DEADTIME и TIM_CALC_DTS — второй источник тестов мёртвого времени; LL_TIM_ENCODERMODE_X2_TI1, X2_TI2, X4_TI12 — 2 и 4 отсчёта на период
  4. STMicroelectronics. DS5319 Rev 20 (STM32F103x8/B) и DS8626 Rev 12 (STM32F405/407) — таблица 4 обоих даташитов — таймеры, их разрядность и шины; пресеты частот таймеров

Где пригодится

Встроить калькулятор на свой сайт

Скопируйте код и вставьте его в HTML страницы, статьи или вики. Виджет бесплатный, без рекламы, счётчиков и cookie. Условие одно — ссылка на GAW под рамкой остаётся на месте. Подробнее о виджетах

<iframe src="https://gaw.ru/embed/mcu-timer/" title="Калькулятор таймера AVR и STM32" width="100%" height="640" style="border:1px solid #e3e5e9;border-radius:8px" loading="lazy" allow="clipboard-write"></iframe>
<p style="margin:6px 0 0;font-size:14px">Калькулятор: <a href="https://gaw.ru/tools/mcu-timer/">Калькулятор таймера AVR и STM32</a> — GAW.ru</p>
Автоподстройка высоты рамки

Если сайт разрешает скрипты, добавьте этот код один раз в любом месте страницы: рамка будет менять высоту вместе с результатом расчёта.

<script>window.addEventListener("message",function(e){if(e.origin!=="https://gaw.ru"||!e.data||e.data.type!=="gaw:embed-height")return;var f=document.querySelectorAll('iframe[src^="https://gaw.ru/embed/"]');for(var i=0;i<f.length;i++)if(f[i].contentWindow===e.source)f[i].style.height=e.data.height+"px"})</script>

Обновлено .

Нашли ошибку в расчёте?