在嵌入式系统中,看门狗(Watchdog Timer, WDG) 是保障系统可靠性的“安全卫士”。当程序因干扰跑飞、死循环或硬件异常导致“卡死”时,看门狗能自动复位芯片,让系统恢复到正常状态。STM32F103C8T6(“小蓝板”)内置了两种看门狗:独立看门狗(IWDG) 和 窗口看门狗(WWDG),分别适用于不同场景。
一、看门狗的作用与分类
- 为什么需要看门狗?
嵌入式系统运行时可能遇到以下异常:
• 软件跑飞:代码逻辑错误导致程序跳转到非法地址(如数组越界、未初始化的函数指针调用)。
• 死循环:任务卡在某个循环中无法退出(如等待一个永远不触发的事件)。
• 硬件干扰:电磁干扰(EMI)或电源波动导致程序计数器(PC)异常。
看门狗通过定时计数机制监控程序运行状态:若在设定时间内未收到“喂狗信号”(即重置看门狗计数器),则认为系统异常,自动触发复位(Reset),强制重启芯片。
- STM32F103C8T6的两种看门狗
看门狗类型 名称 时钟源 特点 典型应用场景
独立看门狗(IWDG) Independent Watchdog 内部低速时钟(LSI,约40kHz) 不受主程序控制,完全独立运行;超时时间可配置(最大约26秒);复位整个芯片 防止系统整体崩溃(如主循环死循环)
窗口看门狗(WWDG) Window Watchdog APB1时钟(通常72MHz) 计数器有“窗口限制”(只能在特定时间窗口内喂狗);超时可配置(最大约86ms);复位整个芯片 监控关键任务执行时序(如中断服务函数必须按时完成)
关键区别:
-
IWDG是“傻瓜式”保护,只要超时未喂狗就复位;WWDG是“智能式”保护,必须在规定时间窗口内喂狗,否则复位。
-
IWDG的时钟(LSI)不稳定(误差±10%),适合对时间精度要求不高的场景;WWDG的时钟(APB1)稳定,适合精确时序监控。
二、独立看门狗(IWDG)实战:防止主循环卡死
- IWDG核心原理
• 时钟源:内部低速时钟(LSI),频率约40kHz(实际范围30~60kHz,受温度/电压影响,标准库中通常按40kHz计算)。
• 计数器:12位递减计数器(值范围0xFFF~0x000),当计数器减到0时触发复位。
• 预分频器(Prescaler):将LSI时钟分频,降低计数频率(可选4/8/16/64/128/256分频)。
• 喂狗操作:通过写入密钥0xAAAA(重载计数器值)和0xCCCC(启动IWDG)控制,实际标准库封装了简化接口。
超时时间公式:
超时时间 = (4 × 2^PR × RL) / LSI频率
其中:PR为预分频系数(4/8/16/64/128/256),RL为重装载值(0xFFF~0x000),LSI≈40kHz。
例如:PR=64(分频后频率=40kHz/64≈625Hz),RL=0xFFF(4095),则超时时间≈(4×2^6×4095)/40000 ≈ (4×64×4095)/40000 ≈ 26.2秒(最大值)。
- 标准库配置步骤与代码
(1)初始化IWDG(设置预分频和重装载值)
#include "stm32f10x.h"
#include "stm32f10x_iwdg.h"
// 初始化独立看门狗:预分频64,重装载值4095(约1秒超时)
void IWDG_Init(void) {
// 启动独立看门狗(内部LSI时钟自动开启,无需手动配置)
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); // 允许写入IWDG寄存器(密钥操作)
IWDG_SetPrescaler(IWDG_Prescaler_64); // 预分频64(40kHz/64≈625Hz)
IWDG_SetReload(4095); // 重装载值=4095(计数器从4095递减到0)
IWDG_ReloadCounter(); // 立即重载计数器(避免初始化后立刻复位)
IWDG_Enable(); // 启动IWDG
}
(2)喂狗操作(在主循环中定期调用)
// 喂狗函数(重载计数器值,复位倒计时)
void IWDG_Feed(void) {
IWDG_ReloadCounter(); // 写入0xAAAA等效操作(标准库封装为直接重载)
}
(3)主函数示例(模拟正常任务+喂狗)
int main(void) {
IWDG_Init(); // 初始化IWDG(约1秒超时)
while (1) {
// 模拟正常任务(例如读取传感器、控制外设)
printf("系统正常运行...\r\n"); // 需确保串口已初始化(仅示例)
// 关键:必须在超时时间内喂狗(例如每500ms喂一次,远小于1秒超时)
IWDG_Feed();
delay_ms(500); // 假设任务周期500ms(自定义延时函数)
}
}
注意事项:
-
若主循环因死循环卡住,超过1秒未调用IWDG_Feed(),IWDG计数器减到0,芯片自动复位。
-
实际项目中需根据任务最坏执行时间(WCET)设置合理的超时时间(例如任务最慢100ms完成一次循环,则超时时间设为200ms)。
三、窗口看门狗(WWDG)实战:监控关键任务时序
- WWDG核心原理
• 时钟源:APB1时钟(通常72MHz),计数器递减频率稳定(误差极小)。
• 计数器:7位递减计数器(值范围0x40~0x7F,初始值由用户配置)。
• 窗口限制:计数器必须在窗口上限(W[6:0])和窗口下限(0x40)之间喂狗。
• 若在窗口上限之前喂狗(过早),触发复位(防止任务提前完成)。
• 若在窗口下限之后喂狗(过晚,计数器减到0x3F时),触发复位(防止任务超时)。
• 预分频器:可选1/2/4/8分频(进一步调整计数频率)。
超时时间公式:
最大超时时间(窗口下限喂狗) = (4096 × 4^WDGTB × (0x7F - 0x40)) / APB1频率
其中:WDGTB为预分频系数(0=1分频,1=2分频,2=4分频,3=8分频),APB1通常为72MHz。
例如:WDGTB=0(1分频),预装载值=0x7F(127),则计数器从127递减到0x40(64)为合法窗口,超时时间≈(4096×1×(127-64))/72000000 ≈ 0.00035秒(约0.35ms,实际需结合预装载值调整)。
更直观的配置:通常设置预装载值=0x7F(最大),窗口值=0x60(例如),则合法喂狗时间为计数器值在0x60~0x7F之间(约几十毫秒)。
- 标准库配置步骤与代码
(1)初始化WWDG(设置预分频、窗口值、计数器初始值)
#include "stm32f10x.h"
#include "stm32f10x_wwdg.h"
// 初始化窗口看门狗:预分频8,窗口值0x60,计数器初始值0x7F(约78ms超时窗口)
void WWDG_Init(void) {
// 启动窗口看门狗(APB1时钟自动使用,无需手动配置)
WWDG_SetPrescaler(WWDG_Prescaler_8); // 预分频8(72MHz/8=9MHz,计数频率=9MHz/4096≈2.19kHz)
WWDG_SetWindowValue(0x60); // 窗口上限值=0x60(计数器必须>0x60才能喂狗)
WWDG_Enable(0x7F); // 初始计数器值=0x7F(启动WWDG),同时使能
}
// 喂狗函数(必须在窗口内调用!)
void WWDG_Feed(void) {
WWDG_SetCounter(0x7F); // 重载计数器为0x7F(必须在窗口内操作)
}
(2)主函数示例(模拟关键任务+合法喂狗)
int main(void) {
WWDG_Init(); // 初始化WWDG(窗口值0x60,计数器0x7F)
while (1) {
// 模拟关键任务(例如中断服务函数或定时任务)
printf("执行关键任务...\r\n"); // 需确保任务在窗口期内完成
// 关键:必须在计数器值>0x60时喂狗(例如每50ms喂一次,假设窗口允许)
WWDG_Feed();
delay_ms(50); // 假设任务周期50ms(需小于窗口时间)
}
}
注意事项:
-
喂狗时机必须严格控制在窗口内!若在计数器值≤0x60时喂狗(过早),或计数器值减到0x3F后喂狗(过晚),都会触发复位。
-
实际项目中需通过实验确定窗口值和喂狗周期(例如用逻辑分析仪监测WWDG计数器值)。
四、IWDG与WWDG的选择与对比
特性 独立看门狗(IWDG) 窗口看门狗(WWDG)
时钟源 内部低速时钟(LSI,约40kHz,不稳定) APB1时钟(通常72MHz,稳定)
超时时间范围 几毫秒~约26秒(灵活) 几十毫秒~约86ms(较精确)
喂狗限制 无窗口限制(任何时间喂狗均可) 必须在特定时间窗口内喂狗(过早/过晚均复位)
适用场景 防止主循环整体卡死(如死循环、任务调度失败) 监控关键任务的执行时序(如中断服务函数必须在规定时间内完成)
复位影响 复位整个芯片 复位整个芯片
选择建议:
-
如果只需要防止系统整体崩溃(如主循环死循环),用IWDG(配置简单,不依赖外部时钟)。
-
如果需要确保某个关键任务(如传感器数据采集、电机控制中断)按时执行,用WWDG(精确控制时序)。
五、常见问题与调试技巧
- IWDG不复位?
• 检查LSI是否启用:IWDG依赖LSI时钟(标准库中IWDG_WriteAccessCmd会自动开启LSI,无需手动配置)。
• 确认喂狗周期:若喂狗过于频繁(如每10ms喂一次),超时时间需设置更短(减小RL值或增大PR分频)。
• 调试时禁用IWDG:开发阶段可通过注释IWDG_Enable()暂时关闭看门狗,避免频繁复位影响调试。
- WWDG误复位?
• 检查喂狗时机:确保在计数器值>窗口值(如0x60)时喂狗(可通过逻辑分析仪监测WWDG计数器)。
• 调整窗口值:若任务执行时间不稳定,适当增大窗口值(如从0x60改为0x70),延长合法喂狗时间窗口。
- 调试工具推荐
• 逻辑分析仪:监测IWDG/WWDG的计数器值或复位信号(如使用Saleae、DSView)。
• 串口打印:在喂狗函数中添加打印(需确保串口初始化不被看门狗影响)。
六、总结
STM32F103C8T6的两种看门狗(IWDG和WWDG)是保障系统可靠性的关键外设:
• 独立看门狗(IWDG):简单可靠,适合防止系统整体崩溃(如主循环死循环),配置灵活但时钟不稳定。
• 窗口看门狗(WWDG):精确控制时序,适合监控关键任务的执行窗口(如中断服务函数超时),依赖APB1时钟但限制严格。
实践建议:
- 在正式项目中,至少启用一种看门狗(推荐IWDG作为基础保护)。
- 通过实际测试调整超时时间或窗口值,确保既不会误复位,也不会因超时过长导致系统长时间卡死。
- 结合日志或指示灯(如复位后LED闪烁特定次数),快速定位复位原因。