Программирование счетчиков и прерываний процессора

Электроника

В этом разделе мы изучим счетчики и прерывания. Нашей целью будет создание синхронизированного события, для того чтобы поморгать светодиодами и отправить сообщения в компьютер
Глоссарий
Для успешного освоения материала рекомендуем вам изучить следующие понятия:
Таймер
(от англ. Timer) — в информатике — средство обеспечения задержек и измерения времени средствами компьютера. Существуют два вида таймеров:

  • аппаратные таймеры функционируют независимо от центрального процессора и в момент срабатывания генерируют прерывание
  • программные таймеры реализуются за счет выполнения в цикле заданного количества одинаковых «пустых» операций. При фиксированной частоте работы процессора это позволяет точно определять прошедшее время
Прерывание
(англ. interrupt) — сигнал от программного или аппаратного обеспечения, сообщающий процессору о наступлении какого-либо события, требующего немедленного внимания. Прерывание извещает процессор о наступлении высокоприоритетного события, требующего прерывания текущего кода, выполняемого процессором
Сторожевой таймер, реже контрольный таймер
(англ. watchdog timer букв. «сторожевой пес») — аппаратно реализованная схема контроля над зависанием системы. Представляет собой таймер, который периодически сбрасывается контролируемой системой. Если сброса не произошло в течение некоторого интервала времени, происходит принудительная перезагрузка системы
Видеолекция
Конспект

Необходимые комплектующие
  • Часто используют таймер-счетчики, которые тактируются от внешних кварцевых резонаторов
  • Микроконтроллер stm32 внутри имеет специальный тактовый генератор, который не использует внешний кварцевый резонатор
Этапы задачи
  1. Моргать светодиодами (500 миллисекунд включено, 500 миллисекунд выключено)
  2. Каждые 5 секунд посылать сообщения в компьютер
Решение
Самый простой способ — это использовать функцию, которая задерживает выполнение кода в определенном месте.

  • Поставим функцию в главный цикл программы
  • После функции поставим вызовы, которые меняют состояние микроконтроллера
  • Получим периодическое изменение состояния микроконтроллера
Важно
Недостатки функции: если мы поставим очень большой код, то точность периода будет незначительной. При этом, если мы запустим разные режимы оптимизации кода, периодическая задержка будет практически невычислимая
Таймер-счетчики

Таймер-счетчики — это специальные аппаратные регистры внутри микроконтроллера.

  • Они изменяют свое состояние (либо увеличивают, либо уменьшают) по определенному такту самого микроконтроллера
  • При достижении определенных значений регистра вызывается прерывание. Оно останавливает общий цикл программы и вызывает функции, которые мы в него вставим
Алгоритм
1. Настраиваем таймер-счетчик в микроконтроллере на поступление событий в 1 миллисекунду

2. Используем программные счетчики для того, чтобы формировать события с периодами большими, чем 1 миллисекунда

3. Инициализируем счетчики для периодов в 500 мс (для светодиодов) и 5 с (для отправки данных на компьютер)

4. Устанавливаем флаги. Сбрасываем событие «раз в 500 мс» и «раз в 5 с»

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

2. В файле main.c в главном цикле программы закомментируем код от предыдущего проекта (работа с UART)

3. Настраиваем таймер
Categories → Timers → TIM1
4. Устанавливаем для него тактирование от внутреннего 80 МГц таймера

5. В параметрах устанавливаем Prescaler (PSC — 16 bits value) 999 и Counter Period 79
6. Выставляем галочку update interrupt, чтобы прерывание формировалось по переполнению таймера
7. Переходим System Core → NVIC

8. Настраиваем приоритеты прерывания
9. Сохраняем и переходим к написанию кода в программе
Написание кода
1. Для запуска таймера в работу вызываем метод
HAL_TIM_Base_Start_IT(&htim1), где htim1 — наш таймер

2. Находим, где располагаются обработчики прерываний
Core → Src → stm32l4xx_it.c

3. Находим вызов для таймера
4. Вызываем HAL_TIM_IRQHardler (&htim1) и переходим в его определение

5. Открываем Src → stm32l4xx_hal_tim.c и в поиске находим этот вызов

6. Указываем большее количество символов для поиска в текстовом редакторе
7. В файле stm32l4xx_hal_tim.c находим вызов HAL_TIM_IRQHardler (&htim1). Находим вызов по переполнению и переходим в его определение
8. Копируем заголовок метода и в файле main.c его вставляем

