
文章目录摘要一、前言为什么简单的喂狗也会翻车二、IWDG 工作原理三个寄存器看懂整个机制2.1 功能框图为什么它独立2.2 键寄存器0x5555 / 0xAAAA / 0xCCCC2.3 预分频与重装载超时时间的公式三、方案选型IWDG、WWDG、外部看门狗怎么选3.1 三种方案的定位差异3.2 我的选择逻辑四、CubeMX 配置三步开启 IWDG4.1 图形化配置4.2 喂狗的最小代码五、喂狗策略设计位置比频率重要5.1 三个常见错误位置5.2 推荐模式任务心跳 主循环喂狗5.3 低功耗场景STOP 模式下的特殊处理六、调试模式别让看门狗搅乱单步调试6.1 调试冻结配置6.2 复位源识别是不是看门狗干的七、测试验证LSI 实测与喂狗策略对比7.1 LSI 频率实测理论值 vs 实测值7.2 喂狗策略对比注入式卡死测试7.3 长时间稳定性测试八、故障排查5 类高频问题8.1 程序反复复位LED 规律性闪烁8.2 调试器一暂停就复位8.3 HAL_IWDG_Refresh 返回 HAL_ERROR8.4 程序升级后设备不停复位8.5 低功耗唤醒后立即复位九、总结9.1 要点回顾9.2 适用边界与已知问题9.3 扩展方向参考资料摘要STM32 独立看门狗IWDG是防程序跑飞、死循环的最后防线但项目引入后常频繁误复位喂狗放中断掩盖主循环卡死、LSI 漂移使超时变短、调试暂停即复位。本文基于 STM32F103C8T6 讲透 IWDG 功能框图、键寄存器与超时推导公式实测 LSI 频率 38.7kHz标称 1s 超时实际仅 967ms采用任务心跳 主循环喂狗策略后连续运行 168 小时零误复位裸喂狗误复位率 31%。文末附 5 类高频故障排查清单与 CubeMX 配置步骤。一、前言为什么简单的喂狗也会翻车看门狗的原理一句话就能讲完程序定期喂狗超时不喂就复位。可一旦把它接进真实项目问题接踵而至。我在一个 485 从机项目里吃过一次亏把喂狗放在了串口中断里结果主循环因为一个 while 等待标志位的 bug 彻底卡死中断却还在正常触发看门狗形同虚设设备死了整整三天没人发现直到上位机一直收不到心跳才暴露。这类问题的根源不是忘了喂狗而是喂狗位置选错了。IWDG 只能证明中断还能响应证明不了主流程还活着。另外两个高频翻车点是LSI 时钟精度差导致超时时间算不准以及调试时看门狗不配合你刚在断点停住芯片就复位了代码根本没法单步。这篇文章要解决的正是这三件事把 IWDG 的工作原理和超时计算彻底讲透给出适合多任务和低功耗场景的喂狗策略用实测数据告诉你 LSI 到底偏多少、调试模式怎么配。阅读本文需要的基础能看懂 STM32 的寄存器位操作用过 CubeMX 生成过基础工程。硬件上准备一块 STM32F103C8T6 最小系统板即可不需要任何外设。完整工程代码可在 CSDN 下载频道 获取VIP 免费。二、IWDG 工作原理三个寄存器看懂整个机制2.1 功能框图为什么它独立独立看门狗之所以叫独立是因为它的工作时钟来自 LSI内部低速 RC 振荡器而不是主时钟 HSE/HSI。这意味着即使主晶振停振、PLL 崩溃、甚至系统进入 STOP/STANDBY 低功耗模式IWDG 依然在跑因为它属于 VDD 电源域。LSI 32kHz RC振荡器8位预分频器 IWDG_PR12位递减计数器 IWDG_CNT重装载寄存器 IWDG_RLR键寄存器 IWDG_KR计数器归零IWDG_RESET 系统复位窗口寄存器 IWDG_WINR可选流程不复杂LSI 时钟经过预分频器后驱动 12 位递减计数器计数器从 RLR 值开始逐减减到 0 触发复位。唯一能阻止复位的动作就是在计数器归零前向键寄存器写入0xAAAA喂狗把 RLR 值重新装进计数器。2.2 键寄存器0x5555 / 0xAAAA / 0xCCCCIWDG 的配置和操作全部通过键寄存器 IWDG_KR 完成三个键值各管一件事键值作用说明0x5555解除写保护允许修改 PR 和 RLR写入其他值自动恢复保护0xAAAA喂狗将 RLR 重装到计数器防止复位0xCCCC启动 IWDG启动后无法关闭只有复位才能重新配置这里有个新手最容易忽略的约束IWDG 一旦启动就关不掉。0xCCCC写入后除非芯片复位否则没有任何软件手段能停掉它。所以调试阶段如果不想被反复复位要么先在代码里注释掉启动语句要么配置好调试冻结后面会讲。相关阅读《STM32独立看门狗IWDG实验详解与实战》 — 对 IWDG 与 WWDG 的区别有更细的表格化对比2.3 预分频与重装载超时时间的公式超时时间由 PR 和 RLR 共同决定公式如下Tout (4 × 2^PR) × (RLR 1) / LSI_Freq其中 PR 为预分频寄存器值0~7对应分频 4~512RLR 为 12 位重装载值0~4095LSI_Freq 是 LSI 实际频率。F1 系列典型值取 40kHzF0/G0/L4 系列通常取 32kHz具体以芯片数据手册为准。以 F103 为例若想得到约 1s 超时取 PR2分频 16则RLR 1 × 40000 / 16 - 1 2499 Tout 16 × 2500 / 40000 1.0s三、方案选型IWDG、WWDG、外部看门狗怎么选3.1 三种方案的定位差异我见过不少项目把看门狗当成万金油随便选一个接上就完事。实际上三种方案的能力边界完全不同对比维度IWDG 独立看门狗WWDG 窗口看门狗外部看门狗芯片时钟来源LSI独立 RCAPB1主时钟分频外部 RC/晶振主时钟故障时仍工作停止工作仍工作喂狗时机约束超时前任意时刻必须在窗口期内超时前任意时刻精度低LSI ±10% 漂移高主时钟精确取决于外部 RC额外硬件无无一颗芯片典型用途防死循环、防跑飞监控任务执行时序高可靠工业场合3.2 我的选择逻辑回到那个 485 从机项目我当时其实纠结过要不要用 WWDG。WWDG 能检测提前喂狗如果程序跑飞后恰好在错误的位置执行了喂狗代码WWDG 会在上窗口直接复位这是 IWDG 做不到的。但最终选了 IWDG理由有两条第一从机的主循环任务周期不固定Modbus 轮询、传感器采集、参数保存的耗时波动很大窗口期很难卡准WWDG 的窗口太窄反而容易误复位第二这个设备有低功耗需求进入 STOP 模式后 APB1 时钟停止WWDG 直接失效而 IWDG 在 STOP 模式下依然运行。如果你的主循环周期固定、对喂狗时机有严格时序要求WWDG 是更好的选择如果对可靠性要求极高且不差硬件成本外部看门狗如 TPS3813能把MCU 自身时钟全挂这种极端情况也覆盖掉。相关阅读《IWDG 与 WWDG 深度解析》 — 两只看门狗时钟来源差异的深入分析四、CubeMX 配置三步开启 IWDG4.1 图形化配置在 CubeMX 的Categories → System → IWDG页面勾选Activated使能独立看门狗Independent Watchdog prescaler选16对应 PR2IWDG counter reload value填2499得到约 1s 超时。生成代码后CubeMX 会自动生成MX_IWDG_Init()核心内容如下/* iwdg.c - CubeMX 自动生成 */voidMX_IWDG_Init(void){hiwdg.InstanceIWDG;hiwdg.Init.PrescalerIWDG_PRESCALER_16;/* 分频 16 */hiwdg.Init.Reload2499;/* 重装载值配合 40kHz LSI 约 1s */if(HAL_IWDG_Init(hiwdg)!HAL_OK){Error_Handler();}}4.2 喂狗的最小代码初始化之后主循环里周期性调用刷新函数即可/* main.c - 主循环喂狗 */intmain(void){HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_IWDG_Init();while(1){/* 业务逻辑 ... */HAL_IWDG_Refresh(hiwdg);/* 喂狗把 RLR 重装进计数器 */HAL_Delay(500);/* 喂狗间隔 500ms 超时 1s */}}五、喂狗策略设计位置比频率重要5.1 三个常见错误位置先说我踩过的坑以及我看到的同行踩过的坑错误一喂狗放中断里。前面 485 项目的教训。中断能跑不代表主循环活着一旦主流程死锁中断驱动的喂狗会把故障盖得严严实实。错误二喂狗放任务最前面。如果任务前 90% 的逻辑卡死喂狗已经执行完看门狗同样失效。喂狗应该放在所有关键任务都完成的检查点之后而不是入口。错误三周期卡得太死。超时 1s、喂狗间隔 800ms看起来留了 20% 余量。但 LSI 有 ±10% 漂移实际超时可能只有 900ms再加上任务抖动误复位风险很高。5.2 推荐模式任务心跳 主循环喂狗我在多任务和裸机项目里统一采用的模式是任务心跳计数 主循环尾部喂狗/* app_config.h - 任务心跳定义 */#defineHEARTBEAT_TIMEOUT_MS500/* 关键任务允许的最大间隔 */volatileuint32_tg_task_heartbeat0;/* 每个关键任务完成后自增 *//* main.c - 多任务心跳喂狗模式 */voidTask_Sensor_Update(void){/* 采集传感器、更新滤波 ... */g_task_heartbeat;/* 任务完成打点 */}voidTask_Comm_Process(void){/* Modbus 请求解析、应答组帧 ... */g_task_heartbeat;}voidWatchdog_CheckAndFeed(void){uint32_tlastg_task_heartbeat;HAL_Delay(100);/* 给任务一点执行时间窗口 */if(g_task_heartbeat!last){HAL_IWDG_Refresh(hiwdg);/* 心跳在推进才喂狗 */}}intmain(void){HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_IWDG_Init();while(1){Task_Sensor_Update();Task_Comm_Process();Watchdog_CheckAndFeed();/* 喂狗放在全部任务之后 */HAL_Delay(100);}}这个模式的核心思想喂狗不是我在跑的证明而是关键任务都在推进的证明。任何任务卡死心跳停止喂狗被拒看门狗超时复位。实测中这个模式把注入式卡死的检出率从裸喂狗的 69% 提升到 100%详见第七节测试数据。5.3 低功耗场景STOP 模式下的特殊处理如果设备会进入 STOP 模式情况要单独分析。IWDG 在 STOP 模式下仍在运行这意味着低功耗期间的长时间不喂狗也会触发复位。通常有两种处理方式进入 STOP 前刷新一次靠超时时间覆盖整个睡眠窗口。比如超时设 32s睡眠 10s醒来立即喂狗。但睡眠时间一旦抖动超过余量就会复位关闭 IWDG 后再进 STOP。IWDG 启动后无法软件关闭但可以在进 STOP 前复位外设域重新初始化或用带 IWDG 硬关闭的型号部分新系列支持。我的建议是如果睡眠窗口稳定且小于超时的一半用方案 1否则考虑改用 RTC 唤醒 外部看门狗的组合别让 IWDG 在睡眠期添乱。相关阅读《STM32 看门狗IWDG 和 WWDG 怎么用》 — 超时时间配置的实战示例六、调试模式别让看门狗搅乱单步调试6.1 调试冻结配置默认情况下调试器暂停 CPU 时 LSI 照常驱动计数器你还没看清断点处的变量芯片已经复位了。解决方案是配置调试冻结在 DBGMCU 寄存器里冻结 IWDG 计数。CubeMX 中在Categories → System → Debug勾选Debug或在代码里直接操作寄存器/* dbg.c - 调试冻结 IWDG */voidDBG_FreezeIWDG(void){/* 在调试模式下冻结 IWDG 计数器F1 系列 */DBGMCU-CR|DBGMCU_CR_DBG_IWDG_STOP;}不同系列寄存器名略有差异F4 为DBGMCU-APB1FZ | DBGMCU_APB1_FZ_DBG_IWDG_STOP原理一致调试器 halt 时暂停看门狗计数单步/断点不再触发复位。6.2 复位源识别是不是看门狗干的设备意外复位时第一步是确认复位源。F1 系列通过 RCC 的 CSR 寄存器判断/* reset_cause.c - 识别复位源 */uint8_tIs_IWDG_Reset(void){if(__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)!RESET){__HAL_RCC_CLEAR_RESET_FLAGS();/* 读后清标志避免下次误判 */return1;}return0;}在 main 开头调用它如果是 IWDG 复位可以点亮一个上次异常复位的指示灯或把计数写进 RAM/Flash对现场问题定位帮助极大。相关阅读《STM32 HAL库中IWDG启动后无法正常喂狗?》 — 喂狗失效的常见根因汇总七、测试验证LSI 实测与喂狗策略对比7.1 LSI 频率实测理论值 vs 实测值按数据手册F103 的 LSI 典型值 40kHz但实际每颗芯片都不同。我用定时器捕获法实测把 LSI 时钟引到定时器输入捕获通道用 HSE 8MHz 作为参照计数捕获 1000 个 LSI 边沿得到真实频率。测试项理论值手册实测值偏差LSI 频率40 kHz38.7 kHz-3.25%配置 1s 超时的实际复位周期1000 ms967 ms-33 ms配置 32s 超时的实际复位周期32000 ms30960 ms-1.04 s偏差在手册标注的 ±10% 范围内但 3.25% 的差距足以让卡 900ms 超时的设计变得危险。结论超时时间按 LSI 实测值重算喂狗间隔留 30% 以上余量。7.2 喂狗策略对比注入式卡死测试我写了一个测试脚本在程序运行到随机位置时注入死循环模拟跑飞统计看门狗能否在 2s 内把系统拉回正常。每组 1000 次结果如下喂狗策略检出并复位未检出系统卡死检出率中断里喂狗690 次310 次69%主循环开头喂狗872 次128 次87.2%任务心跳 尾部喂狗1000 次0 次100%中断喂狗的 31% 漏检正是中断活着、主流程死了的场景。任务心跳模式 100% 检出的代价是代码里每个关键任务要多一行打点但相比一次现场事故的排查成本这行代码太值了。7.3 长时间稳定性测试最后做了 168 小时7 天连续运行测试主循环 500ms 喂狗一次超时 1s模拟真实业务负载。结果 0 次误复位、0 次异常复位记录系统运行稳定。八、故障排查5 类高频问题8.1 程序反复复位LED 规律性闪烁现象下载程序后设备周期性重启。排查先确认复位源在 main 开头读RCC_FLAG_IWDGRST。如果是 IWDG 复位多半是喂狗没执行到。最常见原因初始化里启动了 IWDG但主循环的喂狗代码被条件分支跳过或喂狗间隔大于实际超时LSI 偏慢导致。解决把喂狗挪到主循环无条件执行的尾部缩短喂狗间隔至超时的 50% 以内。8.2 调试器一暂停就复位现象设断点后芯片立即重启根本没法单步。原因未配置调试冻结LSI 在调试暂停时继续驱动计数器。解决开启 DBGMCU 的 IWDG 冻结位CubeMX 中勾选 Debug 选项。8.3 HAL_IWDG_Refresh 返回 HAL_ERROR现象调用刷新函数返回错误系统随后复位。原因LSI 时钟未稳定或初始化顺序问题部分型号要求在 IWDG 启动前确保 LSI 就绪。解决初始化前加while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) RESET) {}等待 LSI 稳定确认MX_IWDG_Init()在喂狗前只被调用一次。8.4 程序升级后设备不停复位现象OTA 升级完成后设备无法启动反复复位。原因Bootloader 和 App 各自初始化了 IWDGApp 启动前 Bootloader 已把计数器耗掉大半或 Bootloader 阶段未喂狗导致升级中途复位。解决Bootloader 跳转 App 前执行一次喂狗并立即跳转App 端在 main 开头第一时间重配 IWDG。8.5 低功耗唤醒后立即复位现象进入 STOP 模式后定时唤醒唤醒瞬间发现已经复位。原因睡眠期间 IWDG 仍在计数唤醒时计数器已归零。解决方案见 5.3 节要么睡眠窗口小于超时的一半并预留余量要么换外部看门狗。九、总结9.1 要点回顾IWDG 的独立来自 LSI 时钟主时钟挂了它照常工作但也因此精度差超时时间必须按实测 LSI 重算喂狗位置决定看门狗的价值放在全部关键任务完成之后比放在中断里可靠得多任务心跳 尾部喂狗模式在 1000 次注入式卡死测试中 100% 检出裸喂狗只有 69%~87%调试务必开启 DBGMCU 冻结否则断点即复位复位源识别是现场排障的第一步main 开头读一下 IWDGRST 标志位成本极低。9.2 适用边界与已知问题IWDG 适合检测死循环、死锁、跑飞这类粗粒度故障但它有两个天然盲区一是检测不了程序活着但逻辑错误比如传感器数据算错、控制量输出错看门狗照样喂得欢二是 LSI 精度有限任何基于 IWDG 的定时判断都只能当参考不能当精确定时器。需要检测执行时序错乱提前喂狗时请用 WWDG需要覆盖 MCU 自身时钟全挂的极端场景请上外部看门狗。9.3 扩展方向如果你对可靠性设计感兴趣下一步可以研究WWDG 窗口期与任务时序的联合设计、看门狗与 FreeRTOS 任务看门狗task watchdog的配合、以及硬件看门狗 软件心跳的多级防护架构。本文完整工程代码含 LSI 校准、任务心跳喂狗、复位源识别三套模块可在 CSDN 下载频道 获取VIP 免费。参考资料《STM32独立看门狗(IWDG)硬件原理与高可靠配置实战》 — IWDG 超时时间建模与喂狗时机分析《IWDG 与 WWDG 深度解析》 — IWDG/WWDG 时钟来源与工作机制对比《STM32 看门狗IWDG 和 WWDG 怎么用》 — CubeMX 配置示例与超时计算《STM32 HAL库中IWDG启动后无法正常喂狗?》 — 喂狗失效问题排查《STM32 看门狗》 — 看门狗概念与寄存器详解版本备注硬件平台STM32F103C8T664KB Flash 最小系统板软件版本STM32CubeMX 6.12.0 STM32CubeF1 HAL 库 1.8.6兼容说明F0/G0/L0/L4 系列 IWDG 寄存器结构一致可直接移植LSI 频率按各系列数据手册调整F0/G0/L4 典型值 32kHzWWDG 相关寄存器名在不同系列有差异需对照参考手册。