Часы на stm32 своими руками

Добавил пользователь Алексей Ф.
Обновлено: 05.10.2024

Коллеги, нужна помощь. Контроллер STM32, часы DS3231, Блютус, матрица 10х15. Всё работает, но засада с часами. При первом включении время с DS3231 считывает верно, но эти часы и минуты так и остаются. т.е. эффекты крутятся, часы в ДС-ке тикают но на экран выводятся только то время которое прочиталось при включении. Где копнуть, есть идеи?

Александр Симонов

Коллеги, нужна помощь. Контроллер STM32, часы DS3231, Блютус, матрица 10х15. Всё работает, но засада с часами. При первом включении время с DS3231 считывает верно, но эти часы и минуты так и остаются. т.е. эффекты крутятся, часы в ДС-ке тикают но на экран выводятся только то время которое прочиталось при включении. Где копнуть, есть идеи?

Вложения

Александр Симонов

Старик Похабыч

происходит коррекция времени. Как определяется потеря питания не смотрел.

Далее имеем безусловное получение информации с часов:

Вернее условно-безусловное. если USE_CLOCK равен 1.
кстати, в начале есть такая строка, которая определяет переменные минут, секунд и часов по умолчанию:

Видим, что rtc.now() - это получение текущего времени из часов. (предполагаем, что автор, как и я, не знаком с используемой библиотекой часов)
Так же понимаем, что это время полученное в setup , а что бы получать верное время меняться оно должно где ? в LOOP конечно.

Далее я ищу где еще используется rtc.now(); и вижу что только 2-х местах в файле clock , в функции clockTicker и clockRoutine. причем clockTicker вызывается из clockRoutine при определенном условии. Именно в этой функции идет отрисовка часов на ленте функцией drawClock.
А поискав еще я нашел вторую функцию clockRoutine - пустую!

Теперь вопрос. Часы как отображаются на гирлянде ?

Функция clockRoutine вызывается в файле custom из функции customModes, причем в 3-х случаях, когда режим равен 2, 10 и 23, а сама customModes вызывается из функции customRoutine, которая есть в цикле loop.

Таким образом, при определенных условиях, работать должно!

Писал специально подробно, показывая, что ничего сложного в раскопках кода нет, может кому пригодиться как урок


Давно мечтал сделать электронные наручные часы и вот наконец собрался. Часы сделаны на микроконтроллере STM8L151G4U6, а в качестве индикаторов были исользованы АЛС314А. В режиме с отключённой индикацией потребляемый ток всего несколько микро Ампер и батарейки типа CR2032 3 Вольта должно хватить где-то на год.

Универсальный таймер на микроконтроллере STM8


Таймер разработан для использования совместно с УФ лампой. Прошивка может быть загружена в микроконтроллер, установленный на оригинальной плате или в микроконтроллер платы термостата W1209 доступном на Aliexpress и Ebay. Тип используемой платы задаётся в файле uv_timer.h см. строки 6-8.

Перечень элементов и gerber-файлы печатной платы находятся в каталоге /pcb. Для заказа печатной платы используйте файл UVTimer_V1.02.zip

Характеристики:

Напряжение питания: 7-30V;
Максимальны ток нагрузки: 1A;
Выдержка: 0.1c-90мин

Термометр на STM8S103K3 и DS18B20

Термометр на STM8S103K3 и DS18B20

Предлагаю вниманию радиолюбителей термометр, выполненный на микроконтроллере STM8S103K3. Устройство заточено под двухзонный контроль температуры с помощью датчиков DS18B20 (один датчик на плате, другой - выносной). Значения отображается на трехсимвольном семисегментном дисплее. Номер зоны измерения температуры обозначается свечением отдельного светодиода. Переключение зон осуществляется кнопкой.

Простые часы с будильником на STM8Sx03

Простые часы с будильником на STM8Sx03

