13. Таймеры (TIM)
Самый универсальный блок микроконтроллера. Одним и тем же счётчиком делают периодические прерывания, широтно‑импульсную модуляцию, измерение длительности импульсов, подсчёт оборотов энкодера и запуск АЦП по расписанию. Освоив таймер, вы закрываете половину типовых задач.
Как это называется в документации
Оригинал Перевод prescaler ( PSC)предделитель auto-reload register ( ARR)регистр автоперезагрузки capture/compare register ( CCR)регистр захвата и сравнения update event событие обновления preload / shadow register предзагрузка, теневой регистр counting mode: up / down / center-aligned счёт вверх / вниз / по центру output compare сравнение выхода input capture захват входа duty cycle коэффициент заполнения dead time защитный интервал one-pulse mode одноимпульсный режим master / slave mode ведущий / ведомый режим encoder interface mode режим энкодера input filter ( ICxF)цифровой фильтр входа detent щелчок — фиксированное положение ручки
13.1 Какие бывают таймеры
| Тип | У F1 | У F4 | Что умеет |
|---|---|---|---|
| базовые | TIM6, TIM7 | TIM6, TIM7 | только счёт: запуск АЦП/ЦАП, ритм для DMA |
| общего назначения | TIM2…TIM5 | TIM2…TIM5, TIM9…TIM14 | ШИМ, захват, энкодер |
| продвинутые | TIM1, TIM8 | TIM1, TIM8 | то же + комплементарные выходы, защитный интервал, аварийный вход |
Продвинутые нужны для управления двигателями и мостовыми схемами: они выдают пару противофазных сигналов с гарантированной паузой между ними, чтобы транзисторы моста не открылись одновременно.
Таблица — для старших камней серий. У F103C8 и F103CB (BluePill) таймеров четыре: TIM1…TIM4; TIM5…TIM8 есть только у F103 от 256 КБ Flash. У F401 и F411 нет TIM6, TIM7, TIM8 и TIM12…TIM14. Точный набор — в таблице возможностей в паспорте своего камня.
Важное отличие F4: таймеры TIM2 и TIM5 у него 32‑битные. У F1 все счётчики 16‑битные. Это снимает главное ограничение — на F1 диапазон «частота × длительность» иногда приходится набирать каскадом из двух таймеров, на F4 хватает одного.
13.2 Базовый счёт
Три регистра определяют всё:
| Регистр | Смысл |
|---|---|
PSC |
предделитель: во сколько раз замедлить входную частоту |
ARR |
до скольки считать перед сбросом |
CNT |
текущее значение счётчика |
частота событий = f_таймера / ((PSC + 1) × (ARR + 1))
Единицы прибавляются потому, что счёт идёт от нуля: ARR = 999 означает
тысячу тактов.
Прерывание раз в миллисекунду при 72 МГц:
void tim2_init_1khz(void)
{
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
TIM2->PSC = 72u - 1u; /* тик 1 мкс */
TIM2->ARR = 1000u - 1u; /* 1000 тиков = 1 мс */
TIM2->EGR = TIM_EGR_UG; /* PSC — сразу; без UG первый период 14 мкс (13.4) */
TIM2->SR = ~TIM_SR_UIF; /* флаг от UG — не прерывание */
TIM2->DIER |= TIM_DIER_UIE; /* прерывание по переполнению */
TIM2->CR1 |= TIM_CR1_CEN; /* пуск */
NVIC_SetPriority(TIM2_IRQn, 6);
NVIC_EnableIRQ(TIM2_IRQn);
}
void TIM2_IRQHandler(void)
{
if (TIM2->SR & TIM_SR_UIF) {
TIM2->SR = ~TIM_SR_UIF; /* сброс флага — записью НУЛЯ */
/* полезная работа */
}
}
⚠️ Флаги таймера сбрасываются записью нуля, в отличие от
EXTI->PR, где нужна единица. Это не произвол: в описании регистра они помеченыrc_w0противrc_w1у EXTI (обозначения разбирались в разделе 39). Перепутать легко, а результат — либо флаг не сбрасывается и обработчик зацикливается, либо стираются флаги соседних каналов.
Как подбирать PSC и ARR. Одну и ту же частоту можно получить разными
парами, но не любая одинаково хороша: чем больше ARR, тем тоньше шаг
регулировки в режиме ШИМ. Правило простое — предделитель берут минимально
необходимым, чтобы ARR вышел побольше.
13.3 Откуда таймер берёт частоту
Здесь та самая особенность, о которой предупреждал раздел 6:
⚠️ Таймеры получают удвоенную частоту своей шины APB, если её делитель больше единицы. При
HCLK= 72 МГц и APB1 = 36 МГц таймеры считают от 72 МГц, а не от 36 (это TIM2…TIM4 на APB1); APB2 у F103 обычно без делителя, и TIM1 считает от тех же 72 МГц. У F407 при 168 МГц делитель есть у обеих шин: APB1 = 42 МГц — таймеры на ней считают от 84 МГц, APB2 = 84 МГц — TIM1, TIM8, TIM9…TIM11 считают от 168 МГц. Расчёт по частоте шины даёт вдвое неверный результат — и это, пожалуй, самая частая ошибка при работе с таймерами.
Проверять всегда стоит по факту: настроить период в секунду и посмотреть на светодиод. Мигает вдвое быстрее — вы попались.
13.4 Теневые регистры
Механизм, который путает больше всего.
PSC имеет два экземпляра: тот, куда вы пишете, и тот, которым таймер
пользуется на самом деле. Перенос из первого во второй происходит по
событию обновления — то есть в момент переполнения счётчика. ARR и CCR
устроены так же, но буфер у них включается отдельно — предзагрузкой: ARPE
для ARR, OCxPE для канала. После сброса предзагрузка выключена, и запись
в ARR и CCR действует сразу.
Зачем: если менять период прямо посреди периода, форма сигнала исказится. Теневые регистры гарантируют, что новое значение вступит в силу целиком и на границе цикла.
Отсюда два следствия:
Настройки не применяются сразу. Записали PSC или, при включённой
предзагрузке, ARR, а таймер продолжает
работать по‑старому до ближайшего переполнения. Если период был длинный,
выглядит как «настройка не сработала». Принудительно применить —
событием обновления:
TIM3->EGR = TIM_EGR_UG; /* немедленно перенести значения в теневые регистры */
UG — настоящее событие обновления: кроме переноса оно обнуляет счётчик и
предделитель и ставит флаг UIF. Если прерывание по обновлению уже
разрешено (UIE), обработчик вызовется сразу — отсюда загадочное «лишнее»
прерывание при запуске; флаг, оставленный UG, вызовет его и позже, в
момент разрешения UIE. Поэтому UG делают до разрешения прерывания и
сразу сбрасывают флаг: TIMx->SR = ~TIM_SR_UIF. Другой путь — заранее
поставить бит URS в CR1: тогда UG переносит значения, но флага не
ставит, и прерывание дают только переполнения.
Предзагрузку надо включать явно. Для ARR это бит ARPE, для каждого
канала — OCxPE. Без них запись идёт напрямую, и смена скважности посреди
импульса даст выброс. А уменьшать ARR на ходу без предзагрузки опасно:
если CNT уже больше нового ARR, счётчик досчитает до 65 535, перевалит
через ноль, и один период выйдет длиной до 65 536 тиков.
13.5 🔧 ШИМ
Самое частое применение. Счётчик считает от нуля до ARR, а компаратор
сравнивает его с CCR: пока CNT < CCR — на выходе один уровень, дальше
другой.
частота ШИМ = f_таймера / ((PSC + 1) × (ARR + 1))
заполнение = CCR / (ARR + 1)
разрешение = ARR + 1 градаций
Долю периода, занятую импульсом, строго называют коэффициентом заполнения. В обиходе — и дальше в справочнике — её зовут скважностью, хотя строго скважность — это отношение периода к длительности импульса, T/τ: при заполнении 25 % она равна 4.
void tim3_pwm_init(uint16_t period, uint16_t duty)
{
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
/* PA6 — выход альтернативной функции, push-pull. */
GPIOA->CRL &= ~(GPIO_CRL_MODE6 | GPIO_CRL_CNF6);
GPIOA->CRL |= GPIO_CRL_MODE6; /* 11 -> выход 50 МГц */
GPIOA->CRL |= GPIO_CRL_CNF6_1; /* 10 -> альтернативная функция */
TIM3->PSC = 72u - 1u; /* тик 1 мкс */
TIM3->ARR = period - 1u;
TIM3->CCR1 = duty;
/* Режим ШИМ 1: пока CNT < CCR — активный уровень. */
TIM3->CCMR1 &= ~TIM_CCMR1_OC1M;
TIM3->CCMR1 |= TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1; /* 110 */
TIM3->CCMR1 |= TIM_CCMR1_OC1PE; /* предзагрузка CCR1 */
TIM3->CCER |= TIM_CCER_CC1E; /* выход канала разрешён */
TIM3->CR1 |= TIM_CR1_ARPE;
TIM3->EGR = TIM_EGR_UG; /* применить настройки немедленно */
TIM3->CR1 |= TIM_CR1_CEN;
}
Дальше скважность меняется одной строкой: TIM3->CCR1 = новое_значение;
Например, tim3_pwm_init(1000, 250) даёт 1 кГц и скважность 25 %. Так это выглядит на осциллографе;
пилу счётчика таймер наружу не выводит — она нарисована над выходом для наглядности:
Компромисс частоты и разрешения. Произведение частоты на число градаций ограничено тактовой:
| Частота ШИМ | ARR при 72 МГц без деления |
Градаций |
|---|---|---|
| 1 кГц | 71 999 (не влезает в 16 бит) | нужен предделитель |
| 20 кГц | 3599 | 3600 — с запасом |
| 100 кГц | 719 | 720 |
| 1 МГц | 71 | 72 — грубовато |
Для управления двигателем берут 20 кГц (выше слышимого диапазона) и получают отличное разрешение. Для светодиодной подсветки хватает и 500 Гц — глаз не заметит.
Вкладка «ШИМ» в калькуляторах приложения считает частоту, скважность и число градаций из PSC, ARR и CCR, а под нужную частоту — ARR без предделителя и CCR под нужную скважность.
⚠️ У TIM1 и TIM8 есть главный выключатель выходов. Всё настроено верно, счётчик идёт,
CCRменяется — а на выводе тишина. Причина в битеMOEрегистраBDTR, который по умолчанию сброшен:
c TIM1->BDTR |= TIM_BDTR_MOE;У TIM2…TIM5 и TIM9…TIM14 такого регистра нет вовсе, поэтому код, отлаженный на TIM3, при переносе на TIM1 молча перестаёт работать. Бит
MOEесть и у TIM15, TIM16 и TIM17 (F0, G0, F3, L4 и другие серии): их ШИМ тоже включают черезBDTR.
13.6 Захват входного сигнала
Обратная задача: не формировать сигнал, а измерить. По фронту на входе таймер
копирует текущее значение счётчика в CCR — вы получаете точную временную
метку без участия процессора.
void tim4_capture_init(void)
{
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
TIM4->PSC = 72u - 1u; /* тик 1 мкс */
TIM4->ARR = 0xFFFFu; /* считаем до предела */
TIM4->EGR = TIM_EGR_UG; /* PSC вступает в силу сразу (13.4) */
/* Канал 1 переключается на ВХОД. */
TIM4->CCMR1 &= ~TIM_CCMR1_CC1S;
TIM4->CCMR1 |= TIM_CCMR1_CC1S_0; /* 01 -> вход TI1 */
TIM4->CCER &= ~TIM_CCER_CC1P; /* нарастающий фронт */
TIM4->CCER |= TIM_CCER_CC1E;
TIM4->DIER |= TIM_DIER_CC1IE;
TIM4->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(TIM4_IRQn);
}
Разность двух последовательных меток даёт период сигнала, а значит и частоту.
Измерение скважности делается двумя каналами сразу: один ловит нарастающий фронт, другой спадающий, оба привязаны к одному входу. Это отдельный режим — ШИМ‑вход, и таймер настраивает его почти автоматически.
Типичные применения: измерение частоты, декодирование сигналов датчиков расстояния, приём сигналов пультов и радиоприёмников.
13.7 Энкодер
Таймер умеет сам считать импульсы поворотного энкодера, разбираясь
в направлении по двум сигналам со сдвигом фаз. Процессор не участвует вовсе —
просто читает CNT, когда нужно.
Настраивается ведомым режимом в SMCR: счёт по одному каналу, по другому
или по обоим сразу. Последний вариант даёт четырёхкратное разрешение.
Энкодер вместе с ШИМ на практике — в 13.10.
Практическая деталь: счётчик 16‑битный и переполняется. Для энкодера, крутящегося в одну сторону долго, нужно ловить переполнение прерыванием и вести старшую часть счёта программно — либо взять 32‑битный TIM2/TIM5 на F4.
13.8 Одноимпульсный режим
Таймер выдаёт ровно один импульс заданной длительности и останавливается. Удобно для формирования строба, импульса запуска ультразвукового датчика, задержанного сигнала.
Включается битом OPM в CR1: после первого события обновления счётчик
сам себя выключает.
13.9 Синхронизация нескольких таймеров
Таймеры умеют управлять друг другом: один становится ведущим и по своему
событию запускает, останавливает или тактирует ведомый. Настраивается парой
регистров — CR2 у ведущего (что именно выдавать наружу) и SMCR
у ведомого (как реагировать).
Зачем это нужно:
- каскад счётчиков — обойти 16‑битное ограничение на F1, получив 32‑битный счёт из двух таймеров;
- синхронный старт нескольких каналов ШИМ, чтобы фазы не разъезжались;
- точная задержка между двумя событиями;
- запуск АЦП по таймеру — самый частый случай, разбирается в разделе 14.
13.10 🔧 Яркость от энкодера
Крутишь ручку — светодиод плавно становится ярче или тусклее. Здесь сходятся энкодер (13.7), ШИМ (13.5) и то, как глаз видит яркость (57.3). Оба таймера работают сами, процессору остаётся одна строка в цикле.
| F103 (BluePill) | F407 (Discovery) | |
|---|---|---|
| энкодер | TIM2: PA0, PA1 | TIM3: PB4, PB5 (AF2) |
| ШИМ | TIM3, канал 1: PA6 | TIM4, канал 1: PD12 (AF2) — зелёный светодиод платы |
| тик ШИМ 1 мкс | PSC = 71 при 72 МГц |
PSC = 83 при 84 МГц |
Светодиод BluePill на PC13 к таймеру не подключён, и ШИМ на нём возможен только программный — нужен внешний светодиод с резистором на PA6. Контакты энкодера замыкают выводы на землю, поэтому на входах подтяжка вверх.
void enc_pwm_init(void)
{
pins();
/* энкодер: оба канала — входы с самым длинным фильтром, счёт по обоим фронтам */
ENC->CCMR1 = TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0 | TIM_CCMR1_IC1F | TIM_CCMR1_IC2F;
ENC->SMCR = TIM_SMCR_SMS_1 | TIM_SMCR_SMS_0; /* 011: энкодер, ×4 */
ENC->ARR = 0xFFFFu;
ENC->CR1 = TIM_CR1_CKD_1 | TIM_CR1_CEN; /* f_DTS = f / 4 — для фильтра */
/* ШИМ: 1 кГц, 1000 градаций */
PWM->PSC = PWM_PSC;
PWM->ARR = 999u;
PWM->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1PE; /* ШИМ 1, предзагрузка */
PWM->CCER = TIM_CCER_CC1E;
PWM->CR1 = TIM_CR1_ARPE;
PWM->EGR = TIM_EGR_UG;
PWM->CR1 |= TIM_CR1_CEN;
brightness_reset((uint16_t)ENC->CNT);
}
int main(void)
{
enc_pwm_init();
for (;;)
PWM->CCR1 = brightness_step((uint16_t)ENC->CNT);
}
Счёт. В режиме энкодера по обоим каналам таймер ловит оба фронта обоих
сигналов — четыре отсчёта на полный цикл. У распространённых механических
энкодеров полный цикл — это один щелчок, поэтому на щелчок приходится четыре
отсчёта; у части моделей щелчок — полцикла, тогда два. Направление таймер
определяет сам: CNT растёт при повороте в одну сторону и убывает в другую.
Дребезг. Самый длинный фильтр входа — 8 отсчётов на частоте f_DTS / 32;
при 72 МГц и CKD = ÷4 это 8 / (18 МГц / 32) ≈ 14 мкс. Дребезг контактов длится
миллисекунды, и фильтр его не уберёт, но квадратурному счёту он не страшен:
пока дребезжит один контакт, второй стоит, и счёт ходит +1 −1 на месте.
Уровень яркости меняется посередине между щелчками — (отсчёты + 2) / 4.
Ручка, отпущенная на щелчке, стоит в двух отсчётах от границы уровня, и контакт,
дребезжащий на краю, яркость не дёргает.
Переход через ноль. Повернули ручку влево от старта — CNT становится
65535, 65534… Если брать CNT как положение, яркость прыгает на максимум.
Правильно считать разность показаний со знаком: (int16_t)(uint16_t)(cnt - s_last)
верна и через переход, пока между чтениями меньше 32 768 отсчётов. Накопленное
значение ограничивают с обеих сторон: ручка, упёршаяся в край, откликается
на обратный поворот сразу, без довода лишних оборотов.
#define STEPS 32 /* уровней яркости */
#define PER 4 /* отсчётов на щелчок: оба фронта обоих каналов */
/* round(1000 · (i / 31)^2,2); при ARR = 999 значение 1000 — горит постоянно */
static const uint16_t gamma22[STEPS] = {
0, 1, 2, 6, 11, 18, 27, 38, 51, 66, 83,
102, 124, 148, 174, 202, 233, 267, 302, 341, 381, 425,
470, 519, 569, 623, 679, 738, 799, 864, 930, 1000,
};
static uint16_t s_last; /* прошлое показание CNT */
static int32_t s_acc; /* отсчёты от нижнего края: 0 … PER·(STEPS−1) */
uint16_t brightness_step(uint16_t cnt)
{
int32_t acc = s_acc + (int16_t)(uint16_t)(cnt - s_last); /* верно и через 0 ↔ 65535 */
s_last = cnt;
if (acc < 0)
acc = 0; /* упёрлись — обратный поворот */
if (acc > PER * (STEPS - 1)) /* откликается сразу */
acc = PER * (STEPS - 1);
s_acc = acc;
return gamma22[(acc + PER / 2) / PER]; /* граница уровня — между щелчками */
}
Шкала. 32 уровня по гамме 2,2 (почему не линейно — в 57.3). Верхнее
значение 1000 = ARR + 1: светодиод горит постоянно (13.12). Первые шаги —
1, 2 и 6 из 1000, глаз видит их как 4,3 %, 5,9 % и 9,8 % яркости. От нуля
до полной яркости — 31 щелчок: при 20 щелчках на оборот это полтора оборота.
Что показала модель. Энкодер промоделирован на компьютере: 16-битный счёт по обоим фронтам, по три отскока на каждом переходе контактов, яркость пересчитывается после каждого фронта.
| Что сделали | CNT |
Уровень |
|---|---|---|
| 40 щелчков вправо | 160 = 40 × 4 | 31 — упёрлись |
| 5 щелчков назад | 140 | 26 — отклик сразу |
| 2 вправо, контакт у щелчка дребезжит 10 раз | 148 | 28, ни одной смены |
| с нуля 3 щелчка влево | 65 524 | 0, а не максимум |
| и 1 вправо | 65 528 | 1 |
Если бы уровень считали отбрасыванием остатка (отсчёты / 4), тот же дребезг
у щелчка дал бы 20 смен яркости.
Мигание вообще без программы. Тот же ШИМ с периодом в секунду мигает сам:
тик 0,1 мс (PSC = 7199 на F103, 8399 на F407), ARR = 9999 — период 1 с,
CCR1 = 2500 — горит 250 мс. Для сравнения: переключение вывода в прерывании
раз в 0,5 с даёт мигание с частотой 1 Гц, а не 2 — полный период состоит из двух
переключений.
13.11 F0 и G0: те же таймеры, другие имена такта
Таймеры — та часть STM32, которая от серии к серии почти не меняется:
CR1, PSC, ARR на 0x2C, CCR1 на 0x34, режимы захвата и сравнения,
теневые регистры — всё как у F1. Рецепт ШИМ из 13.5 переносится на F0
и G0 с двумя правками: имя регистра тактирования и предделитель под
свою частоту.
| F1 | F0 | G0 | |
|---|---|---|---|
| такт TIM3 | APB1ENR |
APB1ENR |
APBENR1 |
| такт TIM1 | APB2ENR |
APB2ENR |
APBENR2 |
TIM3_CH1 на PA6 |
режим AF в CRL |
AF1 | AF1 |
| такт таймера при максимуме | 72 МГц | 48 МГц | 64 МГц |
PSC для счёта 1 МГц |
71 | 47 | 63 |
Код F1/F0 с RCC->APB1ENR на G0 не собирается: no member named 'APB1ENR'
in 'RCC_TypeDef'. ШИМ 1 кГц у G0:
RCC->APBENR1 |= RCC_APBENR1_TIM3EN; /* у G0 — APBENR1 */
GPIOA->AFR[0] = (GPIOA->AFR[0] & ~(0xFu << 24)) | (1u << 24); /* PA6 -> AF1 = TIM3_CH1 */
GPIOA->MODER = (GPIOA->MODER & ~(3u << 12)) | (2u << 12);
TIM3->PSC = PSC_VAL;
TIM3->ARR = ARR_VAL;
TIM3->CCR1 = 250u;
TIM3->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1PE;
TIM3->CCER = TIM_CCER_CC1E;
TIM3->CR1 = TIM_CR1_ARPE | TIM_CR1_CEN;
Набор таймеров зависит от камня. У F072 и G071, на которых проверены
листинги, это продвинутый TIM1 (с BDTR и битом MOE, без которого
выходы молчат — 13.5), TIM2, TIM3, базовые TIM6 и TIM7 и малые
TIM14–TIM17; у TIM15–TIM17 тоже есть BDTR с MOE, и без этого
бита их выходы молчат так же. TIM2 у обеих серий 32-битный: счётчик
и ARR в описании камня — два поля по 16 бит.
У F1 для 1 кГц при полном такте ARR «не влезал в 16 бит» (13.5), а
здесь помещается в любой таймер без предделителя: ARR = 47 999 у F0 и
63 999 у G0 — меньше 65 535. 32 бита TIM2 нужны для периодов длиннее:
16-битному счётчику без предделителя хватает лишь на 1,37 мс при 48 МГц и
1,02 мс при 64 МГц, а TIM2 без него отсчитает и секунду. Но у F030,
F070, G030 и G070 TIM2 нет вовсе, а у F030x6, F070x6 и G030 нет и
TIM6 с TIM15: там длинный период получают только предделителем.
Точный набор — в таблице возможностей паспорта камня.
13.12 Грабли
Частота вдвое больше ожидаемой. Не учтено удвоение частоты таймеров на шине APB с делителем больше 1.
Настройки не вступают в силу. Не сделано событие обновления (UG):
PSC, а при включённой предзагрузке и ARR с CCR, ждут его.
Прерывание пришло сразу после запуска. Его вызвал флаг UIF,
поставленный записью UG: сбросить флаг после UG или заранее
поставить URS в CR1 (13.4).
Один период вдруг длиннее в десятки раз. ARR уменьшили на ходу без
предзагрузки, и CNT оказался выше нового значения: счётчик дошёл до 65 535
и перевалил через ноль. Включить ARPE.
TIM1 молчит. Не выставлен MOE в BDTR. Так же молчат TIM8
и TIM15…TIM17.
Флаг сброшен неправильно. У таймера пишется ноль, а не единица.
Причём TIM->SR = 0 сотрёт заодно флаги всех каналов — правильно
TIM->SR = ~TIM_SR_UIF.
Вывод не настроен на альтернативную функцию. Таймер работает, CCR
меняется, но вывод остаётся обычным GPIO и ничего не выдаёт.
Переполнение при захвате. Если период сигнала длиннее полного цикла счётчика, разность меток получится бессмысленной. Считайте переполнения или увеличивайте предделитель.
Нулевое заполнение. CCR = 0 даёт постоянный неактивный уровень,
CCR > ARR — постоянный активный. Это не ошибка, а нормальное поведение,
но при расчёте процентов легко получить CCR, равный ARR + 1,
и удивиться пропавшему ШИМ.
Прерывание таймера не приходит. HAL_TIM_Base_Start только запускает
счёт; прерывание по обновлению включает HAL_TIM_Base_Start_IT — он ставит
бит UIE в DIER.
Мигает вдвое медленнее расчёта. Переключение раз в 0,5 с — это период 1 с, то есть 1 Гц (13.10).
Яркость прыгает на максимум при повороте влево. CNT взят как положение
и перешёл через ноль. Нужна разность показаний со знаком (13.10).
Светодиод BluePill не откликается на ШИМ. Вывод PC13 к таймеру не подключён.
HAL_GetTick для коротких отрезков. Он считает миллисекунды — отрезок
короче не измерить. Для микросекунд берут свободный таймер с тиком 1 мкс или
DWT->CYCCNT (раздел 73).
13.13 Итоги
- Частота событий =
f / ((PSC + 1) × (ARR + 1)); предделитель берут минимальным, чтобыARRбыл больше — это разрешение ШИМ. - Таймеры на шине APB с делителем больше 1 получают её удвоенную частоту; у F4 это касается и APB2: TIM1 и TIM8 при 168 МГц считают от 168 МГц.
PSCбуферизован всегда,ARRиCCR— только с предзагрузкой (ARPE,OCxPE; после сброса она выключена): тогда новые значения вступают в силу по событию обновления, принудительно — записьюUGвEGR.- Флаги таймера сбрасываются записью нуля, и лучше маской, а не нулём во весь регистр.
- У TIM1 и TIM8 (и у TIM15…TIM17 там, где они есть) выходы включаются
битом
MOE; без него всё настроено, но вывод молчит. - Захват даёт временные метки фронтов без участия процессора — отсюда измерение частоты и скважности.
- Энкодер таймер считает сам, включая направление: по обоим каналам — четыре
отсчёта на полный цикл, и дребезг счёту не страшен. Положение — разность
показаний со знаком, а не сам
CNT; шкала яркости — по гамме (13.10). - Мигать можно вообще без программы: ШИМ с периодом в секунду.
- У F4 таймеры TIM2 и TIM5 32‑битные, что снимает необходимость каскадов.
Полные исходники
tim_f0.c — ШИМ 1 кГц на TIM3 у STM32F072.
/* Раздел 13.11: ШИМ 1 кГц на TIM3 канал 1 (PA6, AF1) у STM32F072 — таймер как у F1. */
#include <stddef.h>
#include "stm32f0xx.h"
_Static_assert(offsetof(TIM_TypeDef, ARR) == 0x2Cu && offsetof(TIM_TypeDef, CCR1) == 0x34u, "регистры как у F1");
#define TIM_HZ 48000000u /* такт таймера = PCLK 48 МГц (делитель APB 1) */
#define PSC_VAL 47u
#define ARR_VAL 999u
_Static_assert(TIM_HZ / (PSC_VAL + 1u) == 1000000u && TIM_HZ / (PSC_VAL + 1u) / (ARR_VAL + 1u) == 1000u, "1 МГц счёт, 1 кГц ШИМ");
void pwm_init_f0(void)
{
RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
GPIOA->AFR[0] = (GPIOA->AFR[0] & ~(0xFu << 24)) | (1u << 24); /* PA6 -> AF1 = TIM3_CH1 */
GPIOA->MODER = (GPIOA->MODER & ~(3u << 12)) | (2u << 12);
TIM3->PSC = PSC_VAL;
TIM3->ARR = ARR_VAL;
TIM3->CCR1 = 250u; /* 25 % */
TIM3->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1PE; /* PWM1, с буфером */
TIM3->CCER = TIM_CCER_CC1E;
TIM3->CR1 = TIM_CR1_ARPE | TIM_CR1_CEN;
}
tim_g0.c — тот же ШИМ на STM32G071.
/* Раздел 13.11: тот же ШИМ на STM32G071 — TIM3 канал 1 (PA6, AF1), такт с APBENR1, 64 МГц. */
#include <stddef.h>
#include "stm32g0xx.h"
_Static_assert(offsetof(TIM_TypeDef, ARR) == 0x2Cu && offsetof(TIM_TypeDef, CCR1) == 0x34u, "регистры как у F0 и F1");
#define TIM_HZ 64000000u
#define PSC_VAL 63u
#define ARR_VAL 999u
_Static_assert(TIM_HZ / (PSC_VAL + 1u) == 1000000u && TIM_HZ / (PSC_VAL + 1u) / (ARR_VAL + 1u) == 1000u, "1 МГц счёт, 1 кГц ШИМ");
void pwm_init_g0(void)
{
RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
RCC->APBENR1 |= RCC_APBENR1_TIM3EN; /* у G0 — APBENR1 */
GPIOA->AFR[0] = (GPIOA->AFR[0] & ~(0xFu << 24)) | (1u << 24); /* PA6 -> AF1 = TIM3_CH1 */
GPIOA->MODER = (GPIOA->MODER & ~(3u << 12)) | (2u << 12);
TIM3->PSC = PSC_VAL;
TIM3->ARR = ARR_VAL;
TIM3->CCR1 = 250u;
TIM3->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1PE;
TIM3->CCER = TIM_CCER_CC1E;
TIM3->CR1 = TIM_CR1_ARPE | TIM_CR1_CEN;
}
Дальше: раздел 13а «Сервопривод: ШИМ 50 Гц, импульс 1–2 мс, угол, плавное движение и питание».