Меню Закрыть

Прерывание по переполнению и сравнению

Прерывание по переполнению и сравнению

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

Что такое прерывания?

Прерывания это механизм который реагирует на  событие которое происходит с микроконтроллером. Бывают внешние (кнопки, датчики, сигналы с других устройств) и Внутренние (internal interrupts) – генерируются внутренними модулями микроконтроллера (таймеры, АЦП, UART и т. д.) и системные.

В нашем случае при работе с таймером генерируется внутреннее прерывание. Например наш таймер досчитал до нужного нам значения.Что происходит в этот момент ?

  1. Возникновение события .Когда таймер достигает своего максимального значения (переполнение) или заданного порога (сравнение), в соответствующем регистре флагов устанавливается бит события.
  2. Запрос прерывания.Если прерывания разрешены (бит разрешения в регистре настроен), микроконтроллер приостанавливает выполнение основного кода и переходит к обработчику прерывания. (подпрограмме в основном коде программы). При этом сохраняется точка куда программа вернётся после выполнения обработчика прерываний.
  3. Выполнение обработчика.  Выполняется код нашего обработчика прерывания.
  4. Возврат в основную программу.Программа возвращается в то место откуда ушла в вектор прерываний.

Переполнение и сравнение

Прерывание по переполнению — это тип прерывания, которое срабатывает, когда счетчик таймера(в регистре ARR) достигает своего максимального значения. Возьмём таймер 4 в микроконтроллере STM32F407VGT6. Это 16 битный таймер а значит его максимальное значение 65535 (помним что счет начинается с нуля). на практике это означает что как только значение регистра ARR достигнет 65535 произойдёт прерывание. 

Прерывание по сравнению — это тип прерывания, которое срабатывает когда счетчик таймера достигает заданного значения. Единственное отличие состоит в том что мы задаём значение в регистре ARR, что позволяет точно отсчитывать интервалы времени.

Рассмотрим как применить это на практике. Задача следующая — используя прерывания по сравнению заставить мигать светодиод на плате с периодом в одну секунду. Будем использовать таймер 2 в микроконтроллере STM32F407VGT6.Первая настройка это источник тактирования. Заходим в настройки таймера (Timers-TIM2) строка Clock Source и выбираем Internal Clock. Используем первый канал в режиме Input capture direct mode.

Далее нужно понять к какой шине подключен таймер. В нашем случае второй таймер подключен к шине APB1 Timers Clocks.(если не уверены, лучше убедится в этом в даташите )

Выставим значения Prescaler на 15999 и Counter period 999.

Перейдем к расчетам.Частота 16 МГц. Наш предделитель 15999 ( счёт начинается с нуля поэтому всегда на 1 меньше ).Частота после предделителя.

16 000 000 / 16000 =  1000 Гц

Чтобы получить время срабатывания.Берём то что задано в регистре Counter period + 1 и делим на полученное значение 

1 000 / 1 000 (Гц) = 1 секунда

Не забудьте включить прерывания нашего таймера.

Код программы.

После генерации нашего кода необходимо добавить несколько строк для запуска и обработки нашего прерывания. В блоке кода добавляем следующие строки.


__HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);

HAL_TIM_Base_Start_IT(&htim2);

Первая строка сбрасывает флаг переполнения таймера (UIF — Update Interrupt Flag). Это важно сделать перед запуском таймера, чтобы прерывание не сработало немедленно из-за ранее установленного флага. Флаг устанавливается автоматически после инициализации в CubeIDE.

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

Когда происходит переполнение таймера(счетчика таймера досчитывает до значения нашего регистра ARR, в нашем случае 999), программа переходит в вектор прерывания, соответствующий заданному таймеру — например, TIM2_IRQHandler для таймера TIM2. На этом этапе у нас есть два способа обработки прерывания:

  1. Работать напрямую с функцией обработчиком прерывания — TIM2_IRQHandler.
  2. Использовать callback-функцию HAL — HAL_TIM_PeriodElapsedCallback.

Если вы используете HAL-библиотеку, рекомендуется использовать именно HAL_TIM_PeriodElapsedCallback. Это более гибкий и безопасный способ, так как HAL сам вызывает этот callback внутри обработчика TIM2_IRQHandler, при этом сохраняя всю свою внутреннюю логику и совместимость. Если же вы не используете HAL или вам нужен максимальный контроль на низком уровне, тогда можно писать код прямо в TIM2_IRQHandler. В нашем случае мы используем HAL, поэтому будем обрабатывать прерывание через HAL_TIM_PeriodElapsedCallback. Например, в этой функции мы будем зажигать и гасить зеленый светодиод на нашей отладочной плате:


HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef)
{
if(htim->Instance == TIM2)//Проверяем что TIM2
  {
  //Переключаем состояние светодиода
  HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);
  }
}

В результате наш диод моргает раз в секунду.

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

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