STM32的IWDG启用后无法软件关闭,必须在RLR设定周期内调用IWDG_ReloadCounter()喂狗,否则复位;需注意LSI频率偏差、预分频器限制、写使能前提及调试时的可控喂狗策略。

STM32 的 IWDG 不能靠软件“启动就完事”
硬件看门狗(IWDG)在 STM32 上一旦启用,就无法被软件关闭——这是设计铁律。很多初学者写完 IWDG_Enable() 就以为万事大吉,结果程序一跑起来就反复复位,根本进不了主循环。原因通常是:没喂狗,或喂狗太晚,或时钟配置错导致超时时间远短于预期。
关键点在于:IWDG 启动后,必须在 RLR(重装载寄存器)设定的周期内调用 IWDG_ReloadCounter(),否则计数器归零触发系统复位。这个周期由 LSI(约 32 kHz)和预分频器共同决定,典型值在毫秒到秒级,但极易算错。
- LSI 实际频率可能只有 28–35 kHz,别硬按 32 kHz 算;
- 预分频器只能选 4、8、16、32、64、128、256,不是任意值;
-
IWDG_WriteAccess_Enable(IWDG_WriteAccess_Enable)必须在配置前调用,否则写PR或RLR无效; - 复位后
IWDG仍保持使能状态(除非硬件复位或掉电),调试时容易误判为代码问题。
喂狗位置必须在“最坏路径”耗时内完成
喂狗不是越勤越好,而是要确保在任意执行路径下,两次 IWDG_ReloadCounter() 的间隔都小于超时时间。常见错误是只在主循环开头喂一次,但某次中断处理或外设等待(比如 while(!USART_GetFlagStatus(USART1, USART_FLAG_TC)))卡住超过超时阈值,立马复位。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 把喂狗放在主循环末尾(而非开头),确保本轮所有逻辑执行完再续命;
- 对长耗时操作拆解,例如 SPI 读取大数组时,每处理 100 字节喂一次狗;
- 避免在裸 delay 函数里喂狗(如
for(volatile int i=0; i),编译器优化可能删掉循环,导致实际延时不达标; - 如果用了 RTOS,不要只在 idle 任务喂狗——idle 可能被高优先级任务长期抢占,应在每个关键任务的合理间隙调用
IWDG_ReloadCounter()。
别用 HAL 库默认的 HAL_IWDG_Init() 直接上线
HAL 库的 HAL_IWDG_Init() 默认把超时设得极短(比如 16 ms),方便调试时快速暴露问题,但直接用于产品会极其脆弱。它底层调用的是 IWDG_SetPrescaler() 和 IWDG_SetReload(),而这两个函数的参数含义反直觉:
-
hiwdg->Init.Prescaler填IWDG_PRESCALER_32,对应 PR 寄存器值为0x02(不是 32); -
hiwdg->Init.Reload是 RLR 寄存器原始值(0–0xFFF),不是毫秒数; - 真实超时 = (RLR + 1) × (4 × 2^PR) / LSI_Freq,其中 LSI_Freq 千万别硬编码成 32000。
推荐做法:手算出目标超时(比如 2.5 s),反推 RLR 值,再用示波器或逻辑分析仪抓 IWDG_ReloadCounter() 调用间隔验证。例如 LSI 实测 31250 Hz,选 IWDG_PRESCALER_256(PR=7),则最大 RLR = floor(2.5 × 31250 / (4×128)) − 1 ≈ 1525,取 1500 更稳妥。
调试阶段必须禁用 IWDG 或加条件喂狗
用 ST-Link 调试时,IWDG 不会因 halt 模式暂停——它照常倒计时。这意味着单步调试几秒就复位,根本没法查问题。解决方法不是关掉看门狗,而是让它“可控”:
- 开发固件中用宏开关:#ifdef DEBUG_MODE,跳过
IWDG_Enable()或把超时设为 30 秒; - 更安全的做法是保留 IWDG,但在调试时通过某个 GPIO 或串口命令临时喂狗(比如收到 'W' 字符才调用
IWDG_ReloadCounter()); - 切勿依赖
__HAL_DBGMCU_FREEZE_IWDG()—— 它只在某些芯片上有效,且不保证所有调试场景都冻结成功; - 量产固件务必删除所有调试用喂狗逻辑,防止被意外触发绕过保护。
真正可靠的看门狗策略,不是让程序不出错,而是让出错后能自恢复。喂狗点的设计,本质上是在业务逻辑里埋设“心跳锚点”,这些锚点必须经得起最差时序考验——而不是写完 IWDG_Enable() 就觉得稳了。


















