STM32的HAL库开发系列 - 延时

延时有几种实现的方法。

1是循环延时/NOP空语句延时。就是利用执行每行代码的时间进行延时。每个单片机都不同需要调试。

2是定时器中断延时。需要额外占用一个定时器。

3是用系统滴答计时器

/**
  * @brief			us延时
  * @param[in]		us
  */
#define TimebaseSource_is_SysTick 0
#if	(!TimebaseSource_is_SysTick)
	extern TIM_HandleTypeDef htim9;		// 当使用FreeRTOS, TimebaseSource为其他定时器时
	#define Timebase_htim htim9
	#define Delay_GetCurrentValueReg()	__HAL_TIM_GetCounter(&Timebase_htim)
	#define Delay_GetReloadReg()		__HAL_TIM_GetAutoreload(&Timebase_htim)
#else
	#define Delay_GetCurrentValueReg()	(SysTick->VAL)
	#define Delay_GetReloadReg()		(SysTick->LOAD)
#endif

static uint32_t fac_us = 0;
static uint32_t fac_ms = 0;

void Delay_us_init(void)
{
	#if	(!TimebaseSource_is_SysTick)
		fac_ms = 1000;					// 作为时基的计数器时钟频率在HAL_InitTick()中被设为了1KHz
		fac_us = fac_ms / 1000;
	#else
		fac_ms = SystemCoreClock / 1000;
		fac_us = fac_ms / 1000;
	#endif
}

void Delay_us(uint16_t us)
{
	/*** 定时器功能实现 ***/
	uint32_t ticks = us * fac_us;
	uint32_t reload = Delay_GetReloadReg();
    uint32_t told = Delay_GetCurrentValueReg();
    uint32_t tnow = 0;
    uint32_t tcnt = 0;
    while (1) {
        tnow = Delay_GetCurrentValueReg();
        if (tnow != told) {
            if (tnow < told) {
                tcnt += told - tnow;
            } else {
                tcnt += reload - tnow + told;
            }
            told = tnow;
            if (tcnt >= ticks) {
                break;
            }
        }
    }

	#ifdef Delay_Use_NOP
		/*** NOP空语句实现 ***/
		uint32_t delay = us * fac_us / 4;
		do {
			__NOP();
		}
		while (delay --);
	#endif
}