Данные часы без лишних функций, показывают только время и имеют будильник. В основе проекта микроконтроллер STM8Sx03. Чтобы каждый раз не пришлось устанавливать время после отключения источника питания, я применил микросхему RTC PCF8563 с питанием от батареи CR1220.

На плате установлен разъем microUSB для подключения основного источника питания 5В. Имеются две кнопки для установки времени и будильника. Удерживайте S1 для установки времени или S2 для установки будильника. Управление четырехразрядным семисегментным дисплеем осуществляется методом мультиплексирования, чтобы не превышать ток вывода контроллера.

G-стоп - мигающий стоп сигнал с G-сенсором

G-стоп - мигающий стоп сигнал с G-сенсором

Насмотревшись и начитавшись бортжурналов про изготовление стоп-сигнала с G-сенсором, решил и себе такое собрать. Моргающий стопак, вообще сильно раздражает людей., да оно и понятно. Ведь стоя в пробке на АКПП, удерживаешь тормоз, и перед глазами сзади стоящего водителя постоянно блымает ваш стоп-сигнал. Именно поэтому очень понравилась реализация Степана-Павловича, на основе акселерометра. На ней и остановился. Но повторять поделку, не было особого желания, поэтому собрал полностью свой вариант с нуля, на основе процессора STM8S и акселерометра LIS302SG.

Цифровой запоминающий осциллограф Neil Scope 3

Цифровой запоминающий осциллограф Neil Scope 3

Основные характеристики осциллографа:
- Полоса пропускания аналога 20 МГц
- Разрядность АЦП 8 бит
- Частота дискретизации на канал 100Mвыб/с
- Минимальная чувствительность 50 В/дел*
- Максимальная чувствительность 10 мВ/дел
- Предельное входное напряжение 100 В*
- Объем ОЗУ 256 Кбайт на каждый канал
- Интерфейс связи с ПК USB 2.0 FullSpeed

* максимальное входное напряжение зависит от максимального напряжения пасивных элементов входного делителя.

Часы с таймером на STM8S105K4

Часы с таймером на STM8S105K4

Особенность данных часов в том, что для отображения одной цифры используются по три знакоместа из каждой строки LCD WH1602. Устройство выполнено на микроконтроллере STM8S105K4, который тактируется от внешнего кварца частотой 16МГц. Для управления используются 4 кнопки - кнопка управления часами, кнопка управления таймером и две кнопки для изменения значений часов и минут. Максимальное время отсчета таймера - 60 минут. По окончанию отсчета звучит сигнал зуммера.

Аудио спектр-анализатор на светодиодной матрице

Сначала я скажу что люблю работать со светодиодами и светодиодными матрицами. Пару недель назад я заказал несколько матриц разрешением 5х7 на Ebay, а затем я увидел этот проект. Простота этого проекта мне показалась интересной, но у меня не было ATtiny, и я хотел что-то более интерактивное. Тогда вот что я сделал. Светодиодная матрица 5x7 аудио спектр-анализатор.


Простой USB осциллограф - Miniscope v2c

Вольтметр – амперметр с аналоговой шкалой на STM8S103F


Микроконтроллеры STM32: использование встроенных RTC

Ранее в посте Микроконтроллеры AVR: пример работы с часами реального времени DS1302 отмечалось, что DS1302 было бы довольно глупо использовать с микроконтроллерами STM32, так как у них есть встроенные часы реального времени. Давайте же попробуем разобраться, как происходит работа с этими встроенными RTC, и что они умеют.

Как обычно, для экспериментов я использовал плату Nucleo-F411RE, но описанные далее шаги можно повторить и для любой другой отладочной платы. Обратите внимание, что в мире STM32 встречаются микроконтроллеры с RTC, но без функции календаря. Их RTC умеет работать со временем, но не с датами. В качестве примера можно привести используемый в Blue Pill микроконтроллер STM32F103C8T6. Чтобы определить, есть ли в микроконтроллере хардварный календарь, внимательно читайте даташит.

