保姆级教程|STM32 IWDG 与 WWDG 看门狗:原理、配置及实战实验全攻略
英文名称本质功能硬件级程序运行监控机制,通过 “喂狗”(重置计数器)避免程序卡死 / 跑飞。类比 “自动重启按钮”,在程序异常时强制复位,保障系统可用性。应用场景嵌入式系统(如 STM32)中防止软件漏洞、硬件故障(如传感器卡死)、电磁干扰导致的系统崩溃。尤其适用于无人值守设备、工业控制等高可靠性场景。
WDG
WDG简介
- 英文名称:Watchdog(WDG)
- 本质功能
- 硬件级程序运行监控机制,通过 “喂狗”(重置计数器)避免程序卡死 / 跑飞。
- 类比 “自动重启按钮”,在程序异常时强制复位,保障系统可用性。
- 应用场景
- 嵌入式系统(如 STM32)中防止软件漏洞、硬件故障(如传感器卡死)、电磁干扰导致的系统崩溃。
- 尤其适用于无人值守设备、工业控制等高可靠性场景。

IWDG框图
1. 硬件架构与组件(对应框图)
- 时钟源(LSI)
- 框图左侧输入为 LSI(40kHz),会议强调其独立于主时钟,确保主时钟故障时仍能工作,频率范围 30~60kHz(计算超时需留余量)。
- 预分频器(8 位 + IWDG_PR)
- 8 位预分频器连接 IWDG_PR 寄存器,提供 6 种分频比(4、8、16、32、64、256)(2n,n=0~5),调整计数器递减速度。
- 12 位递减计数器
- 框图中间的 12 位计数器(最大值 4095),未喂狗时减至 0 触发复位,会议通过程序模拟(按键卡死)验证此机制。
- 重装载寄存器(IWDG_RLR)
- 存储喂狗重置值,通过 IWDG_KR(键寄存器)写入 0xAAAA 实现重装(喂狗操作),框图中显示其输出连接计数器。
- 键寄存器(IWDG_KR)
- 框图右侧的16 位键寄存器,会议详细说明:
- 0xAAAA:喂狗(重装 RLR 到计数器);
- 0xCCCC:启用看门狗(不可关闭);
- 0x5555:解除 PR/RLR 写保护(抗干扰设计,多比特操作避免误触发)。
- 框图右侧的16 位键寄存器,会议详细说明:
- 状态寄存器(IWDG_SR)
- 框图中的状态寄存器,用于指示看门狗运行状态(如是否使能、复位标志等)。
- 供电与工作模式
- 框图底部标注 VDD 供电区, IWDG 在 停机 / 待机模式下仍工作,确保低功耗场景的监控可靠性。
2. 工作流程与原理
- 初始化
- 写 0x5555 解除写保护,配置 PR(分频比) 和 RLR(重装载值);
- 写 0xCCCC 启用看门狗,计数器从 RLR 值开始递减。
- 喂狗操作
- 主循环定期写 0xAAAA,将 RLR 值重装到计数器,重置递减过程(框图中箭头显示重装路径)。
- 复位触发
- 未喂狗时,计数器减至 0,触发 IWDG 复位(框图右侧输出),可以通过 OLED 显示 “独立看门狗 RST” 验证。
3. 特性与应用
- 抗干扰设计:键寄存器的 16 位操作(非单比特),降低电磁干扰导致的误配置 / 误喂狗,提升可靠性(框图中键寄存器的特殊位置体现此设计)。
- 独立运行:依赖 LSI 时钟,主时钟故障时仍工作,适用于 对时间精度要求低、需高可靠性的场景(如工业控制、无人值守设备)。
- 不可关闭性:启用后(0xCCCC)无法关闭,确保系统持续受监控(框图中无关闭路径,会议强调此硬件特性)。
总结:LSI时钟信号 -> 8位预分频器(最多256分频) 预分频寄存器 可以配置分频器的系数(和定时器的PSC相似)->递减计数器 (递减计数器减到0,就触发复位) 为了让其减到0进行复位,就每个一段时间进行值的重装 (重装值寄存器可以设置重载值 与定时器中的ARR相似) -> 键寄存器 (可以写入命令,通过命令将值写入计数器等操作) -> 状态寄存器 有两个状态标志位,一般不看。

