STM32 独立看门狗 IWDG 实战:系统跑飞,它来兜底复位

我早年做个现场采集节点,架在客户厂房顶上,靠 4G 回传数据。程序偶尔会跑飞------要么是某个指针越界进了死循环,要么是外设异常卡在某个奇怪的状态,反正现象就是:串口不回、LED 不闪、网也连不上。板子没死机,是"假死",电源灯还亮着,就是啥都不干。现场在郊区,派人去一趟差旅几千块。后来我加了 IWDG,跑飞就自动复位,问题从"派个人去拔电"变成了"偶尔自己重启一下就好了",客户群里再没人@我。

很多 STM32 项目把采样链路、低功耗、参数保存都搞定了,但有个前提------程序一直在正常跑。可现场电磁干扰、偶发指针错、看门狗没装,系统就可能假死。IWDG 就是最后一道兜底的网:你跑飞了没关系,我帮你重启。

一、看门狗到底是个啥

一句话:一个递减计数器,从重载值往下数,数到 0 就拉复位。你必须在它数到 0 之前"喂狗"(重装计数),证明"我还活着"。没喂 → 超时 → 芯片硬复位。

STM32 有两只狗,别搞混:

  • IWDG(独立看门狗) :由独立的低速时钟 LSI (约 40kHz 内部 RC)驱动,跟主时钟 HSE/PLL 完全脱钩。主时钟挂了、PLL 崩了,它照样数。喂狗窗口是整个周期 (只要在超时前喂就行)。它的使命就是"系统都快散架了,我还能把你拽起来复位"。一旦启动,软件关不掉,只能靠复位清------这个关不掉恰恰是安全点:防止程序自己把狗关了躲复位。
  • WWDG(窗口看门狗) :由 PCLK(主时钟分频)驱动,有喂狗窗口(太早喂、太晚喂都复位),能看"程序跑太快或太慢"的逻辑时序错误。但它依赖主时钟,主时钟没了它不工作。适合抓软件逻辑 bug,不适合当"系统垮了兜底"。

这篇专讲 IWDG------给现场节点装最后一道保险。你要的是"崩溃自动爬起来",不是"逻辑时序卡点",IWDG 正合适。

二、CubeMX 怎么配

1. IWDG 外设 → Activate IWDG 勾上

2. 设 Prescaler(分频)和 Counter Reload(重载值)

超时时间由这俩决定:

复制代码
T_out ≈ (Prescaler × Reload) / LSI_freq

LSI 标称 40kHz。比如 Prescaler=64Reload=1000

T_out ≈ 64 × 1000 / 40000 = 1.6 秒

Reload 范围 0~4095,分频有 4/8/16/32/64/128/256 档。想看几秒,调这俩就行。

3. LSI 时钟

IWDG 依赖 LSI,CubeMX 在 RCC 里会自动把 LSI 打开,你不用手操。但知道它存在------后面讲 LSI 漂移的坑。

4. 调试冻结(关键,可选但强烈建议)

调试时看门狗会一直数,ST-Link 下断点一暂停 CPU,狗照样跑,一断点就复位,根本没法调。代码里加一句 __HAL_DBGMCU_FREEZE_IWDG(),调试暂停时冻结看门狗;或者调试阶段临时注释掉 MX_IWDG_Init()。发布时再打开。

三、最少的代码

使能在初始化里一次搞定,喂狗放在主循环"正常能跑到"的末尾。

c 复制代码
IWDG_HandleTypeDef hiwdg;

void MX_IWDG_Init(void) {
    hiwdg.Instance = IWDG;
    hiwdg.Init.Prescaler = IWDG_PRESCALER_64;  // 64 分频
    hiwdg.Init.Reload    = 1000;               // 重载值 1000
    // 超时 ≈ 64*1000/40000 = 1.6s (LSI=40kHz)
    HAL_IWDG_Init(&hiwdg);    // 一旦启动, 软件关不掉, 只能复位清
    __HAL_DBGMCU_FREEZE_IWDG(); // 调试暂停时冻结, 方便下断点
}

