STM32HAL库中的HAL_Delay()函数实现原理分析
很多初学者只是学会使用HAL_Delay()函数,但却不明白这个函数实现延时的机理,其实它本质山是利用了SysTick定时器来实现延时的,很多人后来不在使用这个函数,又是因为神马原因呢?请听我娓娓道来。
首先你要知道定时器和中断的概念:
定时器
定时器就相当于一个计数器的功能,STM32定时器分为基本定时器,通用定时器,高级定时器。
具体介绍可以参考
SysTick定时器:简单理解来说,SysTick和通用定时器没有太大的区别,它是一个24位向下计数的定时器,而且属于内核外设。
中断
简单理解来说,当发生某个事件时且中断使能,程序会立即跳入到中断服务函数中去执行特定的程序之后,执行完毕后再回到原来的位置继续执行。
HAL_Delay()函数的实现就是利用了SysTick定时器的更新中断。更新中断就是SysTick计数到0后产生的中断。
下面根据具体代码来看它的实现原理:
找到函数原型如下图,这是个弱函数,看来作者似乎已经默认了它的缺点,允许我们自定义一个延时函数。这个函数中又调用了一个 HAL_GetTick()函数,并把它的返回值赋给变量 tickstart ,然后把函数的形参(Delay即延时的毫秒数)赋给变量 wait。
接着if语句的判断wait的值是否小于HAL_MAX_DELAY(它宏定义值为 0xFFFFFFFF),
实际上,我们传入的Delay要保证小于它。进入if语句中,wait自增1。
然后进入while循环中,while循环执行的时间即为延时的时间。我们先看一下HAL_GetTick()函数的原型。
它就返回uwTick的值。我们uwTick,发现它在这个函数中实现了每次自增1:
这个函数是不是似曾相识,没错,它是固定放在SysTick_Handler()函数中的,即SysTick中断服务函数,也就是说每进行一次中断,执行一次该函数,uwTick自增1.
我们回到HAL_Delay()函数原型,进入到该函数,首先获取(通过HAL_GetTick())uwTick的值并且赋给变量tickstart,延时的时间(毫秒数)通过形参赋给wait,wait在if语句自增1后;进入while循环,此时只有HAL_GetTick()-tickstart>=wait才能跳出循环,即变量uwTick增加量等于wait时,延时结束。uwTick在SysTick中断每次自增一。即延时的时间等于:(SysTick中断周期)*(wait-1),即(SysTick中断周期)*Delay。实际上,SysTick中断周期默认配置为1ms。从而实现毫秒延时效果。
值得注意的是,由于HAL_Delay()函数是阻塞的,所以要慎用。