Итак, для включения RTC следует открыть STM32CubeMX и произвести следующие изменения в проекте:

Важно! При проектировании собственной платы нужно серьезно отнестись к выбору конденсаторов рядом с часовым кварцем. Если переборщить с емкостью этих конденсаторов, часы будут идти слишком медленно. На практике неплохо работают конденсаторы на 10 пФ.

Наконец, во вкладке Clock Configuration будет не лишним перепроверить, что LSE действительно используется:

Настройка LSE в STM32CubeMX

В Makefile понадобится добавить пару файлов к списку C_SOURCES:

Теперь можно спокойно использовать RTC в коде. Например, получение даты и времени осуществляется так:

RTC_TimeTypeDef time ;
RTC_DateTypeDef date ;
HAL_StatusTypeDef res ;

res = HAL_RTC_GetTime ( & hrtc , & time , RTC_FORMAT_BIN ) ;
if ( res != HAL_OK ) <
UART_Printf ( "HAL_RTC_GetTime failed: %d \r \n " , res ) ;
return ;
>

res = HAL_RTC_GetDate ( & hrtc , & date , RTC_FORMAT_BIN ) ;
if ( res != HAL_OK ) <
UART_Printf ( "HAL_RTC_GetDate failed: %d \r \n " , res ) ;
return ;
>

А так происходит их изменение:

int RTC_Set (
uint8_t year , uint8_t month , uint8_t day ,
uint8_t hour , uint8_t min , uint8_t sec ,
uint8_t dow ) <
HAL_StatusTypeDef res ;
RTC_TimeTypeDef time ;
RTC_DateTypeDef date ;

date. WeekDay = dow ;
date. Year = year ;
date. Month = month ;
date. Date = day ;

res = HAL_RTC_SetDate ( & hrtc , & date , RTC_FORMAT_BIN ) ;
if ( res != HAL_OK ) <
UART_Printf ( "HAL_RTC_SetDate failed: %d \r \n " , res ) ;
return - 1 ;
>

time . Hours = hour ;
time . Minutes = min ;
time . Seconds = sec ;

res = HAL_RTC_SetTime ( & hrtc , & time , RTC_FORMAT_BIN ) ;
if ( res != HAL_OK ) <
UART_Printf ( "HAL_RTC_SetTime failed: %d \r \n " , res ) ;
return - 2 ;
>

Заметьте, что структура RTC_TimeTypeDef помимо самого времени хранит ряд дополнительных полей. Они могут не очень аккуратно заполняться процедурой HAL_RTC_GetTime . Поэтому при изменении времени структуру лучше заполнить самостоятельно. Иначе можно увидеть, как часы показывают 27 часов, и налететь на прочие потрясающие баги.

Следует также иметь в виду, что в RTC не предусмотрено защиты от дурака, что позволяет выставить дату вроде 31 февраля. Если пользователь вашего устройства может изменять дату, вы должны предусмотреть в коде валидацию вводимых данных, знающую про високосные года и всякое такое. Эта тема уже поднималась в данном блоге, поэтому снова на ней я останавливаться не буду. Пример валидации вы найдете в полной версии исходников к данному посту (ищите в конце текста).

Для питания RTC нужно подать от 1.6 В до 3.6 В на пины микроконтроллера VBAT и GND. Я использовал батарейку CR2032:

Пример использования встроенных RTC микроконтроллеров STM32

Для вывода времени, даты, дня недели и выбранных цветов интерфейса я использовал TFT-экранчик на базе ST7735. Для изменения даты, времени, и всего остального используются четыре кнопки. Действия кнопок сверху вниз: переход назад, перех вперед, уменьшить значение, увеличить значение.

Интересно, что при отсутствии основного питания батарейка питает не только часы, но и небольшое количество SRAM, так называемую backup memory (она же backup registers). Для доступа к ней при инициализации устройства нужно сказать:

