STM Урок 147. LL. Таймеры. Часть 2



В предыдущей части нашего урока мы познакомились с типами таймеров в STM32F1, а также с некоторыми регистрами таймеров, которые мы теперь будем использовать на практике в нашем проекте.

 

Теперь, накопив о таймерах столько знаний, можно перейти и к созданию проекта.

Проект создадим из проекта урока 146 с именем LL_BLINK01 и присвоим ему, соответственно, имя LL_TIM2.

Откроем проект в Cube MX и включим для начала таймер TIM2

 

 

Настроим параметры нашего таймера таким же образом, как мы делали это в уроке 5 по HAL на регулярное срабатывание через 100 милисекунд

 

 

Включим прерывания от таймера

 

 

Идём в раздел Project Manager, слева затем выбрав пункт Advanced Settings, и в настройках TIM2 также выберем вместо HAL библиотеку LL

 

 

Сгенерируем проект, откроем его в KEIL, настроим программатор на автоматическую перезагрузку контроллера и выставим уровень оптимизации в 0.

 

 

Перейдём в файл main.c и добавим функцию-обработчик события таймера TIM2

 

 

Перейдём в файл stm32f1xx_it.c и создадим там прототип нашей функции

 

 

Вызовем нашу функцию в обработчике

 

 

Вернёмся в файл main.c, оставим пока в покое нашу функцию, мы к ней вернёмся позже, а посмотрим, как инициализируется наш таймер, думаю, это многим будет интересно.

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

Дальше мы видим, что у нас здесь происходит поначалу инициализация структуры для таймера

 

 

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

Сначала проверяется наличие заполненных параметров, а затем читается регистр CR1 таймера

 

 

Затем в данном регистре устанавливаются или сбрасываются биты DIR и CMS в соответствии с установками поля CounterMode структуры таймера (в нашем случае будут нули, то есть считаем вверх без всякого выравнивания)

 

 

Затем устанавливается делитель в том же регистре, если он задействован

 

 

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

 

 

Затем из поля структуры Autoreload записываются данные в регистр ARR

 

 

Аналогично устанавливается предделитель в регистр PSC

 

 

 

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

 

 

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

 

 

Далее устанавливается источник тактирования таймера в регистре SMCR путём установки или сброса битов ECE и SMS согласно данным макроса во втором входящем аргументе, в нашем случае LL_TIM_CLOCKSOURCE_INTERNAL, судя по установкам которого мы данные биты сбрасываем

 

 

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

 

 

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

 

 

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

 

 

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

 

 

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

 

 

А происходит это потому, что наш таймер считает, прерывания генерируются, флаг прерывания устанавливается, но никто его не сбрасывает и следующее прерывание висит на очереди и, соответственно дальнейший код не выполняется.

Поэтому перейдём в наш обработчик и первым делом очистим наш флаг, обработав условие его установки

 

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

Добавим глобальный счётчик тиков таймера

 

 

Обнулим его в main()

 

 

В обработчике после сброса флага UIF в регистре SR проинкрементируем наш счётчик и, если он достиг 10, то сбросим его, так как у нас 10 светодиодов

 

 

И до этих действий мы, в зависимости от того, до скольких сосчитал наш счётчик, зажжём соответствующий светодиод, погасив предыдущий

 

 

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

 

 

Таким образом, сегодня мы научились работать с таймером, используя библиотеку LL, конечно не со всем функционалом таймеров, которые необъятны, а лишь с частью из него. Но, тем не менее, эта часть послужит, надеюсь, неплохим уроком для дальнейшего совершенствования навыков программирования контроллеров. Также мы изучили подробно немалое количество регистров таймера контроллера STM32F103.

 

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

 

 

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

 

Исходный код

 

 

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

Программатор недорогой можно купить здесь ST-Link V2

 

 

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

 

STM LL. Таймеры

Один комментарий на “STM Урок 147. LL. Таймеры. Часть 2
  1. zhenya_nguyen:

    если я не ошибаюсь, срабатывание счетчика происходит каждые 100 мс а не 100 мкс, как вы написали

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

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

*