IWDG键寄存器

IWDG超时时间
- 计数器递减机制
- IWDG 的 12 位计数器 初始值为 RLR 寄存器的值(范围 0~4095),每次时钟脉冲(经预分频后的 LSI 时钟)递减 1,直到减至 0 时触发复位。
- 例如:
- 若
RLR = 0,计数器从 0 开始,立即触发复位(最短超时,对应公式中0+1=1次计数)。 - 若
RLR = 4095,计数器从 4095 递减到 0,共 4096 次计数(4095+1),对应最长超时时间。
- 若
- 公式物理意义
超时时间等于 单次计数周期 × 预分频系数 × 总计数次数
- 单次周期:TLSI=1/FLSI(如 40kHz 时为 25μs)。
- 预分频系数:调整时钟频率(如 / 16 分频,延长单次计数周期)。
- 总计数次数:
RLR + 1(从 RLR 到 0 的所有递减步骤,含初始值)。
总结:TSI是时钟信号的周期 * 预分频系数(可以这样理解,分频之后的周期 就是 时钟信号频率 / 分频系数 在进行整体取倒数,所以这里是 * 预分频系数)得的的时间是 一次的时间 然后再* 次数,因为触发的时机为减到0立刻触发看门狗,所以会对 RL+1 (比如RL = 0 那么溢出就会是1)。RL+1 为从初始化减到0的计数总次数。

WWDG框图
1. 硬件架构与工作原理(框图解析)
- 时钟源:采用 PCLK1(36MHz,主时钟分支),经固定 4096 分频后驱动 预分频器(WDGTB,4 种分频比:1、2、4、8),控制计数器递减速度。
- 计数器与寄存器
- 6 位递减计数器(CNT,T5~T0):位于 WWDG_CR 寄存器,T6 为溢出标志(T6=1:未溢出,可喂狗;T6=0:溢出,触发复位)。
- 窗口寄存器(WWDG_CFR,W6~W0):存储最早喂狗阈值,比较器检测 CNT > 窗口值(T6:0 > W6:0) 时,判定为 “过早喂狗”,触发复位(框图中与门逻辑)。
- 控制寄存器(WWDG_CR,WDGA 位):置 1 启用看门狗,启用后不可关闭,且首次配置需确保 T6=1(CNT≥0x40),避免立即复位。
2. 时间窗口与复位机制
- 复位条件
- 过晚喂狗:CNT 减至 <0x40(T6=0),计数器溢出,触发复位(框图中 T6=0 时的复位路径)。
- 过早喂狗:CNT > 窗口值(W6~W0),比较器输出 1,通过与门触发复位(对应 “窗口外喂狗”)。
- 喂狗要求:必须在 窗口值 < CNT < 0x40(T6=1 时) 内进行,确保喂狗时间既不早于窗口下限,也不晚于溢出上限(会议中窗口 30~50ms 即此逻辑的简化应用)。
总结:PCLK1时钟信号 -> 预分频器(进行预分频处理 预分频参数 有 1 2 4 8)这样可以控制递减的速度 -> 6位递减计数器用来递减计数 T6位 也就是第7位 这里用做的溢出位 也就是最开始配置 计数器时最小值为 0x40 因为当T6位从 1 跳变到 0 的时机就是 窗口看门狗的超时喂狗的复位触发时机,WDGA为开启看门狗的控制位 给1开启并且开启后不可关闭 与另一条线路 进行与操作 ,输出信号由另一条路决定,T6溢出会写0,在或门进行非 写一 所以会产生复位 。框图的上面为配置寄存器可以设置看门狗的窗口值 当 当前计数值 CNT 大于 窗口值时,为过早喂狗 会触发 复位。