void init ( ) <
/* . (пропущено) . */

После чего можно осуществлять чтение и запись памяти. Я решил хранить в ней выбранный пользователем цвет интерфейса:

uint8_t chosen_color = ( uint8_t ) HAL_RTCEx_BKUPRead ( & hrtc , RTC_BKP_DR1 ) ;

Как видите, backup memory поделена на 32-х битные регистры. Количество регистров зависит от микроконтроллера, их точное число можно узнать из даташита. Например, использованный мной STM32F411RE имеет 20 регистров. То есть, суммарно в backup memory он может хранить до 80 байт данных. Учитывая, что большинство микроконтроллеров STM32 не имеют встроенного EEPROM, наличие у них backup memory оказывается весьма кстати.

В целом, я не нашел серьезных дефектов во встроенных RTC. Время они показывают весьма точно, дату и день недели обновляют правильно, отключение основного питания переживают. RTC имеют и другие возможности, которые не были рассмотрены выше. Например, есть настройки для дополнительной калибровки часов. А еще RTC могут генерировать прерывания, выводящие микроконтроллер из энергосберегающего режима по расписанию. Однако эти моменты уже выходят за рамки данного поста. В качестве источника дополнительной информации можно порекомендовать книгу Mastering STM32.

Полную версию исходников к этому посту вы найдете на GitHub. Любые вопросы и дополнения, как обычно, всячески приветствуются!


Что необходимо для экспериментов:

  • Аппаратные средства
  • Программное обеспечение

Аппаратные средства

Программное обеспечение

    (UM0462) (usb vcp) Среда разработки — программа - конфигуратор, создание шаблона прошивки.
  • эмулятор терминала terraterm

Что такое модуль

Порты микроконтроллера

У микроконтроллера есть выводы или ножки. Часть из них это питание микроконтроллера, часть имеют специальное назначение (например Reset ), часть — интерфейс ввода/вывода общего назначения (англ. general-purpose input/output, GPIO).

Порты объединены в группы ( A; B; C. ). Каждая группа содержит до 16 портов, пронумерованных от 0 до 15. В итоге нумерация портов выглядит как PA0, PA1,…

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

GPIO — Интерфейс ввода/вывода общего назначения

В модуле IO основные типы портов представлены в таблице:

В качестве датчиков, исполнительных механизмов будем использовать различные устройства от Arduino.

Программа MIOC ( Module Input-Output Configurator )

С помощью данной программы создаем / конфигурируем шаблон прошивки (проект для Embitz; Keil) модуля IO. Программа установки не требует. Скачали, запустили. С помощью данной программы создаём глобальные переменные, которые будем использовать в своих прошивках. Переменные могут быть ассоциированы с портами.

Окно первого запуска:



Выбрать папку для проекта. Папка, для проекта должна быть пуста!




Добавить строку в таблицу переменных



Генерируем BSP код (кнопка F8)


Далее, каждый раз после изменения проекта, обязательна генерация BSP!

Открыть созданный проект в среде разработки EmBitz или Keil. EmBitz пока как временное решение. Похоже автор забросил данный проект. По всей видимости в дальнейшем в проекте будет использоваться Code::Blocks.

В файле main.c напишем следующее:



(Для увеличения размера картинки откройте её в новой вкладке)

В EmBitz нажать F2, после появления окна информации нажать F7. Должна выполниться компиляция.

Повторное нажатие F2 скроет информационные закладки.


Загружаем в микроконтроллер, смотрим, как работает.

Кнопка

Добавим кнопку, например такую:



Добавим переменную в таблицу:


Изменим программу на следующую:


Создаём новую BSP (F8), компилируем, загружаем в микроконтроллер.

Нажимаем на кнопку — светодиод зажигается, отпускаем — тухнет.

Вместо светодиода на другой порт можно подключить реле, например:


И управлять какой либо полезной нагрузкой.

