一、实现原理
以下代码摘自cubeMX自动生成的部分
/*stm32f1xx_it.c*/
//sysTick中断函数
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
/* USER CODE END SysTick_IRQn 0 */
HAL_IncTick();
/* USER CODE BEGIN SysTick_IRQn 1 */
/* USER CODE END SysTick_IRQn 1 */
}
/*stm32f1xx_hal.c*/
//SysTick 初始化函数 (HAL_Init()调用此函数)
__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
/* Configure the SysTick to have interrupt in 1ms time basis*/
if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) > 0U)
{
return HAL_ERROR;
}
/* Configure the SysTick IRQ priority */
if (TickPriority < (1UL << __NVIC_PRIO_BITS))
{
HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);//设置中断
uwTickPrio = TickPriority;
}
else
{
return HAL_ERROR;
}
/* Return function status */
return HAL_OK;
}
//中断函数会调用一次改函数,将uwTick增1
__weak void HAL_IncTick(void)
{
uwTick += uwTickFreq;
}
//获取uwTick值
__weak uint32_t HAL_GetTick(void)
{
return uwTick;
}
//本次讨论的主角,ms延时函数
__weak void HAL_Delay(uint32_t Delay)
{
uint32_t tickstart = HAL_GetTick();//先记录当前uwTick值
uint32_t wait = Delay;
/* Add a freq to guarantee minimum wait */
if (wait < HAL_MAX_DELAY) //HAL_MAX_DELAY为0xffffffff,一般这条不会有问题
{
wait += (uint32_t)(uwTickFreq); //uwTickFreq一般定义为0x01
}
//由于systick中断会不断修改uwTick值,所以在uwTick值比刚开始记录的uwTick值大到wait值也就是ms值就会跳出whlie循环,然后返回
while ((HAL_GetTick() - tickstart) < wait)
{
}
}
二、输入参数限制
如果对uwTickFreq有改动,则需要注意。下面默认uwTickFreq未改动,且值是1。
在引入下面的问题之前,在合理的判断下可以输入的值应该是(0xffffffff - 当前uwTick)。那么,如果当uwTick即将计至最大值时,HAL_Delay()还可以继续使用吗?带着这个问题,我简单的做了一个实验。
三、有效期问题
无符号32位整数数值最大值为0xffffffff 十进制是4294967295,从0ms计至4294967295ms需要4294967.295 s,1193小时,也就是49天多。为了实验验证有效期问题,在这49天之后,uwTick会重新从0开始计数,如果在之前调用了HAL_Delay(),则tickstart 是一个接近最大值的值,而此后uwTick再与tickstart 进行比较时是否一直都是小于wait值呢?会不会因此进入一个无限循环呢?
下面做一个实验:
uint32_t testn;
uint32_t tickss;//用于debug时查看uwTick的值
testn=0xfffffffe;//模拟uwTick值已经计至末端
tickss=0;
while ((tickss - testn) < 100)//延时100ms
{
tickss = HAL_GetTick();
}
实验后发现,tickss值为98时,会退出while循环。 意味着 (tickss - testn) 也就是(0x62 - 0xfffffffe)小于 100 不成立。
这是为什么呢?
用计算器算一遍(PC 是64位,所以减去 0xffff ffff ffff fffe):
也就是说,相减以后,内存中还是以无符号32位数值进行存储,数值为100。
其实熟悉无符号整数存储机制,可想而知。
由此可见 HAL_Delay()可以永久使用。