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 时钟源 30kHz~60kHz 预分频器 4/8/16/32/64/128/256 12位递减计数器 0~4095 系统复位 喂狗操作 重装载寄存器 键寄存器 (KR) 计数器减到0 → 系统复位 喂狗操作 → 重装载值重新加载到计数器 键寄存器写入 0xAAAA → 喂狗 键寄存器写入 0xCCCC → 启动看门狗

核心要点总结

  • IWDG 使用独立 LSI 时钟,不受主时钟影响
  • 预分频系数和重装载值共同决定超时时间
  • 喂狗操作通过键寄存器写入 0xAAAA 实现
  • 硬件模式更安全,适合量产产品
  • 超时时间要留余量,考虑 LSI 频率偏差

专注资料整理