4. 硬件看门狗设计:独立看门狗(IWDG)与窗口看门狗(WWDG)

看门狗这东西,说白了就是一个「监工」。你干活的时候,得时不时跟它打个招呼:「嘿,我还活着呢!」。如果你忘了打招呼,它就认为系统挂了,直接给你来个复位。

我刚开始做运动控制那会儿,觉得看门狗就是个累赘。直到有一次,电机在高速运转时,主控芯片因为一个中断卡死,电机直接飞车……嗯,从那以后,我再也不敢轻视看门狗了。

4.1 独立看门狗(IWDG)—— 最可靠的「保底」

独立看门狗,我习惯叫它「硬汉」。为什么?因为它完全独立于主系统时钟,用的是自己的低速内部振荡器(LSI)。就算主时钟挂了,它照样能工作。

核心特点:

  • 使用独立的40kHz LSI时钟源
  • 12位递减计数器,最大可设4096分频
  • 一旦启动,无法关闭(除非复位)
  • 超时范围:约125μs ~ 32.7s

我在项目中遇到过这样的情况:电机驱动器在强电磁干扰下,主晶振偶尔会失锁。这时候,只有IWDG能兜底。其他看门狗?早就跟着主时钟一起「躺平」了。

IWDG的寄存器操作

操作IWDG其实很简单,就几个关键寄存器:

// 解锁写保护
IWDG->KR = 0x5555;  // 喂狗前必须先解锁

// 设置预分频器(4分频)
IWDG->PR = 0x02;    // 分频系数 = 4 * 2^PR = 16

// 设置重装载值(1000)
IWDG->RLR = 1000;   // 超时时间 = (RLR * 分频系数) / 40kHz

// 喂狗操作
IWDG->KR = 0xAAAA;  // 重装载计数器

// 启动看门狗
IWDG->KR = 0xCCCC;  // 启动后无法停止

注意:IWDG一旦启动,只有系统复位才能关闭。所以调试阶段,我建议先别开,等程序稳定了再启用。我曾经在调试时忘了关IWDG,结果每次单步执行到一半就被复位,折腾了一下午才发现问题。

4.2 窗口看门狗(WWDG)—— 更「智能」的监工

窗口看门狗,比IWDG多了一个「窗口」的概念。什么意思呢?你喂狗的时间不能太早,也不能太晚,必须在设定的时间窗口内完成。

为什么要有窗口?你想想看,如果程序跑飞了,但碰巧在某个循环里还在喂狗,IWDG就检测不到异常。WWDG就不一样了——你喂早了不行,喂晚了也不行,必须卡在正确的时间点。

WWDG的关键参数:

  • 时钟源:PCLK1(APB1总线时钟)
  • 7位递减计数器(T[6:0])
  • 窗口值(W[6:0]):喂狗必须在计数器值 < 窗口值时进行
  • 超时范围:约0.1ms ~ 50ms(取决于时钟配置)

WWDG的寄存器配置

// 配置窗口寄存器
// 假设PCLK1 = 36MHz,分频系数 = 8
// 计数器最大值 = 127,窗口值设为 80
WWDG->CFR = (1 << 7)    // WDGTB = 1,分频系数 = 8
          | (80 << 0);   // 窗口值 W = 80

// 配置控制寄存器
// 计数器初始值设为 127,使能看门狗
WWDG->CR = (127 << 0)   // T[6:0] = 127
          | (1 << 7);    // WDGA = 1,使能

// 喂狗操作(必须在计数器值 < 80 时进行)
WWDG->CR = (127 << 0);  // 重装载计数器

我的经验:WWDG的窗口值设置很有讲究。设得太宽,失去窗口意义;设得太窄,正常程序都可能喂不上。我一般会先跑一遍程序,用逻辑分析仪抓出喂狗的时间点,然后留20%的余量设置窗口。

4.3 IWDG vs WWDG:怎么选?

对比项 IWDG WWDG
时钟源 独立LSI(40kHz) 系统时钟PCLK1
可靠性 极高(独立于主时钟) 中等(依赖主时钟)
超时范围 125μs ~ 32.7s 0.1ms ~ 50ms
窗口功能 有(防止提前喂狗)
典型应用 安全关键系统、强干扰环境 实时性要求高的控制环路

我个人习惯:运动控制的主循环用WWDG,因为它能检测到程序跑飞后「碰巧」喂狗的情况。同时,再开一个IWDG作为最后一道防线,超时时间设得长一些(比如10秒),防止WWDG失效时系统彻底死掉。

4.4 实战中的避坑指南

我曾经踩过的坑:

  • 中断里喂狗:千万别在中断服务函数里喂狗!如果主循环卡死了,但中断还在正常触发,看门狗就形同虚设。我见过有人把喂狗放在定时器中断里,结果主程序死锁了,电机还在转,直到冒烟了才发现。
  • 喂狗位置不对:喂狗应该放在主循环的末尾,而不是开头。放在开头的话,如果喂完狗程序就卡住了,看门狗要等到下一个超时周期才能复位,这段时间系统可能已经出大问题了。
  • 调试时忘记关闭:仿真调试时,IWDG不会因为断点而暂停。所以调试前,最好加个条件编译,把看门狗关掉。
// 推荐的做法:条件编译控制看门狗
#ifdef DEBUG
  // 调试模式:关闭看门狗
  #define WDG_ENABLE()   do{}while(0)
  #define WDG_FEED()     do{}while(0)
#else
  // 发布模式:正常启用
  #define WDG_ENABLE()   IWDG->KR = 0xCCCC
  #define WDG_FEED()     IWDG->KR = 0xAAAA
#endif

void main(void)
{
    // 系统初始化
    SystemInit();
    
    // 使能看门狗
    WDG_ENABLE();
    
    while(1)
    {
        // 执行运动控制任务
        MotorControlTask();
        
        // 执行通信任务
        CommTask();
        
        // 喂狗(放在最后)
        WDG_FEED();
    }
}

4.5 知识体系总览

下面这张图,是我自己总结的看门狗选型与配置流程。每次做新项目,我都会先过一遍这个图,避免漏掉关键步骤。

硬件看门狗设计决策流程 开始看门狗设计 系统是否工作在强干扰环境? (电机驱动、工业现场、户外等) 优先选择 IWDG 独立时钟,不受主时钟影响 超时时间设长(1~10秒) 优先选择 WWDG 窗口功能可检测异常喂狗 超时时间设短(1~50ms) 是否需要双重保护? 安全关键系统:IWDG + WWDG 双重看门狗 普通系统:根据环境选择一种即可

这张图的核心逻辑其实就一句话:环境恶劣用IWDG,追求实时性用WWDG,不差钱两个都用。我在做伺服驱动器时,就是按照这个思路,IWDG设5秒超时保底,WWDG设10ms窗口监控主循环,用了三年没出过看门狗相关的故障。

最后说一句:看门狗不是万能的。它只能检测到程序「死掉」的情况,检测不到「程序活着但逻辑错误」的情况。所以,该做的异常处理、状态机保护,一个都不能少。看门狗只是最后一道防线,不是唯一的防线。

专注资料整理