由于 HAL_Delay() 是依靠嘀嗒定时器(sysTick)的中断实现的,这个中断优先级默认为最低,所以如果调用了其它中断,就会导致嘀嗒定时器的中断程序无法进入,从而导致 HAL_Delay() 失灵。
下面是详细解释:
HAL_Delay() 实现原理
HAL_Delay() 定义:
HAL_Delay 通过 HAL_GetTick() 获取嘀嗒定时器的值,当 HAL_GetTick() 返回的值超过 Delay 的值的时候,退出当前函数。
下面看 HAL_GetTick() 的定义:
可以看见它返回变量 uwTick 的值,全局查找 uwTick,可以找到下列函数:
可以看到,每次调用这个函数 HAL_IncTick,uwTick 的值就会增加 uwTickFreq。
继续往下找,可以找到是谁调用了这个函数 HAL_IncTick:
这个 SysTick_Handler 是系统嘀嗒定时器的中断函数。系统嘀嗒定时器和普通定时器差不多,一定时间(用户设定)后就会产生中断(如果使能了嘀嗒定时器中断)。
讲到这里,可以总结 HAL_Delay 函数的实现原理:uwTick 每隔一段时间就会增加,通过读取 uwTick 的值保存,过一段时间再读取 uwTick 的值,两次读取的时间相减,就可以知道过去了多长时间。这段时间与用户设定的值(Delay)比较,如果大于就退出 HAL_Delay 函数,从而实现延迟。
出错原因
嘀嗒定时器的中断也受 NVIC 管理,也有优先级,而通过 keil 调试我们可以看到:
嘀嗒定时器(System Tick Timer)的中断优先级设置为 15,优先级非常低,所以在其他中断(例如串口接收中断)运行时,不会进入嘀嗒定时器的中断,导致 uwTick 无法更新,那么 HAL_Delay() 自然无法工作。