9. Заполняем тело нашего обработчика прерывания по переполнению
#define HTIM1_EVENT_500ms 500
volatile int32_t htim1_event_500ms_count = HTIM1_EVENT_500ms; //счетчик тиков таймера для полуения события раз в 500 мс
volatile uint8_t event_500ms_flag = 0; //флаг события - изначально событие не установленно

#define HTIM1_EVENT_5s 5000
volatile int32_t htim1_event_5s_count = HTIM1_EVENT_5s; //счетчик тиков таймера для полуения события раз в 5 с
volatile uint8_t event_5s_flag = 0; //флаг события - изначально событие не установленно

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM1)
	{//прерывание из таймера TIM1 - настроен на обновление раз в 1 мс


		//генерируем событие на 500 мс
		htim1_event_500ms_count--; //уменьшаем счетчик для события
		if(htim1_event_500ms_count==0)
		{//счетчик достиг конуа - генерим событие
			htim1_event_500ms_count = HTIM1_EVENT_500ms; //установим счетчик в изначальное состояние
			event_500ms_flag = 1; //установим флаг события

			//запуск действий по событию
			//здесь должно быть "легкое действие", без затрагивания сложных модулей микроконтроллера
			//мигание светодиодами
			HAL_GPIO_TogglePin(GPIOB, LED5_Pin|LED4_Pin|LED3_Pin);
			HAL_GPIO_TogglePin(GPIOA, LED2_Pin|LED1_Pin);


			event_500ms_flag = 0; //сбросим флаг события - отработали
		}

10. Аналогично сделаем обработку события «раз на 5 с»
		//генерируем событие на 5 секунд
		htim1_event_5s_count--; //уменьшаем счетчик для события
		if(htim1_event_5s_count==0)
		{//счетчик достиг конуа - генерим событие
			htim1_event_5s_count = HTIM1_EVENT_5s; //установим счетчик в изначальное состояние
			event_5s_flag = 1; //установим флаг события
			//этот флаг пойдет для "тяжелого" действия - отправки данных через UART
		}

	}

}
11. Заполняем обработку события в главном цикле программы
while (1)
  {

	  if(event_5s_flag==1)
	 	  { //наступило событие для тяжелой обработки - передачи в UART
	 		  sprintf(str_out, "time event\r\n");  //строка послыки
	 		  Size_out = strlen(str_out);       	//размер строки
	 		  HAL_UART_Transmit(&huart2, str_out, Size_out, 10); //посылаем ответ в компьютер

	 		  event_5s_flag=0; //сбросим флаг - обработали событие
	 	  }
  }
12. Сохраняем, компилируем, проверяем
Тестирование
1. Запускаем терминал

2. Устанавливаем параметры com порта
3. В поле приема каждые пять секунд появляется сообщение

4. Проконтролируем моргание светодиодов

5. Подключаем щуп осциллографа к одному из анодов светодиодов и на осциллографе, смотрим импульсы, которые поступают на аноды. Включение и выключение происходит по 500 мс
Важно
По окончании работы сначала отсоединяем щупы, потом блок питания и только потом программатор от компьютера
Мы изучили новые модули микроконтроллера и написали код программы для синхронизации моргания светодиодов и отправки данных с этими модулями. Давайте проверим, все ли вы запомнили.
Интерактивное задание
Тест
Для закрепления полученных знаний пройдите тест
Стартуем!
Что такое таймер-счетчики?
Дальше
Проверить
Узнать результат
Какие числа устанавливаются в параметрах Prescaler (PSC — 16 bits value) и Counter Period при настройке таймера? Частота тактирования 80 МГц, периодичность прерывания таймера 1 мс
Дальше
Проверить
Узнать результат
Что обозначает htim1 в методе HAL_TIM_Base_Start_IT (&htim1) при настройке запуска таймера в работу?
Дальше
Проверить
Узнать результат
Выберите нужную последовательность отключения устройств по окончанию работы:
Дальше
Проверить
Узнать результат
К сожалению, вы ответили неправильно
Прочитайте лекцию и посмотрите видео еще раз
Пройти еще раз
Неплохо!
Но можно лучше. Прочитайте лекцию и посмотрите видео еще раз
Пройти еще раз
Отлично!
Вы отлично справились. Теперь можете ознакомиться с другими компетенциями
Пройти еще раз