我们在使用STM32F系列芯片编写程序中,经常会使用HAL库开发,它把所有我们关心的硬件都封装成了API,调调API就可以,使用方便。
比如HAL_Delay,经常用来延时一段时间。
HAL_Delay有几个注意事项,不知道你平时开发中有没有注意到。
HAL_Delay(1000)是延时1秒吗
假设我们配置的tick为1ms,那么HAL_Delay(1000)是延时1000ms吗?
其实不是延时1000ms。
实际延时是1001ms。
我们看下代码
typedef enum{ HAL_TICK_FREQ_10HZ = 100U, HAL_TICK_FREQ_100HZ = 10U, HAL_TICK_FREQ_1KHZ = 1U, HAL_TICK_FREQ_DEFAULT = HAL_TICK_FREQ_1KHZ} HAL_TickFreqTypeDef; HAL_TickFreqTypeDef uwTickFreq = HAL_TICK_FREQ_DEFAULT; /* 1KHz */ __weak void HAL_Delay(uint32_t Delay){ uint32_t tickstart = HAL_GetTick(); uint32_t wait = Delay; /* Add a freq to guarantee minimum wait */ if (wait < HAL_MAX_DELAY) { wait += (uint32_t)(uwTickFreq); } while ((HAL_GetTick() - tickstart) < wait) { }}
注意第21行,wait =Delay+uwTickFreq
这个条件绝大多数情况下是成立的,也就是这里多加了一个1。
因此我们传入1000,实际延时是1001。
HAL_GetTick() - tickstart) < wait会溢出吗
不会
它执行的是差模运算
假设 tickstart 是 0xFFFFFF00,然后系统继续运行了一段时间,HAL_GetTick() 达到 0x00000050,此时它发生了溢出,变为 0x00000050。
此时差值应该是:
0xFFFFFFFF-0xFFFFFF00+0x00000050+1=0x150
差模运算也是0x150:
0x00000050-0xFFFFFF00=0x150
可以在中断中调用HAL_GetTick吗
HAL_GetTick()是一种阻塞式延时,不建议在其他中断函数中使用。
中断处理一般都是要求快进快出,不能阻塞太久,这是原因之一。
HAL_GetTick()使用的systick中断通常是优先级最低的一类中断,一般是给RTOS调度做时基使用的。
如果在其他中断服务函数中调用这个函数的话,就会导致中断函数一直在等待Delay中的死循环结束。
但是由于Delay的优先级不够,因此出现了一种高优先级任务等待低优先级任务的情况。这种现象被称作优先级翻转。这是原因之二。
如果实在需要调用,建议用其他硬件timer作为定时器的时基,并提高其中断优先级
好了,今天的笔记就分享到这,谢谢大家!