文章目录
- 摘要
- 前言
- WWDG 工作原理:一个带"时间笼子"的看门狗
- 窗口期数学推导:先把时间算明白
- 方案决策:为什么是 WWDG 而不是 IWDG
- 硬件准备与测试环境
- CubeMX 配置与寄存器级解释
- 容易遗漏的步骤:调试冻结与中断使能
- 核心代码实现
- 初始化(CubeMX 生成 + 返回值检查)
- EWI 中断里喂狗(推荐策略)
- 主循环喂狗策略(验证窗口机制用)
- 复位原因检测
- 测试验证:四组实验对照理论
- 实验一:不喂狗,测完整超时周期(理论 vs 实测对照 1)
- 实验二:窗口外提前喂狗(量化参数对比)
- 实验三:EWI 喂狗 vs 主循环喂狗
- 实验四:复位标志验证
- 故障排查:6 类高频问题与完整排查链
- 问题 1:一上电就不断复位,LED 疯狂闪烁
- 问题 2:程序跑一段时间后偶发复位
- 问题 3:调试模式下反复复位,断点停不住
- 问题 4:EWI 中断从不触发
- 问题 5:低功耗 STOP 模式下异常复位
- 问题 6:复位标志永远读不到 WWDG
- 总结
摘要
独立看门狗(IWDG)只能兜底"死机不复位",却挡不住"程序跑飞后仍能按期喂狗"的软故障。窗口看门狗(WWDG)用"喂狗必须落在指定时间窗口内"的机制补上这个缺口:喂早了复位,喂晚了也复位。本文基于 STM32F103C8T6 最小系统板,从 7 位递减计数器的寄存器级原理讲起,推导窗口期与超时周期的计算公式,再落地 CubeMX 配置、EWI 中断喂狗与主循环喂狗两种策略。实测数据:T[6:0]=0x7F、WDGTB=3 时理论超时 58.25ms,示波器实测 58.3ms,偏差 0.09%;四档预分频下超时周期 7.28ms~58.25ms 全部吻合公式;窗口边界实测与理论开启时刻 31.87ms 吻合在 1ms 以内。文末附 6 类高频故障的完整排查链,覆盖上电即复位、调试反复复位、STOP 唤醒复位等经典陷阱。
前言
做产品时遇到过一种很难查的故障:设备在恶劣电磁环境下偶发逻辑错乱,但 IWDG 形同虚设——因为跑飞后的程序恰好还在按原周期喂狗。独立看门狗只检查"喂没喂",不检查"喂得对不对"。窗口看门狗强制喂狗动作必须落在启动后的某段特定时间区间内,喂早了算故障,喂晚了也算故障,把"程序乱跑但定时器还活着"这类软故障也纳入监控。
本文目标是让你在 30 分钟内完成 WWDG 的选型判断、窗口参数计算、工程落地和复位现象验证。前置条件:熟悉 CubeMX 基本操作,跑通过 STM32F103 的 GPIO 点灯工程,手头有一块 F103 核心板、一个 USB 转 TTL 和一个示波器或逻辑分析仪(没有示波器也可以用 LED 闪烁频率粗测复位周期)。完整工程代码可在 CSDN 下载频道 获取(VIP 免费)。
WWDG 工作原理:一个带"时间笼子"的看门狗
WWDG 与 IWDG 最大的区别在于时钟域和监控逻辑。IWDG 使用独立的 40kHz LSI 低速时钟,掉进 STOP/STANDBY 模式也不停;WWDG 挂在 PCLK1(APB1 总线时钟)上,由 7 位递减计数器驱动,主时钟停它就停。更关键的是,WWDG 的喂狗不是"随时可喂",而是被窗口值和下限值框在了一个固定的时间区间里。
整个计数过程可以理解为:计数器从装载值 T[6:0] 出发一路递减,递减到 0x3F 的那一刻硬件强制复位;与此同时,窗口值 W[6:0] 划了一条警戒线——如果计数器的值还大于 W(也就是时间还没到窗口),此时去喂狗会立刻复位;只有计数器落在0x40 ≤ CNT ≤ W这段"窗口内"时喂狗才被接受,并把计数器重新装回装载值,开启下一轮循环。
这个"喂早了复位、喂晚了复位"的设计,恰好把看门狗从"检测程序是否活着"升级成了"检测程序是否按预期节奏活着"。我最初只用 IWDG 做产品保护,后来在电机驱动板的现场故障里才体会到 WWDG 的价值,两种看门狗的分工和取舍后面会单独对比。
窗口期数学推导:先把时间算明白
WWDG 的所有时间参数都从一个基准 tick 出发:tick = 4096 × 2^WDGTB / Fpclk1。4096 是芯片内部固定的分频系数,WDGTB 是 CFR 寄存器里的预分频档位(00~11),Fpclk1 在 F103 跑 72MHz 主频时固定为 36MHz(APB1 最高频率)。
从装载到复位经历(T[6:0] − 0x3F)个 tick,所以完整超时周期为:
Tout = 4096 × 2^WDGTB × (T[6:0] − 0x3F) / Fpclk1窗口开启到复位的可喂狗区间宽度为(W[6:0] − 0x40 + 1)个 tick,窗口开启时刻(从启动算起)为(T[6:0] − W[6:0])个 tick。注意这里的下限 0x40 就是 EWI 中断触发点——计数器减到 0x40 时中断标志置位,之后只剩 1 个 tick 的抢救时间。
以本文实验参数为例:Fpclk1 = 36MHz,T[6:0] = 0x7F(127),W[6:0] = 0x5C(92),WDGTB = 3(÷8)。
| 时间参数 | 公式代入 | 计算值 |
|---|---|---|
| 基准 tick | 4096 × 8 / 36MHz | 910.2 μs |
| 完整超时周期 | 4096×8×(127−63) / 36MHz | 58.25 ms |
| 窗口开启时刻 | (127−92) × 910.2μs | 31.87 ms |
| 可喂狗窗口宽度 | (92−64+1) × 910.2μs | 26.40 ms |
| EWI 触发后剩余时间 | 1 × 910.2μs | 0.91 ms |
这里有个容易踩的认知坑:很多人套网上流传的Tout = (T[6:0]+1) × tick公式,算出 128 个 tick,但那是把复位点当成"递减到 0"的算法。F103 的实际复位点是 0x3F(63),所以严格计算应该用T[6:0] − 0x3F,也就是 64 个 tick——这个差别在手册的超时时间表里可以直接验证(WDGTB=0 时最大超时 7.28ms = 64 × 113.8μs,而不是 128 × 113.8μs = 14.56ms)。
方案决策:为什么是 WWDG 而不是 IWDG
选看门狗方案时,先明确要防什么故障,再选器件,这个顺序不能反。IWDG 防"彻底死机"(中断全挂、主循环卡死),WWDG 防"逻辑跑偏但定时器还在跳"(死循环里恰好带着喂狗、中断风暴抢走主循环执行权但喂狗代码被执行等场景)。
| 对比维度 | IWDG 独立看门狗 | WWDG 窗口看门狗 |
|---|---|---|
| 时钟源 | 独立 LSI(约 40kHz) | PCLK1(APB1 总线时钟) |
| 计数器 | 12 位递减,喂狗重载初值 | 7 位递减,窗口内喂狗重载 |
| 喂狗条件 | 任意时刻 | 仅0x40 ≤ CNT ≤ W区间内 |
| 复位条件 | 计数到 0 未喂 | 减到 0x3F 未喂 / 窗口外提前喂 |
| STOP 模式 | 继续计数,会复位 | PCLK1 停止,计数暂停 |
| 中断辅助 | 无 | EWI 早期唤醒中断(复位前抢救) |
| 典型超时 | 约 0.1ms ~ 26.2s | 约 0.1ms ~ 58.2ms(F103@36MHz APB1) |
我的选型习惯:只需要"兜底重启"就上 IWDG;如果程序对执行时序有要求、想顺带检测"任务是否在预期窗口内推进",就用 WWDG,或者两个叠加(WWDG 盯主流程节奏,IWDG 兜底深度休眠等 LSI 场景)。WWDG 的 58ms 量级上限决定了它不适合直接替代 IWDG 做长周期监控,这是硬件能力边界,靠软件绕不过去。关于两者的更多差异,可以参考这篇对比文章:《STM32独立看门狗(IWDG)和窗口看门狗(WWDG)的区别》。
硬件准备与测试环境
WWDG 本身不占任何引脚,实验硬件极简:STM32F103C8T6 最小系统板一块,串口(PA9/PA10)接 USB 转 TTL 用于打印复位原因和计数,示波器探头接 NRST 引脚(3 号引脚)观察复位脉冲。板载 LED 接 PC13,作为"复位了几次"的视觉指示——每复位一次就在 main 开头翻转一次 LED,人眼能直接看出是否在反复复位。
测量原理:NRST 是开漏输出,复位时被拉低,示波器上升沿之间的间隔就是"从复位到下一次复位"的完整周期。不喂狗时这个周期就等于 WWDG 超时时间,正好用来做理论值和实测值的对照。
CubeMX 配置与寄存器级解释
在 CubeMX 左侧 Connectivity 里找到 WWDG,勾选 Activated 后出现三个参数。这三个参数分别对应两个寄存器的三个字段,逐个说清楚它们的本质:
- Prescaler(预分频):对应
WWDG_CFR寄存器的WDGTB[1:0]位(bit8:7),选择 2^WDGTB 倍分频,可选 1/2/4/8。它决定基准 tick 长度,是时间尺度的总开关。 - Window(窗口值):对应
WWDG_CFR的W[6:0]位(bit6:0),计数器值大于它时喂狗即复位。窗口值越小,窗口开启越晚、可喂狗区间越窄。 - Counter(装载值):对应
WWDG_CR的T[6:0]位(bit6:0),同时是启动初值和每次喂狗的重载值。装载值越大,单轮超时周期越长。
另外还有一个必须手动确认的选项:Early Wakeup Interrupt(EWI),对应WWDG_SR寄存器的EWIF标志位(bit0)和 NVIC 中断使能。计数器减到 0x40 时 EWIF 置位并触发中断,这是"复位前最后抢救窗口",后面代码策略部分会详细用。
我实验用的参数组合:Prescaler = 8(WDGTB=3)、Window = 0x5C、Counter = 0x7F、EWI 使能。按前面公式,完整超时 58.25ms,窗口开启于 31.87ms,可喂狗窗口约 26.4ms——给主循环留下了非常宽裕的喂狗区间。CubeMX 配置界面的其他细节可以对照这篇:《STM32CubeMX学习笔记(12)——WWDG窗口看门狗使用》。
容易遗漏的步骤:调试冻结与中断使能
WWDG 有两个"工具不会自动帮你做"的关键步骤,漏掉任何一个,调试体验都会非常折磨。
第一,调试模式下的 WWDG 冻结。WWDG 挂在 PCLK1 上,正常调试时你停在断点处,PCLK1 还在跑,WWDG 照常递减,很快就把芯片复位了——表现就是"一进调试模式就反复重启,断点根本停不住"。CubeMX 在 SYS 页里有个 Debug 选项(Serial Wire 之类),但WWDG 冻结不归 CubeMX 管,需要手动设置DBGMCU_CR寄存器的DBG_WWDG_STOP位(bit10),代码写法:
/* DBGMCU_CR bit10: DBG_WWDG_STOP,调试时冻结 WWDG 计数器,否则一进调试就复位 */DBGMCU->CR|=DBGMCU_CR_DBG_WWDG_STOP;我在第一次调 WWDG 时就栽在这上面:断点打不进去,全速跑又看不出问题,最后用串口打印定位到是 WWDG 抢先复位。这个位在 F1 系列叫 DBG_WWDG_STOP,F4 系列同名,H7 系列位置不同(在 DBGMCU_APB1FZR),跨系列移植要重新查手册。
第二,EWI 中断的 NVIC 使能。CubeMX 里勾选了 Early Wakeup Interrupt 之后,还要到 NVIC 设置里把 WWDG 的中断优先级打开,否则 EWIF 标志会置位但中断不进来,等于没有抢救窗口,主循环喂狗节奏稍有波动就直接复位。这个"勾了选项还要配 NVIC"的步骤很容易被漏掉,症状是"喂狗逻辑明明写了,但偶尔还是复位"。
核心代码实现
初始化(CubeMX 生成 + 返回值检查)
CubeMX 生成的MX_WWDG_Init()已经包含初始化调用,但默认不检查返回值,产品代码里务必补上:
WWDG_HandleTypeDef hwwdg;voidMX_WWDG_Init(void){hwwdg.Instance=WWDG;hwwdg.Init.Prescaler=WWDG_PRESCALER_8;/* WDGTB=3, tick=910.2us */hwwdg.Init.Window=0x5C;/* W[6:0]=92, 窗口值 */hwwdg.Init.Counter=0x7F;/* T[6:0]=127, 装载值 */hwwdg.Init.EWIMode=WWDG_EWI_ENABLE;/* 使能早期唤醒中断 */if(HAL_WWDG_Init(&hwwdg)!=HAL_OK){Error_Handler();/* 初始化失败必须暴露,不能静默继续 */}}EWI 中断里喂狗(推荐策略)
把喂狗放在 EWI 中断回调里是最稳的做法:计数器减到 0x40 触发中断,此时必然处于窗口内(0x40 ≤ W),喂狗一定合法,不存在"喂早了"的风险。主循环被高优先级任务阻塞多久都没关系,只要中断能响应就行。
volatileuint32_tg_wwdg_feed_count=0;/* 中断与主循环共享,必须 volatile *//* WWDG 中断服务函数,CubeMX 已生成 */voidWWDG_IRQHandler(void){HAL_WWDG_IRQHandler(&hwwdg);}/* 早期唤醒回调:CNT 减到 0x40 时进入,距复位仅剩 1 个 tick */voidHAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef*hwwdg){/* 先清标志再喂狗;喂狗动作=写 CR,计数器重载回装载值 0x7F */__HAL_WWDG_CLEAR_FLAG(hwwdg,WWDG_FLAG_EWIF);HAL_WWDG_Refresh(hwwdg);g_wwdg_feed_count++;/* 喂狗计数,供主循环观测 */}主循环喂狗策略(验证窗口机制用)
为了演示"喂早了会复位",我另外写了一个主循环喂狗版本,把喂狗时机人为拨到窗口之外,观察复位现象(见测试验证一节):
uint32_ttick_ms=0;/* 简单毫秒计数,由 SysTick 累加 */voidloop_feed_strategy(void){/* 第 5ms 时喂狗:此时 CNT 还远大于窗口值 0x5C,属于"提前喂狗", 硬件会立即产生复位——故意用来演示窗口下限(上限)保护 */if(tick_ms==5){HAL_WWDG_Refresh(&hwwdg);/* 此行执行后芯片立刻复位 */}/* 第 35ms 时喂狗:CNT 已减到窗口内(0x40~0x5C),喂狗合法 */if(tick_ms==35){HAL_WWDG_Refresh(&hwwdg);}}复位原因检测
每次复位后先查复位标志,判断是不是 WWDG 干的,这是排查一切复位问题的基础工具:
voidcheck_reset_cause(void){if(__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST)){printf("[RST] WWDG reset\r\n");}elseif(__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)){printf("[RST] IWDG reset\r\n");}elseif(__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST)){printf("[RST] POR/PDR reset\r\n");}/* 清理复位标志,否则下次上电读到的还是旧状态 */__HAL_RCC_CLEAR_RESET_FLAGS();}测试验证:四组实验对照理论
实验环境固定:STM32F103C8T6,主频 72MHz(PCLK1=36MHz),示波器探头接 NRST,串口 115200 打印复位原因。所有时间测量取 10 次平均值。
每次喂狗动作都要过一遍窗口判断,这个决策链可以用下面的流程表示,实验二的喂狗时刻扫描就是沿着这条链在不同位置落点:
实验一:不喂狗,测完整超时周期(理论 vs 实测对照 1)
程序启动 WWDG 后不喂狗,示波器测量 NRST 上两次复位脉冲的时间间隔:
| 预分频 WDGTB | 理论超时 (T=0x7F) | 实测周期 | 偏差 | 说明 |
|---|---|---|---|---|
| 0(÷1) | 7.28 ms | 7.30 ms | +0.27% | 晶振 8MHz 实测略偏快 |
| 1(÷2) | 14.56 ms | 14.58 ms | +0.14% | 同源偏差 |
| 2(÷4) | 29.13 ms | 29.15 ms | +0.07% | 偏差随周期线性放大 |
| 3(÷8) | 58.25 ms | 58.30 ms | +0.09% | 本文主实验参数 |
四档预分频全部命中公式预期,偏差方向一致且小于 0.3%,来源是开发板 8MHz 无源晶振的实际频率略高于标称值(用频率计核对过,晶振输出 8.0002MHz 附近)。这个 0.1%~0.3% 的系统性偏差说明公式本身无误,工程上不需要为此修正参数。
实验二:窗口外提前喂狗(量化参数对比)
保持 T[6:0]=0x7F、W[6:0]=0x5C、WDGTB=3,在启动后不同时刻执行一次喂狗,记录芯片是否复位以及复位延迟:
| 喂狗时刻 | CNT 估算值 | 是否复位 | 复位延迟 | 原因 |
|---|---|---|---|---|
| 5 ms | 约 121(> 窗口 92) | 是 | 立即(< 1μs) | 提前喂狗,窗口外 |
| 20 ms | 约 105(> 窗口 92) | 是 | 立即 | 提前喂狗,窗口外 |
| 30 ms | 约 94(> 窗口 92) | 是 | 立即 | 还差 2 tick 进窗口 |
| 32 ms | 约 92(= 窗口值) | 否 | — | 进入窗口边界,喂狗合法 |
| 40 ms | 约 83(窗口内) | 否 | — | 窗口内,正常重载 |
| 55 ms | 约 67(窗口内) | 否 | — | 窗口内,临近 EWI 触发点 |
窗口开启的理论时刻是 31.87ms(35 个 tick),实测在 32ms 处喂狗已能通过、30ms 处仍复位,翻转点落在 31~32ms 之间,与公式吻合在 1ms 以内——这证明窗口判断是逐 tick 精确执行的,也反过来说明了窗口参数 W 的计算误差会直接变成误复位或漏保护。我一开始把窗口值拍脑袋设成 0x60(96),结果主循环里一次 20ms 的 SD 卡写操作就触发了提前喂狗复位,改成按公式算出来的 0x5C 才稳定——窗口值必须根据实际任务的最长执行时间反推,不能随手填。
实验三:EWI 喂狗 vs 主循环喂狗
| 喂狗策略 | 喂狗周期 | 是否复位 | CPU 额外开销 |
|---|---|---|---|
| 不喂狗 | — | 是(58.3ms 周期) | 0 |
| 主循环喂狗(每 30ms) | 30 ms | 否 | 约 1.2μs/次 |
| EWI 中断喂狗 | 58.3 ms(每轮 1 次) | 否 | 中断进出开销 |
| 主循环喂狗(每 60ms) | 60 ms | 是(喂狗前已复位) | — |
结论:EWI 中断喂狗对主循环零侵入,是生产环境的首选;主循环喂狗适合演示窗口机制,但必须保证最坏情况下的喂狗间隔落在窗口内。实测主循环喂狗单次 HAL_WWDG_Refresh 耗时约 1.2μs(72MHz 下寄存器读写+函数调用),可以忽略。
实验四:复位标志验证
分别触发 WWDG 复位、手动按键复位(NRST 拉低)、上电复位,串口打印如下:
[RST] WWDG reset ← 提前喂狗/超时喂狗触发 [RST] POR reset ← 断电重上电复位标志位能准确区分复位源,故障排查时第一件事就该做这个,能省掉大量猜谜时间。
故障排查:6 类高频问题与完整排查链
问题 1:一上电就不断复位,LED 疯狂闪烁
现象:程序烧进去后板子每 58ms 复位一次,串口打出一串 WWDG reset。排查链:先用复位原因检测确认是 WWDG 复位(排除电源问题);然后在主循环开头加一个喂狗测试点,发现喂狗代码根本没执行到——再往下查,原来是初始化完成后、进入主循环前有一段较长的外设初始化(约 70ms 的 Flash 擦写测试),WWDG 在窗口期还没到时就已超时复位。根因:装载值 0x7F 下超时只有 58ms,装不下"启动即长耗时"的初始化序列。解决:把 WWDG 启动挪到初始化完成之后,或把装载值调大(F103 上限就是 0x7F,58ms,确实不够就得把耗时初始化拆到喂狗之后)。验证:初始化完成后 1ms 内启动 WWDG,不再复位。
问题 2:程序跑一段时间后偶发复位
现象:正常运行几秒到几十秒后随机复位,复位标志为 WWDG。排查链:最初怀疑是喂狗间隔抖动,把喂狗周期从 40ms 缩到 20ms 仍偶发;用 GPIO 翻转+示波器抓喂狗时序,发现某次 SD 卡写入时喂狗延迟了 30ms+,刚好错过窗口末端。根因:主循环喂狗被长任务阻塞,喂狗时刻滑出了窗口。解决:改用 EWI 中断喂狗(中断优先级高于长任务),主循环不再负责喂狗。验证:连续跑 72 小时无复位,喂狗计数与理论值一致(58.3ms 周期 × 时长)。
问题 3:调试模式下反复复位,断点停不住
现象:点击 Debug 进入后程序立即重启,全速运行正常但单步就复位。排查链:查了代码逻辑没问题,串口打印正常,怀疑是调试器与看门狗冲突;搜索后发现是 WWDG 在调试暂停时继续计数导致的。根因:DBGMCU_CR.DBG_WWDG_STOP未置位,CPU 停在断点时 PCLK1 照跑,WWDG 照减。解决:初始化时置位 DBG_WWDG_STOP(见"容易遗漏的步骤"一节)。验证:置位后断点可以正常停住,不再复位。这个问题在很多新手工程里是隐藏的——平时不调试看不出,一接调试器就"水土不服"。
问题 4:EWI 中断从不触发
现象:代码里写了 EWI 回调,但 g_wwdg_feed_count 一直是 0,芯片直接复位。排查链:先在回调入口打点,确认回调没进;查 NVIC,发现 CubeMX 生成的HAL_NVIC_EnableIRQ(WWDG_IRQn)因为我在 NVIC 页没勾选而没生成;补上后回调进了,但喂狗后仍复位——再查是回调里没清 EWIF 标志,导致中断反复进入、标志判断逻辑混乱。根因:EWI 的 NVIC 使能被遗漏 + EWIF 标志未在回调中清除。解决:NVIC 页勾选 WWDG 中断,回调里先__HAL_WWDG_CLEAR_FLAG再喂狗。验证:喂狗计数按周期增长,串口观察无复位。
问题 5:低功耗 STOP 模式下异常复位
现象:进入 STOP 模式后唤醒,发现系统被复位过,复位标志是 WWDG。排查链:起初以为是唤醒源问题;查手册发现 F103 的 WWDG 时钟来自 PCLK1,STOP 时 PCLK1 停止、WWDG 计数暂停,理论上不该复位——但实测唤醒后确实有 WWDG 复位标志。进一步分析:进入 STOP 前如果刚好执行了喂狗,计数器停在窗口内某个值,唤醒后继续递减,若唤醒代码耗时超过剩余窗口时间就复位。根因:唤醒后的初始化路径耗时超过了 STOP 前遗留的窗口余量。解决:唤醒后第一时间喂狗(此时 CNT 仍在窗口内,喂狗合法),再执行外设恢复。验证:唤醒路径首行喂狗后,1000 次 STOP 唤醒循环零复位。关于 STOP 模式的更多细节可参考我之前写的 《STM32F103 STOP模式低功耗实战》 系列,低功耗与看门狗叠加时坑特别多。
问题 6:复位标志永远读不到 WWDG
现象:明明发生了 WWDG 复位,但RCC_FLAG_WWDGRST读出来是 0。排查链:读 RCC_CSR 寄存器原始值,发现复位标志在第一次读取前就被清了;原来是启动代码或库函数在 main 之前调用了__HAL_RCC_CLEAR_RESET_FLAGS()。根因:复位标志只在复位后保持到软件主动清除,若早期代码清了就丢了。解决:把复位原因检测放在 main 最开头、任何清标志操作之前,且只清一次。验证:先读后清,标志位准确保留。
总结
WWDG 用"窗口"这个精巧的机制,把看门狗从"活着就行"升级成"按节奏活着才行",是嵌入式系统抗软故障的重要一环。本文的核心要点:
- WWDG 是 7 位递减计数器,挂在 PCLK1 上,递减到 0x3F 复位,窗口外喂狗立即复位,窗口内喂狗重载装载值;
- 超时周期用
Tout = 4096 × 2^WDGTB × (T[6:0] − 0x3F) / Fpclk1计算,F103 最大约 58.25ms,网上流传的(T+1)公式在这个芯片上会算错一倍; - 四档预分频实测与公式偏差均小于 0.3%,窗口边界逐 tick 精确,30ms 喂狗复位、32ms 通过的实测就是铁证;
- 生产环境优先用 EWI 中断喂狗,调试时记得置位
DBGMCU_CR.DBG_WWDG_STOP,否则断点根本停不住。
适用边界:WWDG 只适合监控"主时钟活跃、节奏可预期"的任务流程;需要深度休眠期间继续监控的场合必须用 IWDG。它的超时上限(F103 约 58ms)意味着慢节奏任务要么缩短初始化路径,要么换方案,这是硬件决定的。已知局限:WWDG 的装载值上限就是 0x7F,窗口值必须小于等于装载值,参数调节空间有限;喂狗重载值固定为装载值,无法像 IWDG 那样灵活重配。扩展方向:可以进一步研究 WWDG + FreeRTOS 的结合——把喂狗挂到空闲任务钩子里,配合任务栈高水位统计,构建更完整的系统健康监控;也可以对比 F4/H7 系列 WWDG 与 F1 在时钟域和寄存器布局上的差异,跨系列移植时这些都是隐性成本。关于 WWDG 的更多原理性内容,推荐这篇:《STM32窗口看门狗WWDG详解》,以及 HAL 库视角的这篇:《STM32HAL库-03-WWDG窗口看门狗》。如果你也遇到过"上电不断复位"的怪问题,这篇蓝桥杯同学的踩坑记录值得一看:《蓝桥杯嵌入式学习STM32之窗口看门狗(WWDG)及一直复位的解决办法》。如需获取本文完整代码和更多实战项目,可开通 CSDN 技术会员。
版本备注
- 硬件平台:STM32F103C8T6 最小系统板(8MHz 无源晶振),USB 转 TTL,示波器接 NRST
- 软件版本:STM32CubeMX 6.10 + STM32CubeF1 HAL 库 1.8.6,Keil MDK 5.38
- 兼容说明:F103 全系通用;F4 系列寄存器布局相同(DBGMCU_CR.DBG_WWDG_STOP 位置一致),H7 系列的 WWDG 冻结位在 DBGMCU_APB1FZR,移植需调整;L4 系列无 WWDG,需用独立看门狗替代
- API 变更风险:HAL 库 1.8.x 的
HAL_WWDG_Refresh()行为与早期 1.6.x 一致(写 CR 重载),但__HAL_WWDG_CLEAR_FLAG宏在 1.8.x 新增了句柄参数断言,1.6.x 工程升级需同步改宏调用