int main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_IWDG_Init();            // 看门狗启动

    while (1) {
        do_real_work();        // 真正干活(采样/上报/处理)
        HAL_IWDG_Refresh(&hiwdg);  // 正常跑到这里才喂, 证明整套系统还活着
    }
}

这段在干嘛:初始化把看门狗拉起来,之后主循环每转一圈,干完活就在末尾 HAL_IWDG_Refresh(往 KR 写 0xAAAA 重装计数器)。只要 do_real_work 能正常返回,狗就被喂到,系统稳住;哪天 do_real_work 卡死回不来,计数器数到 0,芯片硬复位,IWDG 完成兜底。

★ 关键认知:喂狗的位置 = "系统活着"的证词。你喂在哪儿,就证明"程序能跑到哪儿"。喂在末尾,证明整圈主循环都健康;喂在中间,证明只到一半。位置选错,狗就形同虚设。

四、真正会坑你的几个点

1. 在中断里喂狗,主循环假死狗不叫。 ★ 最高频也最隐蔽的坑。有人图省事在定时器中断里 HAL_IWDG_Refresh,结果主循环 while(1) 卡死、啥也不干,中断还在跑,狗照样被喂,系统假死一整天没人发现。喂狗只能放在主循环能正常轮转到的最后一步,主循环卡住就喂不到,狗才叫得出来。

2. 超时时间设太短,正常任务也被咬死。 你算着主循环 200ms 一圈,把狗设成 1 秒,觉得绰绰有余。结果某次 Flash 擦除(一页擦几十毫秒)叠加一次大批量 DMA,单次任务偶发跑 2 秒,狗 1 秒就复位,正常活儿也被打断。超时 = (分频×重载)/LSI,留足最大单次任务耗时的余量,别卡太紧。

3. LSI 精度差,温度电压一漂就误复位。 LSI 是内部 RC,标称 40kHz,实际可能 ±10%~±20%,还随温度电压漂。你按 40kHz 算 1.6 秒,低温下可能 1.3 秒就到点。超时窗口别算得太临界,留 30% 以上裕量,否则冬天户外偶发误复位,查半年查不出。

4. 调试下断点被狗复位,根本调不了。 不配 DBGMCU 冻结,ST-Link 一暂停 CPU,IWDG 还在数,断点没下完狗就咬了,程序反复复位,你连单步都进不去。调试阶段 __HAL_DBGMCU_FREEZE_IWDG() 或临时注释 MX_IWDG_Init,发布前恢复。

5. 忘了使能就以为有保护。 CubeMX 没勾 Activate、或代码里忘了调 HAL_IWDG_Init,你以为装了狗,其实压根没启动,跑飞照样不复位。初始化后读一下 IWDG->SR 或接个 LED 在使能后闪一下,确认它真启动了。

6. 主循环里死等阻塞,喂狗在后面够不着。 比如 while(!data_ready); 等一个永远不来的事件,或者等串口回应不设超时,卡在这,循环末尾的喂狗永远执行不到------这时候狗倒是会叫,但你本意不是卡在这被复位,是这段等待本身有 bug。所有等待加超时退出,别死等。

7. 把喂狗写进可能被跳过的分支。 有人把 HAL_IWDG_Refresh 放进某个 if 里,正常走这个分支才喂,异常走了另一条路就不喂。结果异常路径越走越偏,狗沉默。喂狗要在主循环主干、无条件执行的位置,不在条件分支里。

8. 裸写 KR 寄存器键顺序错。 不用 HAL 手操 IWDG 时,KR 的键有讲究:0x5555 解锁(才能改 PR/RLR)、0xAAAA 喂狗、0xCCCC 启动。顺序错、键写错,要么改不了参数,要么误触发启动。HAL 帮你封装好了,裸写时一定对着参考手册的键序来。

