searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

STM32:独立看门狗、窗口看门狗的配置实战全解析

2026-07-08 14:58:45
0
0

一、看门狗的核心原理:定时喂狗与超时复位

无论是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 完整配置代码(标准库)

c
#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库)

c
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喂狗放在关键任务完成点——确保任务按时完成。

调试验证三步走

  1. 过早喂狗测试: 在窗口开启前触发WWDG喂狗,验证是否引发复位。
  2. 合规窗口测试: 在窗口期内喂狗,确认系统正常运行。
  3. 超时测试: 故意不喂狗,检查复位时序是否符合计算。

五、常见问题排查指南

问题 原因 解决方案
系统频繁复位 喂狗间隔≥超时时间 缩短喂狗间隔,增加设计余量
看门狗不工作 未解除写保护就配置 先写0x5555到KR再配置PR/RLR
WWDG总是复位 窗口设置不合理 窗口下限=理论最短时间×0.7,上限=理论最长时间×1.3
早期唤醒中断不触发 EWI位未使能 检查WWDG_CFR的EWI位是否置1
高温环境下提前复位 LSI频率随温度升高 用TIM5捕获实测LSI频率,动态调整RLR

调试时临时禁用看门狗的方法

c
__HAL_DBGMCU_FREEZE_IWDG();
__HAL_DBGMCU_FREEZE_WWDG();

六、总结:选型决策树

 
需要简单可靠的死机防护?
  → 选 IWDG

主时钟可能不稳定或需要低功耗模式?
  → 选 IWDG

需要检测代码执行时序异常?
  → 选 WWDG

需要中断提前预警?
  → 选 WWDG

对可靠性要求极高的关键系统?
IWDG + WWDG 联合使用

看门狗不是万能的。对于永久性硬件损坏,复位无法恢复;对于可预见的软件问题,应优先通过软件设计避免。但作为系统可靠性的最后一道防线,它能在你最无助的时候,给系统一次重新来过的机会。

0条评论
0 / 1000
窝补药上班啊
1449文章数
7粉丝数
窝补药上班啊
1449 文章 | 7 粉丝
原创

STM32:独立看门狗、窗口看门狗的配置实战全解析

2026-07-08 14:58:45
0
0

一、看门狗的核心原理:定时喂狗与超时复位

无论是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 完整配置代码(标准库)

c
#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库)

c
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喂狗放在关键任务完成点——确保任务按时完成。

调试验证三步走

  1. 过早喂狗测试: 在窗口开启前触发WWDG喂狗,验证是否引发复位。
  2. 合规窗口测试: 在窗口期内喂狗,确认系统正常运行。
  3. 超时测试: 故意不喂狗,检查复位时序是否符合计算。

五、常见问题排查指南

问题 原因 解决方案
系统频繁复位 喂狗间隔≥超时时间 缩短喂狗间隔,增加设计余量
看门狗不工作 未解除写保护就配置 先写0x5555到KR再配置PR/RLR
WWDG总是复位 窗口设置不合理 窗口下限=理论最短时间×0.7,上限=理论最长时间×1.3
早期唤醒中断不触发 EWI位未使能 检查WWDG_CFR的EWI位是否置1
高温环境下提前复位 LSI频率随温度升高 用TIM5捕获实测LSI频率,动态调整RLR

调试时临时禁用看门狗的方法

c
__HAL_DBGMCU_FREEZE_IWDG();
__HAL_DBGMCU_FREEZE_WWDG();

六、总结:选型决策树

 
需要简单可靠的死机防护?
  → 选 IWDG

主时钟可能不稳定或需要低功耗模式?
  → 选 IWDG

需要检测代码执行时序异常?
  → 选 WWDG

需要中断提前预警?
  → 选 WWDG

对可靠性要求极高的关键系统?
IWDG + WWDG 联合使用

看门狗不是万能的。对于永久性硬件损坏,复位无法恢复;对于可预见的软件问题,应优先通过软件设计避免。但作为系统可靠性的最后一道防线,它能在你最无助的时候,给系统一次重新来过的机会。

文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
0
0