tags: [source-summary] type: source source: "尚硅谷嵌入式技术之STM32单片机(扩展篇)V1.0.0 — 看门狗章节 + 配套代码27~28" author: "尚硅谷研究院" date: 2026-07-15
用生活理解:看门狗就像社区里的保安——你得定时去保安亭刷卡(喂狗),证明你还在正常工作。如果你一直没来刷卡(程序跑飞/卡死),保安就拉响警报(系统复位)。IWDG 是独立供电的保安(不怕停电),WWDG 是严格规定只能在特定时间窗口内刷卡的保安。
嵌入式系统运行中可能因电磁干扰、电源波动、软件 bug 等原因导致程序跑飞或死循环。看门狗可以在程序异常时自动复位系统,保证设备不会"死机"。
IWDG(Independent Watchdog)使用独立的 LSI 时钟(~40KHz),与主时钟独立——即使主时钟停振,IWDG 仍然工作。
LSI(~40KHz) → 8位预分频器 → 12位递减计数器(RL[11:0]) → 复位
↑
键寄存器(KRW)写 0xAAAA 重装
| 寄存器 | 功能 |
|---|---|
| KR (键寄存器) | 写 0xCCCC 启动、写 0xAAAA 喂狗、写 0x5555 允许写 PR/RLR |
| PR (预分频器) | 分频系数(3 位) |
| RLR (重装载寄存器) | 12 位重装值(0~4095) |
Tout = (RLR + 1) × 4 × 2^PR / LSI
LSI ≈ 40KHz
常见超时时间表(LSI=40KHz):
| PR[2:0] | 分频系数 | RLR=0xFFF(4095) | RLR=0xFFF(4095)+计算 | 分辨率 |
|---|---|---|---|---|
| 000 | 4 | 4096×4/40K = 0.41s | 0.1ms | |
| 001 | 8 | 4096×8/40K = 0.82s | 0.2ms | |
| 010 | 16 | 4096×16/40K = 1.64s | 0.4ms | |
| 011 | 32 | 4096×32/40K = 3.28s | 0.8ms | |
| 100 | 64 | 4096×64/40K = 6.55s | 1.6ms | |
| 101 | 128 | 4096×128/40K = 13.11s | 3.2ms | |
| 110 | 256 | 4096×256/40K = 26.21s | 6.4ms | |
| 111 | 256 | 4096×256/40K = 26.21s | 6.4ms |
示例:PR=011(分频32), RLR=1000
Tout = 1001 × 32 × 4 / 40000 = 3.2s
void IWDG_Init(void)
{
// 1. 写 0x5555 到 KR,允许修改 PR 和 RLR
IWDG->KR = 0x5555;
// 2. 设置预分频系数 = 32 (PR=011)
IWDG->PR = 3; // PR[2:0]=011
// 3. 设置重装值 = 1000 → Tout ≈ 3.2s (40KHz)
IWDG->RLR = 1000;
// 4. 写 0xCCCC 启动 IWDG
IWDG->KR = 0xCCCC;
// 5. 喂狗(必须在 3.2s 内执行一次,否则复位)
// 通常在 main 循环中调用
}
void IWDG_Feed(void)
{
IWDG->KR = 0xAAAA; // 写 0xAAAA 重装计数器
}
int main(void)
{
IWDG_Init(); // 启动看门狗
while (1)
{
// 主循环逻辑...
IWDG_Feed(); // 每 3s 内喂一次狗(Tout=3.2s)
// 如果程序卡死在此循环后面,3.2s 后系统复位
}
}
注意:IWDG 一旦启动无法停止,只能通过系统复位关闭。
WWDG(Window Watchdog)更加灵活——它要求必须在特定的时间窗口内喂狗:
| 特性 | 说明 |
|---|---|
| 时钟源 | APB1(36MHz),不是独立时钟 |
| 计数器 | 7 位递减(T[6:0],最大值 127) |
| 窗口上限 | 由 CFR 寄存器 W[6:0] 设定 |
| 喂狗时机 | 必须在 CNT > W[6:0] 且 CNT ≠ 0x3F 时喂狗 |
| 早期唤醒中断 (EWI) | CNT=0x40 时产生中断(可提前预警) |
窗口区(允许喂狗) 禁止区
CNT: 127 ← ... ← [W+1] ← ... ← 0x40 ← 0x3F → 复位
↑ ↑
最早喂狗时机 最晚喂狗时机
Tout = (CNT - W) × (PSC + 1) / APB1
WWDG 的最小喂狗间隔和最大喂狗间隔由 PSC 预分频系数和窗口值决定。
void WWDG_Init(void)
{
// 1. 开启 WWDG 时钟
RCC->APB1ENR |= RCC_APB1ENR_WWDGEN;
// 2. 设置预分频系数 = 8 (APB1=36MHz → CK=4.5MHz)
WWDG->CFR |= WWDG_CFR_WDGTB_1 | WWDG_CFR_WDGTB_0; // WDGTB[1:0]=11: /8
// 3. 设置窗口值 = 0x50(CNT 必须 < 0x50 才能喂狗,即最早喂狗点)
WWDG->CFR &= ~WWDG_CFR_W; // 清除窗口位域
WWDG->CFR |= (0x50 << 0);
// 4. 设置计数器初始值 = 0x7F(最大值)
WWDG->CR = 0x7F;
// 5. 使能窗口看门狗(WDGA=1)
WWDG->CR |= WWDG_CR_WDGA;
}
void WWDG_Feed(void)
{
// 必须在窗口内喂狗(CNT < W + 1)
WWDG->CR = 0x7F; // 重装计数器(必须在主循环写入此值)
}
void WWDG_IRQHandler(void)
{
if (WWDG->SR & WWDG_SR_EWIF) // 早期唤醒中断
{
// 距离复位还有 0x40 个计数周期,赶紧处理紧急事务
// 注意:在 ISR 中不能喂狗!
WWDG->SR = 0x00; // 清标志
}
}
| 对比项 | IWDG | WWDG |
|---|---|---|
| 时钟源 | LSI (~40KHz) 独立 | APB1(依赖主时钟) |
| 计数器 | 12 位递减 | 7 位递减 |
| 超时范围 | ~0.1ms ~ 26s | ~0.1ms ~ 若干 ms |
| 喂狗窗口 | 无窗口(任意时间喂即可) | 有窗口:太早太晚都复位 |
| 可停止 | ❌ 启动后不可停 | ✅ 可通过软件停止 |
| 中断 | ❌ 无 | ✅ 有 EWI 早期唤醒中断 |
| 独立供电 | ✅ 完全独立 | ❌ 依赖主电源 |
| 选型建议 | 需要高可靠性、长时间定时的系统 | 需要精确检测程序执行时序的系统 |
// HAL 库使用 IWDG_HandleTypeDef
IWDG_HandleTypeDef hiwdg;
hiwdg.Instance = IWDG;
hiwdg.Init.Prescaler = IWDG_PRESCALER_32; // PR=011: 分频32
hiwdg.Init.Reload = 1000; // RLR=1000
HAL_IWDG_Init(&hiwdg); // 相当于 KR=0xCCCC 启动
// HAL 库喂狗
HAL_IWDG_Refresh(&hiwdg); // 相当于 KR=0xAAAA
WWDG_HandleTypeDef hwwdg;
hwwdg.Instance = WWDG;
hwwdg.Init.Prescaler = WWDG_PRESCALER_8; // WDGTB=11
hwwdg.Init.Window = 0x50; // 窗口值
hwwdg.Init.Counter = 0x7F; // 计数值初始值
hwwdg.Init.EWIMode = WWDG_EWI_ENABLE; // 使能早期唤醒中断
HAL_WWDG_Init(&hwwdg);
// HAL 库喂狗(就在主循环更新 CR 值)
HAL_WWDG_Refresh(&hwwdg); // 相当于 CR=0x7F
// HAL WWDG 早期唤醒中断回调
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
{
// 距离 WWDG 复位还剩 64 个计数周期,执行紧急备份
}
| IWDG 操作 | 寄存器 | HAL 库 |
|---|---|---|
| 启动 | KR = 0xCCCC |
HAL_IWDG_Init() |
| 喂狗 | KR = 0xAAAA |
HAL_IWDG_Refresh() |
| 配置 | 先 KR = 0x5555 |
通过 Init 结构体 |
| WWDG 操作 | 寄存器 | HAL 库 |
|---|---|---|
| 启动 | `CR | = WDGA` |
| 喂狗 | CR = 0x7F |
HAL_WWDG_Refresh() |
| 配窗口 | CFR.W = value |
Init.Window = value |
| EWI 回调 | 手动中断函数 | HAL_WWDG_EarlyWakeupCallback() |