Меню

Сброс счетчика таймера stm32

ОБОРУДОВАНИЕ
ТЕХНОЛОГИИ
РАЗРАБОТКИ

Блог технической поддержки моих разработок

Урок 16. Таймеры STM32 в режиме счетчиков. Генерация циклических прерываний от таймеров.

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

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

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

Таймеры STM32.

У нашего микроконтроллера STM32F103C8T6 есть 4 таймера:

  • TIM1 – расширенный таймер, ориентированный на управление электродвигателем.
  • TIM2 … TIM4 – таймеры общего назначения.

Все таймеры имеют одинаковую архитектуру. Расширенный таймер отличается наличием дополнительных аппаратных узлов для формирования противофазных сигналов ШИМ. В результате его можно конфигурировать на работу в режиме 6-канального ШИМ и управлять им тремя полумостовыми усилителями мощности.

Но сейчас нас это не интересует. Для нашей задачи — формирования циклических прерываний, все таймеры имеют одинаковую архитектуру.

Таймеры STM32 — многофункциональные устройства. С помощью каждого из них можно реализовать:

  • Счетчик импульсов, а значит и времени с автоматической перезагрузкой.
  • Захват входного сигнала (4 канала).
    • Обнаружение фронта входного сигнала, запоминание времени, генерация события.
    • Измерение временных параметров входного ШИМ-сигнала: периода и длительности импульсов.
    • Интерфейс энкодера. Измерение параметров импульсов энкодера.
  • Сравнение кодов таймера (4 канала).
    • Генерация события по совпадению кода таймера с заданным значением.
    • Формирование ШИМ-сигнала.
    • Формирование одиночных импульсов, режим одновибратора.

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

Но сейчас нас интересует исключительно режим счетчика с перезагрузкой. Именно в этом режиме удобнее всего формировать циклические прерывания.

Функциональная схема таймера достаточно сложная. Я выделил только необходимую нам часть.

Собственно отсчет импульсов или времени происходит на 16-ти разрядном счетчике CNT. Когда код счетчика достигает значения регистра перезагрузки, счетчик сбрасывается в 0. Таким образом, счетчик считает по циклу от 0 до значения регистра перезагрузки.

Частота сигнала тактирования таймера может быть уменьшена с помощью 16-ти разрядного предделителя PSC.

Перезагрузка счетчика формирует событие (прерывание). Частота его появления также может быть уменьшена счетчиком повторов (8 разрядов). Коэффициент деления задается в регистре повторов.

Код счетчика используется другими узлами таймера, например, для формирования ШИМ. Но об этом в других уроках.

В качестве источника тактирования могут быть выбраны:

  • Внутренние синхросигналы шин APB1 иAPB2, про которые мы говорили в уроке 5 (система тактирования микроконтроллера).
    • Для таймера TIM1 используется синхросигнал шины APB2;
    • Для таймеровTIM2- TIM4 используется синхросигнал шины APB1.
  • Внешнее тактирование, режим 1. Используется выходной сигнал другого таймера или внешний сигнал входов захвата.
  • Внешнее тактирование, режим 2. Используется вывод микроконтроллера ETR.
  • Особый режим синхронизации – интерфейс подключения энкодера.

Сейчас мы будем использовать только внутренний источник тактирования.

Режимы счета таймера.

При использовании таймера в качестве счетчика импульсов можно выбрать один из режимов:

  • прямой счет;
  • обратный счет;
  • двунаправленный.

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

В режиме обратного (реверсивного) счета с каждым входным импульсом содержимое счетчика уменьшается на 1. При достижении 0 в счетчик загружается значение регистра перезагрузки и реверсивный счет продолжается. Таймер считает по циклу от значения перезагрузки до 0. В момент перезагрузки формируется прерывание.

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

Читайте также:  Электронные счетчики электроэнергии каскад

Установка конфигурации таймера с помощью STM32CubeMX.

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

