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

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