Top.Mail.Ru

Простейшая организация микросекундной задержки для STM32.

Приветствую, начнем новый год с завершения дел прошлогодних, а именно, с данной форумной темы. В двух словах суть такова - HAL'овая HAL_Delay(), которая в подавляющем большинстве случаев используется для осуществления задержек, дает возможность оперировать интервалами, кратными 1 мс. Чего зачастую бывает недостаточно, поэтому рассмотрим простейшую реализацию микросекундного варианта. Вообще я бы лично использовал скорее модуль DWT для этого, но сегодня разберем вариант с выделением под эту задачу одного из таймеров, поскольку именно о таком попросили.

Создаем проект и инициализируем в STM32CubeMx как обычно:

  • тактирование и отладку:
Настройки проекта в STM32CubeMx
  • тот самый таймер, пусть будет TIM4, разницы существенной нет:
  • настраиваем частоты, у меня внешний кварц 8 МГц на плате:
Настройка тактирования.

Пройдем чуть подробнее. Контроллер я взял тот же, что и у автора темы на форуме - STM32F103C8. Опять же - разницы никакой нет, все элементарно адаптируется под другой чип/семейство/таймер и т. д. TIM4 находится на шине APB1, в данном случае для таймеров имеем частоту - 72 МГц. Значение предделителя, равное 71, дает итоговую величину (71 + 1 = 72), что, в свою очередь, задает частоту таймера, равной:

f_{T} = 72 \medspace МГц \medspace / \medspace 72 = 1 \medspace МГц

То есть один "тик" таймера соответствует 1 мкс. Период таймера, то есть величину, при которой произойдет переполнение, задаем максимально возможной - 65535. Практической ценности в данном проекте она в себе не несет.

Итак, переходим к сути. Работать механизм будет следующим образом:

void usDelay(uint16_t useconds)
{
  __HAL_TIM_SET_COUNTER(&htim4, 0);
  while(__HAL_TIM_GET_COUNTER(&htim4) < useconds);
}

Обнуляем значение счетного регистра таймера (TIM4->CNT), а затем в цикле просто ожидаем, когда его величина станет равной значению useconds, переданному в функцию в качестве аргумента. Что и даст требуемый результат. Макросы __HAL_TIM_SET_COUNTER() и __HAL_TIM_GET_COUNTER(), соответственно, устанавливают значение регистра CNT и возвращают его текущую величину. Не забываем предварительно запустить таймер при помощи HAL_TIM_Base_Start():

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM4_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start(&htim4);

/* USER CODE END 2 */

В проекте я добавил инициализацию PA4 в качестве выхода, так что подергаем выводом, задавая разные значения задержки для проверки:

while (1)
{
	/* USER CODE END WHILE */

	/* USER CODE BEGIN 3 */
	HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_4);
	usDelay(delayValue);
}
/* USER CODE END 3 */

Переменная delayValue определена все в этом же файле main.c:

/* USER CODE BEGIN PV */
uint16_t delayValue = 125;

/* USER CODE END PV */

В итоге получаем:

STM32, микросекундная задержка.

Благодаря дельному замечанию в группе ВК 👍,