Создадим проект Lesson16_1. Настроим конфигурацию системы тактирования. Обратим внимание на то, что частота тактирования таймеров на шинах APB1 и APB2 задана 72 мГц.

  • PC13 – активный выход;
  • PB13 – активный выход;
  • PB12 – вход с подтягивающим резистором.

Теперь будем конфигурировать таймер 1. В нашем микроконтроллере он самый многофункциональный.

Открываем вкладку Timers ->TIM1.

Выбираем в качестве источника тактирования внутреннее тактирование: Clock Source -> Internal Clock.

Ниже появилось поле Parameter Settings.

Давайте подробно разберем, что в нем.

Prescaler (PSC).

Это регистр предделителя. Предделитель делит частоту тактирования таймера, поступающую на основной счетчик. По сути, он, вместе с входной частотой, определяет разрешающую способность таймера.

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

Счетчик и регистр предделителя 16-ти разрядные. Т.е. максимальный коэффициент деления 65536.

Надо помнить, что реальный коэффициент деления на 1 больше, чем значение регистра предделителя. Например:

Значение регистра предделителя Коэффициент деления
1
999 1000
65535 (максимальное значение) 65536

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

Counter mode.

Режим счетчика, определяет в какую сторону считать.

  • Up – прямой счет.
  • Down – реверсивный счет.
  • Center Aligned mode 1 – двунаправленный счет, прерывание генерируется в момент, когда счетчик считает в обратную сторону и доходит до 0.
  • Center Aligned mode 2 – двунаправленный счет, прерывание генерируется, когда счетчик считает в прямом направлении и достигает значения перезагрузки.
  • Center Aligned mode 3 – двунаправленный счет, прерывание генерируется, в обоих случаях — при достижении 0 и значения перезагрузки.

Counter Period (Auto Reload Register).

Регистр перезагрузки. Его значение задает период работы таймера. Конечно, на время периода влияет еще режим счета.

Счетчик 16-ти разрядный. Значит, для однонаправленного счета период может длиться от 1 до 65536 длительностей импульсов предделителя. Реальная длительность периода на 1 больше значения регистра перезагрузки. Все как для регистра предделителя.

Internal Clock Division (CKD).

Делитель входной частоты для внутренних нужд таймера.

Частота используется при фильтрации внешних сигналов, формировании “мертвого времени” ШИМ и т.п. Сейчас это нам не интересно.

Repetition Counter (RCR).

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

Счетчик 8-ми разрядный. Коэффициент деления на 1 больше значения регистра повторов и может быть в диапазоне 1 — 256. Регистр буферизирован, можно изменять его значения в любой момент.

Auto-reload preload.

Регистр перезагрузки буферизирован. Разработчики микроконтроллера предоставляют программисту выбор — при записи значения перезагрузки передавать его в регистр моментально или дождаться крайнего состояния счетчика.

Управляет режимом перезагрузки специальный бит, а в STM32CubeMX выбор делается в выпадающем меню.

Вкладка NVIC Settings позволяет выбрать нужный тип прерывания, связанного с таймером.

Пример конфигурации таймера и реализации программы.

Сделаем практическую задачу. Установим конфигурацию таймера 1, обеспечивающую циклические прерывания с периодом 0,5 секунд. В обработчике прерывания будем инвертировать состояние светодиода. В результате получим мигающий светодиод, но с использованием таймера и прерывания.

Частота тактирования у нас 72 мГц. Превратим ее с помощью предделителя в круглое значение.

Например, если задать 720 – 1 = 719, то частота после предделителя будет 72 000 000 / 720 = 100 000 Гц, или период 10 мкс.

Читайте также:  Счетчик электроэнергии со 2м2

Если в регистр перезагрузки задать значение 50 000, то получим требуемый период 0,5 секунд.

Во вкладке NVIC Settings выберем прерывание по перезагрузке счетчика.

Создаем проект и открываем его в Atollic TrueStudio.

В папке Src проекта создан файл stm32f1xx_it.c. Он существовал и во всех предыдущих проектах. Просто мы на него до времени не обращали внимания.

