Embedded HandbookПриложения
Все разделы › III. Периферия
STM32F103, STM32F407 · уровень средний · 21 мин чтения
Открыть в интерактивном справочнике

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 МГц. Расчёт по частоте шины даёт вдвое неверный результат — и это, пожалуй, самая частая ошибка при работе с таймерами.

Проверять всегда стоит по факту: настроить период в секунду и посмотреть на светодиод. Мигает вдвое быстрее — вы попались.

TIM2 от шины APB1 до прерывания: удвоение частоты, предделитель, счёт до ARR и событие обновления раз в миллисекунду


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 %. Так это выглядит на осциллографе; пилу счётчика таймер наружу не выводит — она нарисована над выходом для наглядности:

ШИМ TIM3 на экране осциллографа: пила счётчика до ARR, уровень CCR1 и выход PA6

Компромисс частоты и разрешения. Произведение частоты на число градаций ограничено тактовой:

Частота ШИМ 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.

Энкодер на обоих фронтах: сигналы A и B со сдвигом на четверть периода, CNT растёт на 1 на каждом фронте — 4 отсчёта на щелчок — и так же убывает при обратном вращении; контакт B дрожит у щелчка, CNT ходит 8, 7, 8, уровень (CNT + 2) / 4 стоит на месте, а CNT / 4 мигает

Практическая деталь: счётчик 16‑битный и переполняется. Для энкодера, крутящегося в одну сторону долго, нужно ловить переполнение прерыванием и вести старшую часть счёта программно — либо взять 32‑битный TIM2/TIM5 на F4.


13.8 Одноимпульсный режим

Таймер выдаёт ровно один импульс заданной длительности и останавливается. Удобно для формирования строба, импульса запуска ультразвукового датчика, задержанного сигнала.

Включается битом OPM в CR1: после первого события обновления счётчик сам себя выключает.


13.9 Синхронизация нескольких таймеров

Таймеры умеют управлять друг другом: один становится ведущим и по своему событию запускает, останавливает или тактирует ведомый. Настраивается парой регистров — CR2 у ведущего (что именно выдавать наружу) и SMCR у ведомого (как реагировать).

Зачем это нужно:


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 Итоги

Полные исходники

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 мс, угол, плавное движение и питание».

Открыть в интерактивном справочнике