《STM32 独立看门狗与窗口看门狗:喂狗时机算错为什么反而复位?从超时窗口到低功耗唤醒》
做 STM32 项目时,看门狗是最容易“好心办坏事”的外设:不开,程序跑飞没人管;开了,喂狗时机算错,板子反而隔几秒自己复位一次。更让人困惑的是,独立看门狗(IWDG)和窗口看门狗(WWDG)明明都是看门狗,喂早了、喂晚了的后果却完全相反。本文把两者的超时计算、喂狗窗口和低功耗下的注意事项一次讲清。
一、独立看门狗:只怕喂晚了,不怕喂早了。IWDG 由独立的低速时钟 LSI 驱动,即使主时钟停振、程序跑飞,它也能继续计数,这正是它能兜底的原因。它的超时时间由预分频系数 PR 和重装载值 RLR 决定,公式是:T = (4 × 2^PR × RLR) / f_LSI。以常见的 LSI 标称 32kHz 为例,取 PR=4(即 64 分频)、RLR=1000,超时约为 (4×16×1000)/32000 = 2 秒。实际工程里不能直接用 32kHz 这个标称值:LSI 的出厂偏差可达 ±5% 甚至更大,随温度还会漂移。如果按标称值把超时算得刚刚好,低温或高温下实际超时可能缩短,正常喂狗也会被误判为超时。稳妥的做法是按最坏情况留 30% 以上的余量,或者在量产前实测几块板子的 LSI 频率再定参数。IWDG 的喂狗只有一个要求:在计数器减到 0 之前写 0xAAAA 到键寄存器 KR。喂得早没有惩罚,所以主循环里每 500ms 喂一次、超时设 2 秒,是最常见的写法。需要注意的是,IWDG 一旦使能就无法用软件关闭,只能等复位;调试时如果在断点处停住,IWDG 依然在跑,单步调试会被反复复位打断。STM32 的 DBGMCU 提供了调试时冻结看门狗的选项,联调阶段记得打开,发布前再确认冻结配置不会被误带到量产固件里。
二、窗口看门狗:喂早了也会复位。WWDG 由 PCLK1 驱动,计数器从 0x7F 向下递减到 0x3F 时产生复位。它的特别之处在于有一个“窗口”:只有当计数器值小于窗口值 W、且大于 0x3F 时喂狗才有效。喂得太早,计数器还没进入窗口,同样触发复位。用公式表达,设预分频为 WDGTB、PCLK1 为 f_PCLK1,则从 0x7F 递减到某一值 N 的时间为:T(N) = 4096 × 2^WDGTB × (0x7F - N) / f_PCLK1。窗口的打开时刻对应 N=W,关闭时刻对应 N=0x3F。举例:PCLK1=36MHz,WDGTB=3(8 分频),W=0x5A,则窗口在约 19.4ms 后打开,在约 49.2ms 后关闭,合法喂狗区间只有中间约 30ms。喂狗任务必须落在这个区间里,既不能图省事在循环开头就喂,也不能被高优先级中断拖过关闭时刻。正因为有窗口,WWDG 能发现 IWDG 发现不了的一类故障:程序没有跑飞,只是在某个循环里转得太快、逻辑提前返回,导致喂狗过于频繁。窗口看门狗把“喂得太勤”也当成异常,这在电机控制、电源时序这类对执行节奏有要求的场合很有价值。代价是喂狗时机的 jitter 必须可控:如果喂狗任务会被不确定时长的中断或 DMA 回调打断,窗口就可能被错过,选 WWDG 之前要先评估最坏情况下的任务抖动。
三、代码:两种看门狗的最小可用写法。IWDG 的初始化与喂狗只有几行,关键是参数按实测 LSI 留余量:void IWDG_Init(void) { IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); IWDG_SetPrescaler(IWDG_Prescaler_64); IWDG_SetReload(1000); IWDG_ReloadCounter(); IWDG_Enable(); } void IWDG_Feed(void) { IWDG_ReloadCounter(); }。WWDG 则要算好窗口值,并把喂狗放在定时中断里,保证节奏稳定:void WWDG_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); WWDG_SetPrescaler(WWDG_Prescaler_8); WWDG_SetWindowValue(0x5A); WWDG_Enable(0x7F); WWDG_ClearFlag(); WWDG_EnableIT(); } void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM2, TIM_IT_Update); WWDG_SetCounter(0x7F); } }。一个常见坑是把 WWDG 的喂狗写进主循环:主循环周期受外设等待、打印输出影响,抖动常常超过窗口宽度,复位原因查半天才发现是喂早了。窗口看门狗的喂狗动作应当由定时器驱动,与主循环解耦;如果一定要在主循环喂,窗口值要放得足够宽,并用最坏情况的循环周期去验算。
四、低功耗与复位原因:两个容易漏的细节。进入 STOP 模式时,IWDG 依赖的 LSI 仍然运行,停在低功耗里的等待时间也要计入喂狗周期;如果 STOP 的时间本身就超过 IWDG 超时,醒来第一件事就是复位。处理办法有三种:唤醒前由 RTC 定时唤醒起来喂一次狗;把超时设得比最长睡眠还长;或者在确实不需要看门狗的深度睡眠场景改用 WWDG(它随 PCLK1 停止而停止),但这意味着睡眠期间失去保护,要按产品风险权衡,不可无脑照搬。复位后要第一时间读 RCC 的复位标志寄存器 CSR:IWDGRSTF 置位说明是独立看门狗复位,WWDGRSTF 置位说明是窗口看门狗复位。很多现场问题查不下去,就是因为复位原因没有记录,重启后直接清标志,等于把唯一的线索擦掉了。建议在启动早期把复位原因存到备份寄存器或通过串口打印出来,再清标志;看门狗复位次数本身也是产品健康度的重要指标,量产固件应当统计并上报,而不是默默重启了事。
五、选型建议。只要求“跑飞必复位”,选 IWDG,喂狗周期取超时的一半以下,留足 LSI 偏差余量;要求“节奏异常也要复位”,选 WWDG,用定时器喂狗并按最坏抖动验算窗口;两者也可以同时开,IWDG 兜底、WWDG 把关节奏,但要注意复位原因的区分与调试冻结配置。看门狗不是加上就万事大吉,喂狗时机本身就是系统时序设计的一部分,算清窗口、留足余量、记下复位原因,才算真正把它用好。
- 点赞
- 收藏
- 关注作者
评论(0)