WWDG工作特性
1. 复位触发机制
- 过晚喂狗(T<0x40):当 7 位计数器(T6:0)减至小于 0x40(即 T6=0,如 0x3F~0x00),立即触发复位(图 159 中计数器下降到 3Fh 时 T6 位清零,随后产生复位信号)。
- 窗口外喂狗(T>W):若喂狗操作(重装计数器)发生在计数器值大于窗口值 W [6:0](图中 “不允许刷新” 区域),视为 “过早喂狗”,直接触发复位(比较器检测 T>W,通过逻辑门复位)。
2. 早期唤醒中断(EWI)
- 触发条件:计数器等于 0x40(T6=1,T5~T0=0)时,产生 EWI 中断(图中 T6 位在 0x40 时仍为高电平,未到 3Fh)。
- 功能:用于紧急操作(如数据保存) 或 提前喂狗(在 T<0x40 前重装计数器,避免复位),是 WWDG 的 “预警机制”,提升系统容错能力。
3. 时间窗口与喂狗逻辑(时序图解析)
- 窗口划分
- 禁止区(T>W):过早喂狗→ 复位;
- 允许区(W≥T≥0x40):可喂狗(重装计数器,图中斜线下降到 W 以下进入窗口,此时操作有效);
- 危险区(T<0x40):过晚喂狗→ 复位(T6=0 时触发)。
- 喂狗操作:必须在 允许区(W~0x40) 内定期写入 WWDG_CR 寄存器(重装计数器),确保喂狗时间合法(窗口 30~50ms 即此逻辑的具体应用,40ms 位于窗口内,验证正常喂狗)。
总结:计数器当前计数大于 窗口值,视为提前喂狗 产生复位 ,在设置的 窗口内喂狗 操作有效 当 T6为 = 0 就触发 复位 但是在 T6 = 1 的最后一个计数 就是 要产生计数的前一个计数 可以设置 EWI 操作 可以进行 一系列的操作(如保存数据等等,防止数据丢失等)。

WWDG超时时间
总结:时间的计算方式与 独立看门狗的计算方式相同 这里 * 4096 是因为 进来之后会先进行 默认的4096 分频 所以要 * 4096.

IWDG和WWDG对比

