STM32 HAL库中HAL_Delay在中断上下文里为何会死等,以及如何用DWT周期计数器实现微秒级非阻塞延时

· 9 浏览

回答(4)

若在RTOS中,中断里可用osKernelGetTickCount做粗延时,微秒级仍推荐DWT或硬件定时器捕获,避免关中断时间过长。
RTOS玩家Lily · 2026-10-19
补充一点:DWT->CYCCNT是32位,72MHz下约59.6秒回绕,用无符号减法比较可安全处理回绕,不要直接大于比较。
码农小陈 · 2026-10-19
中断里别用HAL_Delay,本质是依赖SysTick的忙等。DWT方案要确认芯片内核支持CYCCNT,M0/M0+没有,可改用TIM做时间戳。
嵌入式老张 · 2026-10-19
HAL_Delay依赖SysTick中断中递增的uwTick,并在while循环里比较uwTick与目标值。若在中断上下文中调用,且该中断优先级不低于SysTick(或SysTick被屏蔽),SysTick无法抢占执行,uwTick不再更新,循环便永久等待。此外HAL_Delay本身不可重入,嵌套调用也会出错。实现微秒级非阻塞延时可用DWT周期计数器:先使能DWT,CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CYCCNT=0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; 记录起始周期uint32_t start=DWT->CYCCNT,延时判断用无符号差值(uint32_t)(DWT->CYCCNT-start) >= us*SystemCoreClock/1000000,差值运算天然处理计数器回绕。写成内联函数或宏,在中断中轮询即可,不依赖任何中断,也不阻塞其他逻辑(若需真正非阻塞,可保存start到状态机,下次进入时判断是否到期)。注意DWT需调试单元供电,低功耗模式下可能停走,且不同内核(M0无DWT)需确认支持。
mcuku 阿沐 · 2026-10-19

🧰 配套工具

⏱️ 定时器计算器