STM Урок 207. LL. STM32F4. Таймеры



Продолжаем работу над программированием линейки контроллеров STM32F4 с использованием библиотеки LL.

Теперь давайте поработаем с таймерами.

С таймерами мы работаем уже давно и постоянно, также и с использованием библиотеки LL, но только общались мы с применением данной библиотеки с таймерами только применяя контроллеры серии F1. Теперь настала пора поработать и с серией F4.

Разница в таймерах между данными сериями не столь велика, поэтому, думаю, будет несложно. Тем более по архитектуре таймеров мы уже прошлись в уроке с применением библиотеки HAL, а по регистрам — при использовании библиотеки LL для серии F1 в уроке 147, поэтому в изучение аппаратной реализации нам углубляться на данном уроке сильно не придётся. Конечно же, если вдруг, встретится что-то новое в этом, мы обязательно такой вопрос изучим.

Плату мы по прежнему будем использовать STM32F429I-DISCOVERY.

Проект мы за основу возьмём с прошлого урока с именем LL_BLINK01 и присвоим ему имя LL_TIMER. Проект на основе существующего делается точно также, как и в случае использования IDE SystemWorkbench. Также данный процесс по пунктам я описал в текстовом файле, который лежит в архиве с проектом.

Откроем наш проект в Cube MX и включим там таймер 6, так как он один из самых простых по настройке

 

 

Настроим таймер на период 500 милисекунд и включим события по обновлению

 

 

Также включим глобальные прерывания

 

 

Можно, в принципе, немного назначить ниже приоритет данных прерываний (цифру ставим выше, чтобы назначить приоритет ниже, самый высокий — 0), чтобы они не толпились с прерываниями от системного таймера, иначе обычные задержки рискуют быть неточными, хотя и с одинаковыми приоритетами траблов замечено не было

 

 

Задействуем библиотеку LL под таймеры

 

 

Сгенерируем проект, откроем его в CubeIDE и для начала посмотрим, как происходит инициализация нашего таймера, для чего зайдём в тело функции MX_TIM6_Init, где сначала включается тактирование периферии при помощи функции LL_APB1_GRP1_EnableClock, вследствие чего устанавливается данный бит

 

 

Дальше назначается приоритет и включаются глобальные прерывания. Этот процесс мы пока не рассматриваем, так как это тема отдельного урока.

Затем заполняется структура и вызывается функция LL_TIM_Init, в теле которой выполняется ряд макросов и функций в зависимости от того, какой таймер. Рассмотрим только те условия, в которые мы попадём в случае использования нашего таймера.

 

 

Сначала считывается весь регистр CR1 в переменную

 

 

В условие макроса установки режима IS_TIM_COUNTER_MODE_SELECT_INSTANCE мы не попадаем.

Делителя у нас нет, поэтому в тело следующего условия if (IS_TIM_CLOCK_DIVISION_INSTANCE(TIMx)) мы также не попадаем.

Далее идут вызовы функций без условий.

Первая функция LL_TIM_WriteReg(TIMx, CR1, tmpcr1) занесёт настройки в регистр CR1, считанные до этого и затем изменённые. Но так как мы никуда не попали, мы занесём в регистр то же, что и считали из него.

Далее с помощью вызова следующей функции данные из поля структуры Autoreload записываются регистр ARR

 

 

Регистр ARR полностью аналогичен одноимённому регистру из серии F1.

Далее устанавливается предделитель путём занесения данных из поля структуры в регистр PSC, также полностью аналогичный с одноимённым регистром серии F1, при помощи следующей функции

 

 

Следующее условие IS_TIM_REPETITION_COUNTER_INSTANCE(TIMx) у нас также не выполнится, поэтому в его тело мы не попадём, , а дальше устанавливается бит UG в регистре EGR, так как мы выбрали в Cube обработку событий Update Event

 

 

Возвращаемся назад на уровень выше в функцию MX_TIM2_Init, где далее очищается бит ARPE в регистре CR1

 

 

Далее в регистре CR2 устанавливаются или сбрасываются биты поля MMS также согласно установкам макроса, в нашем случае устанавливается бит MMS1, что означает выбор режима Update

 

 

 

И в заключении настройки таймера отключается режим MASTER/SLAVE сбросом бита MSM в регистре SMCR

 

 

Переходим в функцию main, где сначала удалим весь пользовательский код из бесконечного цикла, а затем разрешим прерывания путём установки бита UIE в регистре DIER с помощью специальной функции библиотеки

 

 

И далее непосредственно запускаем таймер, то есть заставляем его считать тики посредством установки бита CEN в регистре CR1

 

 

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

 

 

В данном условии при помощи функции LL_TIM_IsActiveFlag_UPDATE мы проверяем на установку бит UIF в регистре SR, затем при помощи функции LL_TIM_ClearFlag_UPDATE его же и сбрасываем.

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

 

 

А затем мы его вызовем в функции TIM6_DAC_IRQHandler

 

 

Вернёмся в файл main.c и добавим там глобальный пользовательский флаг для переключения текущего состояния светодиода

 

 

Далее в нашем обработчике TIM6_Callback в зависимости от состояния данного флага зажжём соответствующий светодиод, а другой погасим, а также переключим флаг

 

 

Соберём код, прошьём контроллер и увидим, что каждые полсекунды светодиоды на плате меняют состояние, то есть зажигаются и гаснут по очереди

 

 

Итак, на данном уроке мы научились работать с таймером контроллера линейки STM32F4, используя библиотеку LL.

Всем спасибо за внимание!

 

 

Предыдущий урок Программирование МК STM32 Следующий урок

 

Исходный код

 

 

Отладочную плату можно приобрести здесь STM32F429I-DISCO

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

STM LL. STM32F4. Таймеры

2 комментария на “STM Урок 207. LL. STM32F4. Таймеры
  1. а почему предыдущего урока нет?

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*