9. 低功耗 Stop 下狗还在跑,睡太久被从梦里咬醒。 ★ 低功耗场景的坑。你进 Stop 睡 2 秒(µA 级),IWDG 1.6 秒超时照常数,醒来前狗就把你复位了,等于没睡、还反复重启。Stop 节点要在每次唤醒主循环里 Refresh ,且 Stop 时长必须 小于看门狗超时;用 RTC 周期唤醒保证按时回来喂狗。别指望 Stop 里狗会停------IWDG 由 LSI 驱动,Stop 模式下 LSI 还在跑,狗一秒都不歇。

10. 用了狗却不查"为什么复位"。 复位后不读复位标志,分不清是上电、还是狗咬的、还是欠压。复位一上来读 RCC->CSR 里的 IWDGRSTF 位:置位说明是看门狗咬的,记下、上报、再去查是哪段卡死。否则每次都当普通上电,问题永远埋着,下次还咬。

五、完整例程骨架

把"使能、主循环末喂狗、复位后查标志"串起来;Stop 节点在唤醒路径里也补一脚喂狗。

c 复制代码
int main(void) {
    HAL_Init(); SystemClock_Config(); MX_GPIO_Init();
    MX_IWDG_Init();   // 看门狗启动

    // 复位后查: 是不是看门狗咬的?
    if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)) {
        __HAL_RCC_CLEAR_RESET_FLAGS();
        log_event("reset by IWDG");   // 记下, 排查哪段卡死
    }

    while (1) {
        do_real_work();               // 干活
        HAL_IWDG_Refresh(&hiwdg);     // 主干无条件喂狗, 证明活着
        // 若是 Stop 节点: 进 Stop 前确认睡的时间 < 看门狗超时
        // enter_stop();  // 唤醒回来第一件事接着 Refresh
    }
}

看门狗的本质不是"让系统不崩",是"崩了能自己爬起来"------它不治病,只防止病入膏肓还硬撑。给你的现场节点都装上,再把"复位后查标志"接上日志,绝大多数"假死"就从紧急工单变成了一条无人察觉的自愈记录。

适合:任何无人值守、现场部署、怕假死的节点(工业采集、户外传感器、网关)------给采集节点加最后一道保险。不适合:纯实时控制且不容许任何意外复位的场景(如某些安全关键回路,那种要靠双机热备而非看门狗)。铁律三条:喂狗只在主循环主干、绝不放中断(中断喂狗=假活不叫);超时留足最大任务耗时+LSI 漂移裕量;Stop 场景睡眠时长必须小于看门狗超时、唤醒即喂;复位后必查 IWDGRSTF 标志记录原因。

相关推荐
zcmodeltech2 小时前
智能制造教学实训沙盘模型多系统协同控制系统设计:基于STM32与Modbus RTU的工业机器人-智慧工厂-数字孪生全场景联动方案
数据库·stm32·嵌入式硬件·机器人·制造·多分类
程序员与背包客_CoderZ3 小时前
Linux D-Bus通信协议详解:从入门到C/C++编码实战
linux·服务器·c语言·c++·嵌入式硬件·嵌入式软件·dbus
嵌入式阿蔡4 小时前
HAL库 vs LL库 vs 寄存器:到底用哪个?
c语言·stm32·单片机·嵌入式硬件·嵌入式实时数据库
天空'之城5 小时前
单片机基础核心知识点汇总(三)
单片机·嵌入式硬件
嵌入式阿蔡5 小时前
CAN总线入门:从协议帧到STM32实战
c语言·stm32·单片机·嵌入式硬件·嵌入式实时数据库
恒锐丰科技韩生6 小时前
率能 SS8847E|2.7~15V 双通道 H 桥电机驱动 ETSSOP16 散热封装 家电 / 打印 / 舞台灯光专用
嵌入式硬件·硬件工程
离凌寒6 小时前
一、对stm32mp157配置freertos后,任务挂掉无法启动问题总结
stm32·单片机·嵌入式硬件
消失的旧时光-19438 小时前
7-fix补充篇:机器人为什么需要多级控制仲裁?Cloud、Linux 与 MCU 分别管什么
linux·单片机·机器人·仲裁机制·安全保护机制
Hello_Damon_Nikola9 小时前
CH573从入门到精通
c语言·开发语言·单片机·嵌入式硬件