4、独立看门狗(IWDG)详解:STM32 IWDG寄存器配置、时钟源选择、预分频器设置
独立看门狗,简称 IWDG。说实话,这是我在项目里用得最多的看门狗。为什么?因为它独立于主时钟,哪怕主时钟挂了,它照样能跑。这在工业现场简直是救命稻草。
我记得有一次做电机驱动器,现场强电磁干扰直接把主晶振震停了。主控芯片死在那,连 SysTick 都不走了。但 IWDG 还在跑,因为它用的是独立的内部 RC 振荡器。最后系统自动复位,设备重新站了起来。从那以后,我对 IWDG 就特别信任。
4.1 IWDG 的核心特性
先说说 IWDG 的几个关键点:
- 完全独立:它有自己的时钟源——LSI(低速内部振荡器),大约 40kHz(实际在 30kHz~60kHz 之间浮动)。
- 不需要外部晶振:省了两个引脚,也省了成本。
- 一旦启动,无法软件停止:除非复位,否则它一直跑。这个特性很关键,防止程序跑飞后自己把看门狗关了。
- 支持硬件和软件启动:可以通过选项字节配置成硬件启动,上电即运行。
重要提醒:IWDG 的时钟 LSI 精度不高,典型值 40kHz,但实际可能偏差 ±10%~±20%。所以超时时间只能算个大概,不能用于精确计时。
4.2 时钟源选择:为什么是 LSI?
你可能会问:为什么不用 HSI 或 HSE?
原因很简单——可靠性。LSI 是芯片内部自带的 RC 振荡器,不需要任何外部元件。即使主时钟因为晶振损坏、引脚虚焊、电磁干扰等原因停振,LSI 依然能正常工作。
我有个血的教训。早期一个项目用了外部晶振给看门狗提供时钟,结果现场振动大,晶振引脚接触不良。看门狗直接罢工,系统死机了都没人知道。后来全部换成 IWDG,再没出过类似问题。
LSI 的频率范围一般在 30kHz~60kHz,STM32 数据手册会给出具体值。以 STM32F103 为例,典型值 40kHz,最小值 30kHz,最大值 60kHz。
4.3 预分频器设置:算好你的超时时间
IWDG 的预分频器有 4 个档位:4、8、16、32、64、128、256。注意,这里的预分频系数是 2 的幂次方。
超时时间的计算公式:
超时时间 = (预分频系数 × 重装载值) / LSI频率
举个例子,假设 LSI = 40kHz,预分频系数设为 64,重装载值设为 625:
超时时间 = (64 × 625) / 40000 = 1 秒
嗯,这里要注意:重装载值最大是 0xFFF(4095),所以最长超时时间大约是:
最长超时 = (256 × 4095) / 30000 ≈ 34.9 秒
如果 LSI 取最大值 60kHz,那最短超时时间:
最短超时 = (4 × 1) / 60000 ≈ 66.7 微秒
下面是常用的配置组合表:
| 预分频系数 | 预分频器寄存器值 | LSI=40kHz 时最小超时 | LSI=40kHz 时最大超时 |
|---|---|---|---|
| 4 | 0 | 0.1ms | 409.5ms |
| 8 | 1 | 0.2ms | 819ms |
| 16 | 2 | 0.4ms | 1.638s |
| 32 | 3 | 0.8ms | 3.276s |
| 64 | 4 | 1.6ms | 6.552s |
| 128 | 5 | 3.2ms | 13.104s |
| 256 | 6 | 6.4ms | 26.208s |
我的习惯:一般选预分频系数 64 或 128,重装载值设 500~1000,超时时间控制在 1~3 秒。太短容易误复位,太长又起不到保护作用。
4.4 寄存器配置实战
IWDG 的寄存器不多,就几个:
- IWDG_KR(键寄存器):写入 0x5555 允许访问其他寄存器,写入 0xAAAA 喂狗,写入 0xCCCC 启动看门狗。
- IWDG_PR(预分频寄存器):设置预分频系数。
- IWDG_RLR(重装载寄存器):设置重装载值。
- IWDG_SR(状态寄存器):检查寄存器更新是否完成。
直接上代码,这是我项目里常用的初始化函数:
void IWDG_Init(uint8_t prescaler, uint16_t reload)
{
// 1. 允许访问 PR 和 RLR 寄存器
IWDG->KR = 0x5555;
// 2. 设置预分频系数
IWDG->PR = prescaler;
// 3. 设置重装载值
IWDG->RLR = reload;
// 4. 等待寄存器更新完成
while (IWDG->SR & 0x01); // 等待 PVU 位清零
while (IWDG->SR & 0x02); // 等待 RVU 位清零
// 5. 启动看门狗
IWDG->KR = 0xCCCC;
// 6. 第一次喂狗(启动后必须立即喂一次)
IWDG->KR = 0xAAAA;
}
喂狗函数更简单:
void IWDG_Feed(void)
{
IWDG->KR = 0xAAAA;
}
我曾经踩过的坑:启动 IWDG 后,必须在第一次超时之前喂狗。否则芯片会立即复位。另外,修改 PR 和 RLR 时一定要等状态寄存器就绪,否则写入无效。
4.5 硬件启动模式
如果你想让 IWDG 上电就自动运行,不需要软件启动,可以配置选项字节。在 STM32 的选项字节中,将 IWDG_SW 位设置为 0,IWDG 就会变成硬件模式。
硬件模式的好处是:即使程序在启动阶段就跑飞了,看门狗也能起作用。我在一些安全等级要求高的项目里,都会开启硬件模式。
配置方法(以 STM32F1 为例):
// 在系统初始化早期调用
void IWDG_HardwareEnable(void)
{
// 解锁选项字节
FLASH_Unlock();
FLASH_OB_Unlock();
// 设置 IWDG 硬件模式
OB->USER = (OB->USER & ~0x08) | 0x00; // 清除 IWDG_SW 位
// 重新加载选项字节
FLASH_OB_Launch();
}
建议:量产时用硬件模式,开发调试时用软件模式。这样调试时方便,量产时安全。
4.6 常见问题与避坑指南
最后分享几个我实际遇到的问题:
- 喂狗位置不对:不要在中断里喂狗。如果主循环卡死了但中断还能进,看门狗就形同虚设。我一般只在主循环的固定位置喂狗。
- 超时时间太短:系统启动、Flash 擦写、ADC 采样等操作耗时较长。如果超时时间设得太短,正常操作都会触发复位。建议留 2~3 倍余量。
- LSI 频率偏差:不同芯片、不同温度下 LSI 频率差异很大。量产时一定要按最差情况计算超时时间。
- 调试时注意:用调试器单步执行时,IWDG 不会暂停。如果你停在断点太久,芯片会复位。我习惯在调试时先注释掉 IWDG 初始化,调试完再打开。
说白了,IWDG 是系统可靠性的最后一道防线。配置不难,但细节很多。把这些细节处理好,你的系统才能真正做到「死不了」。
核心要点总结:
- IWDG 使用独立 LSI 时钟,不受主时钟影响
- 预分频系数和重装载值共同决定超时时间
- 喂狗操作通过键寄存器写入 0xAAAA 实现
- 硬件模式更安全,适合量产产品
- 超时时间要留余量,考虑 LSI 频率偏差