Нужно определить, что будет консолью.

  • адаптер USB-UART
  • виртуальный COM-порт (кабель Micro-USB)



Теперь на консоли будет отображаться состояние кнопки:


DS18B20


Поместим в таблицу переменную:


Изменим программу на следующую:


Создаём новую конфигурацию, компилируем, загружаем в микроконтроллер.

На консоли будет отображаться температура, измеряемая датчиком.


В качестве примера работы с АЦП можно использовать потенциометр:


Или датчик влажности почвы


Остановимся на последнем:



В консоли наблюдаем:


adc — текущее показание АЦП. max и min — зафиксированные минимальное и максимальное показания датчика, совсем сухой (0%) и совсем мокрый (100%).

Совсем мокрый (100%) — опустим датчик в стакан с водой. Совсем сухой (0%) — лежит на открытом воздухе.

По сути мы сделали калибровку датчика влажности почвы от 0 до 100%. Максимальное и минимальное значения поместим в текст программы.


Результат работы. Датчик помещен в землю цветочного горшка:


Данный проект — шаблон решения для полива растений.

На этом пока всё. Программа MIOC будет пополняться дополнительными возможностями.


Продолжаем тему таймеров в STM32. В прошлый раз мы рассмотрели базовые таймеры, которые довольно-таки просты. Но сегодня мы поиграемся с более крутой игрушкой — таймерами общего назначения, которые на голову выше предыдущих.

  • До 4-х каналов для:
    • Захвата сигнала (input capture).
    • Сравнения вывода (output compare).
    • Генерации сигнала ШИМ (выровненного по границе или по центру).
    • Генерации одиночных импульсов.
    • Обновление: переполнение счётчика.
    • Событие-триггер: старт, остановка, инициализация счётчика или его обновление внутренним или внешним триггером.
    • Захват сигнала.
    • Сравнение (output compare).
    • Включение BRK.

    Вот как вы думаете, если у таймеров общего назначения так много функций, чем тогда продвинутые (advanced-control) таймеры отличаются от них? o_O
    Правильный ответ — почти ничем, это по факту просто таймеры общего назначения, которые не имеют никаких ограничений: в них напихано по 4 канала (с комплементарными) и есть все возможности сразу, без какого-то ни было разброса. Так что остальная часть статьи будет относиться ко всем таймерам выше базовых, а продвинутые таймеры я отдельно упоминать не буду.

    В даташите на STM32F100xx ( ещё ссылка ) есть сводная таблица возможностей таймеров, в которую тоже удобно поглядывать для справки:


    Кстати, обращайте внимание на сноски. Например, там написано, что у МК семейства Low density Value line нет таймера TIM4.

    Захват сигнала

    В этом режиме с выбранного канала захватываются импульсы, на каждый из них текущее значение счётчика таймера кладётся в регистр TIM_CCRx, где x — номер канала. Таким образом, период следования импульсов равен разнице между текущим значением TIM_CCRx и предыдущим. Ну а для того, чтобы получить период в каких-то внятных единицах измерения, нужно настроить предделитель через функции базового таймера.

    При этом можно настроить генерацию прерывания и запроса DMA на приход очередного импульса, и если в это время предыдущее значение TIM_CCRx не было считано, будет сгенерировано так называемое прерывание over-capture, т.е. сигнал о том, что предыдущее значение потерялось.

    Ловить можно фронты, спады или и то, и другое вместе. Есть настройка так называемого фильтра — числа выборок, после которого переход уровня будет считаться состоявшимся (полезно для устранения дребезга). Значение фильтра может принимать значения от 0 (фильтр выключен) до 15 (0xF). Также настраивается делитель входной частоты — 2, 4 или 8: будет ловиться каждый 2й, 4й или 8й импульс соответственно.

    Примера ради подёргаем вывод PB15 и замерим таймером TIM3 период, подключив PB15 к его каналу 1 (PA6):


    Изменим предыдущий пример, используя захват ШИМ (прокомментированы только изменения):

    Режим чтения энкодера

    Работу с энкодером я уже как-то описывал , и тогда я считывал и декодировал данные с энкодера программно, здесь же таймер сделает работу за нас (не всю, конечно же). Боковые выводы энкодера надо подключить к двум каналам таймера, а средний вывод — к GND. Таймер в этом режиме сам обрабатывает поступающие с энкодера импульсы, а также увеличивает/уменьшает свой счётчик на 4 при каждом щелчке энкодера, и запоминает направление вращения.

    Так как мне захотелось ещё и прерывание заиметь, я сделал период равным 4 и разрешил счёт в обе стороны, так что теперь прерывание будет возникать при каждом щелчке энкодера. Использовал я каналы 1 и 2 таймера TIM3 (PA6 и PA7):

    Сравнение вывода (output compare)

    В этом режиме выбранный канал таймера будет подключен к соответствующему выводу и будет изменять его (вывода) состояние каждый раз, когда счётчик таймера досчитает до значения регистра TIM_CCRx. Состояние вывода, в зависимости от настройки, будет меняться на ноль, на единицу или на противоположное текущему. У многих таймеров у каналов есть комплементарные выводы, которые по умолчанию являются инверсными: на такой выход подаётся тот же сигнал, что и на обычный, но с противоположным уровнем.

    Смотрим в сводную таблицу по таймерам в даташите и видим, что комплементарных выводов у TIM3 нет, но вот у единственного канала таймера TIM16 есть такой вывод — этот таймер я и использую для примера. Вообще, комплементарные выводы есть и у нескольких других таймеров, но вот TIM15 — особенный: у него есть два канала, но комплементарный вывод имеет только 1й канал. Будьте бдительны!

    В таблице пинаутов находим выводы канала 1 таймера TIM16 — PB8 (основной) и PB6 (комплементарный). Для иллюстрации работы таймера подключим эти выводы к светодиодам на плате STM32VLDiscovery — PC8 и PC9, которые в коде мы отключим от греха подальше. Таким образом, выводы канала таймера будут напрямую мигать светодиодами:


    В это примере я выбрал режим переключения вывода в противоположное состояние (TIM_OCMode_Toggle), а остальные настройки оставил по умолчанию. Кстати, не забывайте вызывать функции типа TIM_OCStructInit() для инициализации соответствующих структур, даже если заполняете все поля структур вручную: copy&paste-ориентированное программирование никто не отменял, но при нём легко забыть заполнить какое-нибудь поле и ловить потом баги.

    В режиме сравнения генерируется то же самое прерывание, что и в режиме захвата сигнала — TIM_IT_CCx, но здесь оно было не нужно, поэтому я его не разрешал.

    Генерация ШИМ

    Вот это куда более интересная и практичная штука. Принципы ШИМ уже неоднократно были описаны — как на нашем сайте , так и у Di Halt'a (уж там разжёвано всё до мелочей), а я сосредоточусь на особенностях реализации в STM32.

    Отличной иллюстрацией крутизны таймеров STM32 для генерации ШИМ будет типичная прикладная задача — управление сервомашинкой : Как известно, сервы управляются импульсами переменной ширины, которые шлются с частотой примерно 50 Гц (каждые 20 мс). У сервы, которая оказалась под рукой (Robbe 4.3 g), ширина управляющего импульса от 500 мкс (0°) до 2250 мкс (175°), судя по замерам — то есть, по 10 мкс на каждый градус поворота:

    ΔT = T₂ — T₁ = 2250 — 500 = 1750 мкс
    ∠A = 175°
    ΔT/A = 10 мкс/°

    1. Установить таймеру такой делитель частоты, чтобы отсчёт вёлся каждые 10 мкс.
    2. Задать период ШИМ в 20 мс, то есть 2000 отрезков времени по 10 мкс.
    3. Класть в регистр сравнения число, равное 50 (500 мкс / 10 мкс) + задаваемый угол.
    4. Регистр сравнения лучше обновлять строго в момент окончания периода во избежание дёргания сервы.

    Dead-time

    Если кто не знает, это задержка фронтов сигналов на основном и комплементарном выводах канала таймера. Эта функция есть у некоторых таймеров (смотрите руководство), и нужна она бывает для исключения сквозных токов при управлении силовыми ключами [полу]мостовых схем. Даже не спрашивайте меня, что это такое — это вне моей компетенции.

    Настраивается этот самый dead-time в поле TIM_DeadTime структуры TIM_BDTRInitTypeDef и имеет диапазон значений с 0 по 255 (0xFF). Но смысл этого числа не так уж прямолинеен:


    Ага, вот так оно и рассчитывается. Здесь Tdts — это длительность такта генератора dead-time (DTG), зависящая от Tdts — текущей частоты тактирования таймера. Обычно таймеры тактируются системной частотой, и TIM_Prescaler на это никак не влияет, а влияет поле TIM_ClockDivision структуры TIM_TimeBaseInitTypeDef — делитель частоты таймера.

    Для примера положим, что таймер затактирован без деления частоты (делитель равен 1, TIM_CKD_DIV1), системная частота F равна 24 МГц, а значение DTG = 150. Тогда:

    Я тут для примера набросал код с dead-time попроще для расчёта: DTG=96 ⇒ DT=96.


    Для того, чтобы узреть этот самый dead-time на одноканальном осциллографе, нужно подключить PB8 и PB6 через резисторы 1 кОм к его щупу:


    Т.к. на эти выводы идут взаимно инверсные сигналы, на экране будут прекрасно видны места, где во время dead-time уровень на обоих входах одинаков из-за задержки фронтов:


    Ну, и напоследок — имейте ввиду, что если длительность dead-time превышает длительность импульса на выводе, то соответствующий импульс не будет сгенерирован вообще.

    Счётчик повторений

    Этот счётчик имеется у нескольких таймеров (TIM15, TIM16 и TIM17) и выполняет он очень простую функцию: генерировать событие (прерывание или запрос DMA) update не на каждое переполнение счётчика, а на каждые N переполнений. То есть, вы задаёте счётчик повторений, таймер его копирует в скрытый регистр и при каждом переполнении уменьшает значение копии на 1. Когда значение достигает нуля, генерируется событие update, таймер снова копирует счётчик повторений и т.д. На самом деле, перечисленные таймеры и так задействуют этот счётчик, просто по умолчанию его значение равно нулю, и событие генерируется на каждое переполнение.

    Счётчик может принимать значения от 0 до 255 (0xFF). Описывать тут особо нечего, потому что для использования этой функции достаточно при инициализации таймера написать что-то вроде:


    и всё. В этом случае событие update будет генерироваться каждые 8 переполнений (7 повторений).

    Если вам вдруг понадобится резко перевести выводы каналов таймера в заранее определённое состояние (например, выключить), то эта функция — то, что нужно. Включить её проще пареной репы — нужно сконфигурировать пин TIMx_BKIN на вход, и при инициализации BDTR включить вход BRK:


    По умолчанию для активации функции break нужно на вход BRK подать логический ноль, но это можно настроить в поле TIM_BreakPolarity. Как только break активирован, все выводы каналов переходят в состояние, которое задаётся при их инициализации полями TIM_OCIdleState и TIM_OCNIdleState в структуре TIM_OCInitTypeDef (по умолчанию на выводах будет низкий уровень). Dead-time при этом учитывается.

    Синхронизация таймеров

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

    Для этого нужно настроить выходной триггер таймера TIM3 на переполнение (update), а входной триггер таймера TIM2 — на вход с триггера TIM3. Смотрим в таблицу соединения триггеров для таймеров TIM2-TIM4 (таких таблиц несколько — для разных групп таймеров):


    Читайте также: