1. 为什么HAL_Delay()在中断中会卡死?
这个问题困扰过很多STM32开发者,我自己也踩过这个坑。记得有一次在做一个电机控制项目,我在定时器中断里加了个HAL_Delay(100)想让LED闪烁指示状态,结果整个系统直接卡死,电机停转,吓得我赶紧断电检查。
根本原因在于中断优先级冲突。HAL_Delay()的实现原理很简单:它依赖一个叫做uwTick的全局变量,这个变量每毫秒在SysTick中断里自增1。当你调用HAL_Delay(100)时,程序会记录当前的uwTick值,然后死循环检查是否过去了100个滴答。
// HAL_Delay的核心代码
while ((HAL_GetTick() - tickstart) < wait) {
// 在这里死等
}
问题就出在这里:如果你的中断优先级比SysTick高(数字更小),那么在这个中断执行期间,SysTick中断根本无法触发,uwTick的值永远不会增加,HAL_Delay()就永远等不到它想要的那个时间点,整个程序就卡死在这个while循环里了。
2. SysTick的工作原理深度解析
要彻底理解这个问题,我们需要深入看看SysTick定时器是怎么工作的。SysTick是Cortex-M内核自带的24位递减计数器,不是STM32外设,所以所有Cortex-M芯片都有这个定时器。
SysTick的四个核心寄存器:
| 寄存器 | 功能 | 位宽 |
|---|---|---|
| CTRL | 控制状态寄存器 | 32位 |
| LOAD | 重装载值寄存器 | 24位 |
| VAL | 当前值寄存器 | 24位 |
| CALIB | 校准值寄存器 | 32位 |
以STM32F103为例,如果系统时钟是72MHz,想要1ms中断一次,需要这样计算:
重装载值 = 系统时钟频率 / 分频系数 / 期望频率 - 1
= 72,000,000 / 1 / 1000 - 1
= 71999
在HAL库中,这个配置是通过HAL_Init()函数完成的:
HAL_StatusTypeDef


1408

被折叠的 条评论
为什么被折叠?