独立看门狗(小实验)
核心配置流程(分步详解)
1. 解除写保护(关键前提)
- 目的:默认情况下,预分频器(PR)和重装值寄存器(RLR)被写保护,需先解锁才能修改。
- 操作
- 向 IWDG_KR 寄存器 写入 键值 0X5555(对应库函数:
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable))。 - 作用:允许后续操作修改 PR 和 RLR 寄存器。
- 向 IWDG_KR 寄存器 写入 键值 0X5555(对应库函数:
2. 计算并设置预分频系数(PR)和重装值(RLR)
-
公式:超时时间(ms)=LSI频率(kHz)(PR+1)×(RLR+1)×1000
- LSI 频率:取 40kHz(默认值,实际以芯片手册为准)。
- 参数选择原则
- 优先选择 较小的预分频系数(如 16、32 等),减少因整数取整导致的时间误差。
- 确保
PR和RLR的值在允许范围内(PR:07;`RLR`:00xFFF,即 0~4095)。
-
示例计算(以超时时间 1000ms 为例):
-
选择 PR=16 分频(对应库函数参数
IWDG_Prescaler_16),则:RLR=(161000×40)−1=2500−1=2499 -
库函数调用
IWDG_SetPrescaler(IWDG_Prescaler_16); // 设置预分频系数 IWDG_SetReload(2499); // 设置重装值
-
3. 启动独立看门狗
- 操作:向 IWDG_KR 寄存器 写入 键值 0XCCCC(对应库函数:
IWDG_Enable())。 - 效果:看门狗开始倒计时,从
RLR值(如 2499)递减至 0 时触发复位。
4. 喂狗操作(主循环中持续执行)
-
目的:防止看门狗超时复位,需在超时时间内定期 “喂狗”(重置计数器)。
-
操作:向 IWDG_KR 寄存器 写入 键值 0XAAAA(对应库函数:
IWDG_ReloadCounter())。 -
示例代码
while (1) { IWDG_ReloadCounter(); // 喂狗 delay_ms(800); // 确保间隔小于超时时间(1000ms) }
三、辅助配置:复位原因判断(可选)
-
功能:通过 RCC 寄存器 判断复位是否由看门狗触发。
-
步骤
- 查看标志位:调用
RCC_GetFlagStatus(RCC_FLAG_IWDGRST)检测独立看门狗复位标志。 - 清除标志位:调用
RCC_ClearFlag()清除标志,避免误判后续复位。
- 查看标志位:调用
-
代码示例
if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET) { // 处理看门狗复位逻辑(如显示提示) RCC_ClearFlag(); // 必须清除标志位 } else { // 处理普通复位逻辑 }
四、注意事项与调试建议
- 写保护机制:
- 配置完 PR 和 RLR 后,无需手动重新启用写保护(启动看门狗或写入非 0X5555 值会自动恢复保护)。
- 时间误差:
- LSI 时钟精度较低(±10%),实际超时时间可能与计算值有偏差,建议预留 20%~30% 余量(如设置超时 1000ms 时,喂狗间隔控制在 800ms 以内)。
- 测试方法:
- 故意延长喂狗间隔(如超过 1000ms),观察是否触发复位,验证看门狗功能是否正常。
- 通过按键阻塞主循环,模拟程序卡死场景,测试看门狗复位逻辑。
| 函数名称 | 功能描述 | 参数 | 对应寄存器操作 | 返回值 |
|---|---|---|---|---|
IWDG_WriteAccessCmd |
解除或启用独立看门狗寄存器的写保护 | NewState: IWDG_WriteAccess_Enable(0X5555) IWDG_WriteAccess_Disable(0X0000) |
向IWDG_KR写入键值 |
无 |
IWDG_SetPrescaler |
设置独立看门狗的预分频系数 | Prescaler:预分频系数(如IWDG_Prescaler_16、IWDG_Prescaler_32等) |
向IWDG_PR写入预分频值 |
无 |
IWDG_SetReload |
设置独立看门狗的重装值(计数器初始值) | Reload:重装值(0~0xFFF,即 0~4095) |
向IWDG_RLR写入重装值 |
无 |
IWDG_ReloadCounter |
重新装载计数器(喂狗操作) | 无 | 向IWDG_KR写入0XAAAA |
无 |
IWDG_Enable |
启动独立看门狗 | 无 | 向IWDG_KR写入0XCCCC |
无 |
IWDG_GetFlagStatus |
获取独立看门狗的标志位状态(如超时标志) | Flag: IWDG_FLAG_RLRF(.reload 标志) |
读取IWDG_SR寄存器 |
SET或RESET |
RCC_GetFlagStatus |
检测并返回 RCC 复位标志位状态(判断复位原因) | RCC_FLAG: 如RCC_FLAG_IWDGRST(独立看门狗复位) RCC_FLAG_WWDGRST(窗口看门狗复位) |
读取 RCC 控制寄存器的标志位 | SET或RESET |
RCC_ClearFlag |
清除 RCC 的复位标志位(避免后续误判) | 无 | 清除 RCC 控制寄存器的标志位 | 无 |
总结
不需要手动开器LSI时钟,如果开启看门狗 就自动开启 LSI时钟 ,下面需要输入 指令 关闭写保护(不用手动开启写保护 当开启看门狗 或者写入 非 0x55时,会自动开启写保护) ,然后再写入 预分频 写入 重装载寄存器 ,然后开启看门狗 装置,可以在主程序中加入 判断是否是 看门狗产生的复位等操作 来跟直观的看到 看门狗复位的程序现象。

独立看门狗主要代码
//main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "key.h"
int main(void)
{
OLED_Init();
Key_Init();
OLED_ShowString(1, 1, "IWDG_RET or RET");
//判断是否是通过什么方式产生的复位
if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET)
{
OLED_ShowString(2, 1, "IWDG_SET");
Delay_ms(200);
OLED_ShowString(2, 1, " ");
Delay_ms(100);
//要手动清除标志位
RCC_ClearFlag();
}
else
{
OLED_ShowString(3, 1, "SET");
Delay_ms(200);
OLED_ShowString(3, 1, " ");
Delay_ms(100);
}
//下面为开启看门狗的操作
//先写使能
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
//写入 重装值 预分频器值
//查看表格 看要设置的分频器的计数范围 是否 包含要计数的计数次数
IWDG_SetPrescaler(IWDG_Prescaler_16);
//计算重装值 1000 ms = 1 / 40khz * 16 * (RL + 1) ---》 RL = 2499 注意单位换算
IWDG_SetReload(2499);
IWDG_Enable();
while(1)
{
//按下按键 阻塞程序
Key_GetNum();
//在循环中设置时间 执行喂狗操作
IWDG_ReloadCounter();
OLED_ShowString(4, 1, "FEED");
Delay_ms(200);
OLED_ShowString(4, 1, " ");
Delay_ms(600);
}
}
窗口看门狗(小实验)
窗口看门狗(WWDG)操作流程
- 第一步:开启时钟
- 时钟来源:WWDG 时钟来自 PCLK1(需手动开启,不同于 IWDG 的自动时钟开启)。
- 函数调用:通过
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE)开启 WWDG 的 APB1 时钟。
- 第二步:配置寄存器
- 预分频系数(Prescaler):通过
WWDG_SetPrescaler(WWDG_Prescaler_8)设置分频比(例:选择 8 分频,即 2^3=8)。 - 窗口值(Window Value):通过
WWDG_SetWindowValue(0x21)设置窗口上限值(需结合计算,见下文)。 - 特点:WWDG 无写保护,可直接写入寄存器配置。
- 预分频系数(Prescaler):通过
- 第三步:使能看门狗并初始化计数器
- 调用
WWDG_Enable(0x54 | 0x40)使能 WWDG,同时设置初始计数器值(需包含 T6 位,见参数计算部分),使能要先进行一次喂狗 ,注意 使能与 循环函数中的喂狗操作不能间隔太近,否则会提前喂狗导致复位。 - 控制寄存器(CR):需设置使能位(WDGA,最高位)、计数器值(T6~T0)和溢出标志位等。
- 调用
- 主循环喂狗
- 调用
WWDG_SetCounter(0x54 | 0x40)定期向计数器写入值,确保计数器值在窗口范围内(即大于窗口值且未超时)。
- 调用
参数计算
超时时间