Это файл обработчиков прерываний. Хороший стиль размещать функции обработки прерываний в нем.

В самом конце файла появилась функция:

void TIM1_UP_IRQHandler(void) <

/* USER CODE BEGIN TIM1_UP_IRQn 0 */
/* USER CODE END TIM1_UP_IRQn 0 */

/* USER CODE BEGIN TIM1_UP_IRQn 1 */
/* USER CODE END TIM1_UP_IRQn 1 */
>

Это и есть обработчик прерывания таймера 1. Код, который мы поместим в функцию, будет вызываться с периодом 0,5 секунд.

Вызовем в обработчике прерывания функции инверсии состояния для обоих светодиодов.

void TIM1_UP_IRQHandler(void) <

/* USER CODE BEGIN TIM1_UP_IRQn 0 */

HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_13);

Мы установили конфигурацию таймера, но не запустили его. Сделаем это HAL-функцией в файле main.c.

/* Initialize all configured peripherals */

/* USER CODE BEGIN 2 */

HAL_TIM_Base_Start_IT(&htim1); // запуск таймера

Функция запускает таймер в режиме генерации прерываний.

Все. Компилируем, загружаем, проверяем. Оба светодиода мигают раз в секунду.

Полностью проект можно загрузить по ссылке:

Зарегистрируйтесь и оплатите. Всего 40 руб. в месяц за доступ ко всем ресурсам сайта!

Основной цикл у нас пустой. Программа просто крутится в нем.

while (1) <

/* USER CODE END WHILE */

По отношению к нему светодиоды мигают в фоновом режиме, сами по себе. Если мы будем выполнять в цикле какие-либо действия, это никак не скажется на равномерном мигании светодиодов. Единственное условие – надолго не запрещать прерывания.

В следующем уроке будем разрабатывать программу, обрабатывающую сигнал кнопки параллельным процессом. Научимся связывать переменные разных файлов одной программы. Разберемся в специфике использования функций обработки прерываний.

Источник



STM32 с нуля. Timer. Настройка и использование таймеров.

Таймеры в STM32, как в принципе и вся периферия, являются очень навороченными. От обилия разных функций, которые могут выполнять таймеры может даже закружиться голова. Хотя, казалось бы, таймер он на то и таймер, чтобы просто считать. Но на деле все гораздо круче!

Мало того, что таймеры обладают такими широкими возможностями, так их еще несколько у каждого контроллера. И даже не два и не три, а больше! В общем, нахваливать все это можно бесконечно. Давайте уже разбираться, что и как работает. Итак, микроконтроллер STM32F103CB имеет:

  • 3 таймера общего назначения (TIM2, TIM3, TIM4).
  • 1 более продвинутый таймер с расширенными возможностями (TIM1).
  • 2 WDT (WatchDog Timer).
  • 1 SysTick Timer.

Собственно таймеры общего назначения и таймер TIM1 не сильно отличаются друг от друга, так что ограничимся рассмотрением какого-нибудь одного из них. К слову я остановил свой выбор на TIM4. Без особой причины, просто так захотелось :). Таймеры имеют 4 независимых канала, которые могут использоваться для:

  • Захвата сигнала.
  • Сравнения.
  • Генерации ШИМ.
  • Генерации одиночного импульса.

Таймеры 16 битные (то есть могут считать до 65535), умеют работать с инкрементальными энкодерами и датчиками Холла, несколько таймеров можно синхронизировать между собой. Есть прерывания на разные события, а именно:

  • Переполнение.
  • Захват сигнала.
  • Сравнение.
  • Событие-триггер.

При наступлении любого из этих событий таймеры могут генерировать запрос к DMA (DMA – прямой доступ к памяти, уже скоро мы будем разбираться и с ним). Теперь немного подробнее о каждом из режимов работы таймеров.

