一、看门狗的核心原理:定时喂狗与超时复位
无论是IWDG还是WWDG,其本质都是一个递减计数器。系统启动后,计数器开始倒计时,程序必须在计数器归零之前执行"喂狗"操作——也就是重置计数器的值。如果程序因为异常无法按时喂狗,计数器归零,看门狗就会触发系统复位,强制MCU重新启动,回到一个已知的安全状态。
这个机制就像你养了一只定时需要喂食的狗:你按时喂它,它就乖乖待着;你忘了喂它,它就把整个家拆了——然后你不得不重新收拾。
理解了这个核心逻辑,我们就可以深入两种看门狗各自的"性格"了。
二、独立看门狗(IWDG):不受主时钟影响的"独立卫士"
2.1 为什么叫"独立"?
IWDG之所以独立,是因为它拥有一套完全自成体系的时钟源——内部低速振荡器LSI,典型频率约40kHz(实际范围在30kHz~60kHz之间波动)。这意味着:
- 主时钟挂了,它还在跑。 即使HSE晶振停振、PLL锁相环失效,IWDG依然能正常工作。
- 功耗极低。 LSI是RC振荡器,不需要外部元件,适合电池供电场景。
- 一旦启动,无法软件关闭。 只能通过系统复位来停止它。这是一把双刃剑——可靠性极高,但调试时需要格外小心。
2.2 硬件结构与关键寄存器
IWDG的硬件结构非常简洁,核心由三个寄存器驱动:
| 寄存器 | 功能 | 关键值 |
|---|---|---|
| KR(键寄存器) | 控制启动、喂狗、解锁 | 0xCCCC=启动;0xAAAA=喂狗;0x5555=解锁 |
| PR(预分频寄存器) | 设置LSI分频系数 | 可选4/8/16/32/64/128/256 |
| RLR(重装载寄存器) | 设置计数器初始值 | 12位,范围0~0xFFF(4095) |
特别注意:修改PR和RLR之前,必须先向KR写入0x5555解除写保护! 这是无数开发者踩过的坑。
2.3 超时时间计算公式
Tout=fLSI4×2PR×(RLR+1)
其中:
- PR为预分频值(0~6,对应分频系数4~256)
- RLR为重装载值(0~4095)
- f_LSI取典型值40kHz(实际需按30kHz计算以确保最坏情况下仍能及时复位)
实战举例: 设置PR=3(分频系数32),RLR=1249,LSI=40kHz:
Tout=400004×23×1250=4000032×1250=1秒
也就是说,你需要在1秒内至少喂一次狗,否则系统复位。
2.4 完整配置代码(标准库)
#include "stm32f10x_iwdg.h"
void IWDG_Configuration(void)
{
// 步骤1:解除写保护(必须先做!)
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
// 步骤2:设置预分频系数为32(1.25kHz计数频率)
IWDG_SetPrescaler(IWDG_Prescaler_32);
// 步骤3:设置重装载值,实现约1秒超时
IWDG_SetReload(1249);
// 步骤4:首次喂狗
IWDG_ReloadCounter();
// 步骤5:启动看门狗(写入0xCCCC)
IWDG_Enable();
}
int main(void)
{
IWDG_Configuration();
while(1)
{
// 正常业务逻辑
Process_Data();
// 喂狗(必须在1秒内执行)
IWDG_ReloadCounter();
Delay_ms(800); // 喂狗间隔小于超时时间
}
}
2.5 IWDG的致命陷阱
不要用硬件定时器中断来喂狗! 硬件中断优先级高于主循环,如果主程序跑飞了但中断还在正常执行,看门狗会被"假喂"——计数器永远不会溢出,系统永远不会复位,你的设备就彻底卡死了,而且你还以为它在正常运行。
正确的做法是:在主循环的关键路径上喂狗,确保主程序活着才能喂狗。
三、窗口看门狗(WWDG):精准苛刻的"时间裁判"
3.1 与IWDG的本质区别
如果说IWDG是"只要你活着就行"的粗放管理,那WWDG就是"你必须在规定时间内活着"的精密监控。WWDG引入了一个核心概念——时间窗口:
| 特性 | IWDG | WWDG |
|---|---|---|
| 时钟源 | LSI(~40kHz) | PCLK1(通常36MHz) |
| 时间精度 | 低(±50%) | 高(<0.1%) |
| 复位条件 | 仅超时未喂狗 | 过早喂狗 或 过晚喂狗 |
| 计数器 | 12位 | 7位(0x40~0x7F) |
| 中断功能 | 无 | 有(早期唤醒中断EWI) |
| 适用场景 | 通用异常保护 | 实时控制、时序监控 |
WWDG的设计哲学是:如果程序跑飞后进入一个死循环,但这个死循环恰好在"正确的时间"喂了狗,IWDG会被骗过去,但WWDG不会。 因为WWDG要求喂狗必须落在特定的时间窗口内。
3.2 窗口机制详解
WWDG的计数器T[6:0]从初始值(通常0x7F=127)开始递减:
- 下窗口(固定): 0x40(64)。当计数器≤0x40时,绝对不能喂狗,否则立即复位。
- 上窗口(可配置): W[6:0],由WWDG_CFR寄存器设置,必须大于0x40。
- 复位触发点: 计数器从0x40减到0x3F时触发复位。
- 早期唤醒中断: 计数器减到0x40时触发EWI中断,这是系统复位前的"最后一次呼救"。
喂狗的有效窗口 = 计数器值在(W[6:0], 0x40)之间。 早于W[6:0]喂狗→程序跑太快→复位;晚于0x40喂狗→程序太慢→复位。
3.3 超时时间与窗口时间计算
Twwdg=fPCLK14096×2WDGTB×(T[5:0]+1)
Twindow=fPCLK14096×2WDGTB×(T[5:0]−W[5:0])
其中:
- WDGTB为预分频系数(0~3,对应1/2/4/8分频)
- T[5:0]为计数器初始值(通常0x7F)
- W[5:0]为窗口值
实战举例: PCLK1=36MHz,WDGTB=3(8分频),T=0x7F(127),W=0x5A(90):
- 计数周期 = 4096 × 8 / 36MHz ≈ 0.910ms
- 超时时间 = 128 × 0.910ms ≈ 116.5ms(从0x7F减到0x3F)
- 窗口开启时间 = (127-90) × 0.910ms ≈ 33.7ms
- 喂狗必须在系统启动后33.7ms~116.5ms之间完成!
3.4 完整配置代码(HAL库)
WWDG_HandleTypeDef hwwdg;
void WWDG_Configuration(void)
{
// 步骤1:使能WWDG时钟(必须先做!)
__HAL_RCC_WWDG_CLK_ENABLE();
// 步骤2:配置参数
hwwdg.Instance = WWDG;
hwwdg.Init.Prescaler = WWDG_PRESCALER_8; // 8分频
hwwdg.Init.Window = 0x5A; // 窗口值=90
hwwdg.Init.Counter = 0x7F; // 初始值=127
hwwdg.Init.EWIMode = WWDG_EWI_ENABLE; // 启用早期唤醒中断
if(HAL_WWDG_Init(&hwwdg) != HAL_OK)
{
Error_Handler();
}
// 步骤3:配置中断优先级
HAL_NVIC_SetPriority(WWDG_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(WWDG_IRQn);
}
// 喂狗函数(必须在窗口时间内调用!)
void WWDG_Feed(void)
{
HAL_WWDG_Refresh(&hwwdg); // 内部实现:写入WWDG_CR = 0x7F | WDGA
}
// 早期唤醒中断服务函数
void WWDG_IRQHandler(void)
{
if(__HAL_WWDG_GET_FLAG(__HAL_WWDG_GET_IT_SOURCE(WWDG_IT_EWI)))
{
__HAL_WWDG_CLEAR_FLAG(WWDG_FLAG_EWIF);
// 紧急处理:保存关键数据、切换安全模式等
Save_Critical_Data();
Emergency_Shutdown();
// 最后尝试喂狗
HAL_WWDG_Refresh(&hwwdg);
}
}
3.5 WWDG的实战应用场景
场景一:电机控制系统。 控制周期为1ms,要求看门狗监控2个周期内的任务执行。设置窗口为1.5ms~2ms,任何任务超时都会触发复位。
场景二:RTOS任务监控。 每个关键任务维护自己的"喂狗标记",看门狗监护任务定期检查所有标记,只有当所有任务都正常时才喂狗。这种分布式喂狗架构能有效避免个别任务异常被掩盖。
场景三:通信协议监控。 UART/CAN等通信协议处理中,如果程序卡在发送/接收状态无法退出,WWDG的窗口机制能确保在合理时间内恢复。
四、IWDG与WWDG的联合使用策略
在高可靠性系统中,同时使用两种看门狗是最佳实践:
| 看门狗 | 角色 | 超时设置 |
|---|---|---|
| IWDG | 最后防线 | 较长(1~5秒) |
| WWDG | 精细监控 | 较短(50~200ms) |
喂狗位置设计:
- IWDG喂狗放在主循环末尾——确保主循环在跑。
- WWDG喂狗放在关键任务完成点——确保任务按时完成。
调试验证三步走:
- 过早喂狗测试: 在窗口开启前触发WWDG喂狗,验证是否引发复位。
- 合规窗口测试: 在窗口期内喂狗,确认系统正常运行。
- 超时测试: 故意不喂狗,检查复位时序是否符合计算。
五、常见问题排查指南
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 系统频繁复位 | 喂狗间隔≥超时时间 | 缩短喂狗间隔,增加设计余量 |
| 看门狗不工作 | 未解除写保护就配置 | 先写0x5555到KR再配置PR/RLR |
| WWDG总是复位 | 窗口设置不合理 | 窗口下限=理论最短时间×0.7,上限=理论最长时间×1.3 |
| 早期唤醒中断不触发 | EWI位未使能 | 检查WWDG_CFR的EWI位是否置1 |
| 高温环境下提前复位 | LSI频率随温度升高 | 用TIM5捕获实测LSI频率,动态调整RLR |
调试时临时禁用看门狗的方法:
__HAL_DBGMCU_FREEZE_IWDG();
__HAL_DBGMCU_FREEZE_WWDG();
六、总结:选型决策树
需要简单可靠的死机防护?
→ 选 IWDG
主时钟可能不稳定或需要低功耗模式?
→ 选 IWDG
需要检测代码执行时序异常?
→ 选 WWDG
需要中断提前预警?
→ 选 WWDG
对可靠性要求极高的关键系统?
→ IWDG + WWDG 联合使用
看门狗不是万能的。对于永久性硬件损坏,复位无法恢复;对于可预见的软件问题,应优先通过软件设计避免。但作为系统可靠性的最后一道防线,它能在你最无助的时候,给系统一次重新来过的机会。