窗口时间

注意与解决
-
问题现象
- 编译下载后程序持续复位,原因:
- 初始化时首次喂狗与主循环中第二次喂狗间隔过短(<30ms),触发 “喂狗过快” 复位。
- 编译下载后程序持续复位,原因:
-
解决方案
-
方案 1:将喂狗代码移至延时之后,确保两次喂狗间隔≥窗口时间(30ms)。
-
方案 2:通过标志位判断首次执行,首次使能时同步喂狗,后续循环单独喂狗:
static uint8_t isFirstRun = 1; if (isFirstRun) { WWDG_Enable(0x94); // 首次使能并喂狗 isFirstRun = 0; } else { WWDG_SetCounter(0x54); // 后续喂狗 }
-
窗口看门狗主要程序
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "key.h"
int main(void)
{
OLED_Init();
Key_Init();
OLED_ShowString(1, 1, "WWDG_RET or RET");
//判断是否是通过什么方式产生的复位
if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET)
{
OLED_ShowString(2, 1, "WWDG_SET");
Delay_ms(200);
OLED_ShowString(2, 1, " ");
Delay_ms(100);
//要手动清除标志位
RCC_ClearFlag();
}
else
{
OLED_ShowString(3, 1, "SET");
Delay_ms(200);
OLED_ShowString(3, 1, " ");
Delay_ms(100);
}
//下面为开启看门狗的操作
//开启看门狗时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
//看表格 要想 超时时间为50ms 窗口时间为 30ms 分频系数的选择只有8分频
WWDG_SetPrescaler(WWDG_Prescaler_8);
//设置窗口值 30ms T[5:0] - W[5:0] = 30 / ((1/ 36MHZ)*1000 * 4096 * 8) = 33
WWDG_SetWindowValue(0x40 | 21);
//使能窗口看门狗要先进行一次喂狗 设置超时时间 50ms
// T[5:0] + 1 = 50 / ((1/ 36MHZ)*1000 * 4096 * 8) = 55
WWDG_Enable(0x40 | 54);
while(1)
{
//按下按键 阻塞程序
Key_GetNum();
OLED_ShowString(4, 1, "FEED");
Delay_ms(20);
OLED_ShowString(4, 1, " ");
Delay_ms(15);
//在循环中设置时间 执行喂狗操作 喂狗 50ms
WWDG_SetCounter(0x40 | 54);
}
}
更多推荐



所有评论(0)