Режим захвата сигнала. Очень удобно при работе таймера в этом режиме измерять период следования импульсов. Смотрите сами: приходит импульс, таймер кладет свое текущее значение счетчика в регистр TIM_CCR. По-быстрому сохраняем это значение в какую-нибудь переменную. Сидим, ждем следующий импульс… Импульс пришел, таймер снова фиксирует значение счетчика в TIM_CCR, и нам остается только вычесть из этого значения то, которое мы предварительно сохранили. Это, наверное, самое простое использование этого режима таймера, но очень полезное. Отлавливать можно как передний фронт импульса, так и задний, так что возможности довольно велики.

Читайте также:  Счетчики электроэнергии с пультом схемы

Режим сравнения. Тут просто подключаем какой-нибудь канал таймера к соответствующему выводу, и как только таймер досчитает до определенного значения (оно в TIM_CCR) состояние вывода изменится в зависимости от настройки режима (либо выставится в единицу, либо в ноль, либо изменится на противоположное).

Режим генерации ШИМ. Ну тут все уже понятно из названия ? В этом режиме таймер генерирует ШИМ! Наверно нет смысла что-то писать тут еще сейчас. Скоро будет пример как раз на ШИМ, там и поковыряем поподробнее.

Режим Dead-Time. Суть режима в том, что между сигналами на основном и комплементарном выводах таймера появляется определенная задержка. В интернете есть довольно много информации о том, где это можно и нужно применять.

Ну вот, в принципе, кратко об основных режимах работы таймера. Если будут вопросы про другие режимы, более специфические, пишите в комментарии, буду рад помочь!

Надо бы потихоньку написать программу для работы с таймерами. Но сначала посмотрим, что есть в библиотеке Standard Peripheral Library.

Итак, за таймеры несут ответственность файлы – stm32f10x_tim.h и stm32f10x_tim.c. Открываем первый и видим, что структура файла повторяет структуру файла для работы с GPIO, который мы рассматривали в предыдущей статье. Здесь описаны структуры и поля структур, которые нужны для конфигурирования таймеров. Правда здесь уже не одна, а несколько структур (режимов, а соответственно и настроек-то у таймеров побольше, чем у портов ввода-вывода). Все поля структур снабжены комментариями, вот, например:

Здесь будем задавать режим работы таймера. А вот еще:

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

С первым файлом понятно. А в файле stm32f10x_tim.c – готовые функции для работы с таймерами. Тоже все в целом ясно. Мы уже использовали библиотеку для работы с GPIO, теперь вот работаем с таймерами, и очевидно, что для разной периферии все очень похоже. Так что давайте создавать проект и писать программу. Итак, создаем новый проект, добавляем в него все необходимые файлы:

  • необходимо отметить, что в поле TIM_Prescaler нужно записывать значение, на единицу меньшее, чем то, которое мы хотим получить.

В этой программе мы смотрим, что было на выходе до момента генерации прерывания – если ноль, выставляем единицу на 0.5 мс. Если была единица – ставим ноль на 2.5 мс. Компилируем и запускаем отладку!

Небольшое, но очень важное отступление… Наш пример, конечно, будет работать и для теста он вполне сгодится, но все-таки в “боевых” программах нужно следить за оптимальностью кода как с точки зрения его объема, так и с точки зрения производительности и расхода памяти. В данном случае нет никакого смысла использовать структуру timer, а также вызывать функцию TIM_TimeBaseInit() каждый раз при смене периода. Правильнее менять всего лишь одно значение в одном регистре, а именно в регистре TIMx->ARR (где х – это номер таймера). В данном примере код трансформируется следующим образом:

Итак, продолжаем, на пути у нас очередные грабли! А именно ошибка:

  • ..\..\..\SPL\src\stm32f10x_tim.c(2870): error: #20: identifier “TIM_CCER_CC4NP” is undefined

Не так страшно как может показаться, идем в файл stm32f10x.h, находим строки:

И смело дописываем:

Вот теперь все собирается, можно отлаживать. Включаем логический анализатор. В командной строке пишем: la portb&0x01 и наблюдаем на выходе:

Видим, что все работает правильно! В следующей статье будем изучать режим генерации ШИМ, оставайтесь на связи ?

Источник

Adblock
detector