独立看门狗IWDG
156.9独立看门狗IWDG
/*
* 整体目的:启动 STM32F103 的独立看门狗,并用 KEY0 决定是否持续刷新;松开按键后
* 倒计时到零触发系统复位,复位后 LED0 再闪烁 500 ms 作为可见现象。
* 设计思路:LSI 经 64 分频驱动 12 位递减计数器,Reload=3125;主循环仅在 KEY0
* 读到低电平时喂狗,刷新会把重装载值重新装入计数器,而不是把它清零。
* 硬件依据:工程把 LED0 定义在 PB5、KEY0 定义在 PE4;LED0 低电平点亮,KEY0
* 低电平有效且 GPIO 配置为无内部上下拉,因此按键稳定性依赖板级外部电路。
* 时间依据:按标称 40 kHz LSI,超时约为 (3125+1)*64/40000=5.0016 s;LSI 实际
* 可能约为 30~60 kHz,不能把课堂现象当作精确 5 秒计时器。
* 执行效果:按住 KEY0 时循环反复刷新而不复位;松开约一个超时周期后 IWDG 复位 MCU,
* 程序重新初始化并让低电平有效的 LED0 再亮约 500 ms。
* 代码范围:摘录 CubeIDE/15IWDG 的 iwdg.c、main.c 与时钟关键代码,不展开 HAL 内部。
*/
/* Core/Src/iwdg.c:配套工程的实际 IWDG 配置。 */
IWDG_HandleTypeDef hiwdg; /* 定义全工程使用的独立看门狗 HAL 句柄。 */
void MX_IWDG_Init(void) /* 配置并启动 IWDG;启动后只能通过系统复位停止。 */
{ /* IWDG 初始化函数体开始。 */
hiwdg.Instance = IWDG; /* 将句柄绑定到芯片内部独立看门狗。 */
hiwdg.Init.Prescaler = /* 选择 LSI 到 IWDG 计数器之间的预分频系数。 */
IWDG_PRESCALER_64; /* 将标称 40 kHz 除以 64,得到约 625 Hz 计数频率。 */
hiwdg.Init.Reload = 3125U; /* 设置 12 位重装载值;3125 到 0 共经历 3126 个计数。 */
if (HAL_IWDG_Init(&hiwdg) != HAL_OK) /* 写入参数、启动并首次装载计数器,随后检查结果。 */
{ /* IWDG 初始化失败分支开始。 */
Error_Handler(); /* 进入工程统一错误处理;不要继续假定看门狗有效。 */
} /* IWDG 初始化状态判断结束。 */
} /* IWDG 初始化函数结束,看门狗已经开始倒计时。 */
/* main.c:IWDG 启动后,只有低电平有效的 KEY0 才持续刷新计数器。 */
MX_GPIO_Init(); /* 先配置 PB5/LED0 与 PE4/KEY0,确保实验引脚状态明确。 */
MX_IWDG_Init(); /* 启动独立看门狗;后续所有阻塞路径都必须短于超时上限。 */
HAL_GPIO_WritePin( /* 建立复位后可观察的 LED0 点亮状态。 */
LED0_GPIO_Port, /* 选择 LED0 所在的 GPIOB。 */
LED0_Pin, /* 选择 PB5 对应的 LED0 位。 */
GPIO_PIN_RESET); /* 输出低电平;本板 LED0 低电平点亮。 */
HAL_Delay(500U); /* 保持点亮约 500 ms,使每次复位都能被肉眼观察。 */
HAL_GPIO_WritePin( /* 结束上电或复位后的 LED 指示脉冲。 */
LED0_GPIO_Port, /* 仍操作 LED0 所在 GPIOB。 */
LED0_Pin, /* 仍只改变 PB5,不影响同端口其他引脚。 */
GPIO_PIN_SET); /* 输出高电平,让低电平有效的 LED0 熄灭。 */
while (1) /* 前台永久检查按键状态,等待喂狗或复位。 */
{ /* 主循环一轮开始。 */
if (HAL_GPIO_ReadPin( /* 读取 KEY0 当前逻辑电平。 */
KEY0_GPIO_Port, /* 选择 KEY0 所在的 GPIOE。 */
KEY0_Pin) == GPIO_PIN_RESET) /* PE4 为低表示按键有效;依赖板上的外部上拉。 */
{ /* KEY0 有效时进入刷新分支。 */
HAL_IWDG_Refresh(&hiwdg); /* 把 Reload 重新装入递减计数器,推迟复位。 */
} /* KEY0 无效时不刷新,让计数器继续减至 0。 */
} /* 返回循环顶部;若已超时,硬件复位会中断该流程。 */
/* SystemClock_Config():实际同时选择 HSE 系统时钟源和 IWDG 所需的 LSI。 */
RCC_OscInitStruct.OscillatorType = /* 声明本次需要配置的两个振荡器。 */
RCC_OSCILLATORTYPE_LSI | /* 选择片内低速 RC,作为 IWDG 的独立时钟。 */
RCC_OSCILLATORTYPE_HSE; /* 同时选择外部高速晶体,供系统主时钟链使用。 */
RCC_OscInitStruct.LSIState = RCC_LSI_ON; /* 明确启动 LSI,使 IWDG 在主时钟异常时仍能计数。 */
一、看门狗
看门狗的目的不是让程序“永不出错”,而是在软件没有按预期完成健康检查时把 MCU 拉回可控的复位起点。独立看门狗(IWDG)由片内低速内部 RC 振荡器 LSI 驱动,主系统时钟异常时仍可运行,因此特别适合处理死循环、任务卡死等故障。
原稿的“从 0 数到 100、到期产生复位中断”只是教学类比。STM32F1 的 IWDG 实际从重装载值向下计数至 0x000,随后产生的是硬件复位信号,而非进入可由用户编写 IWDG_IRQHandler 处理的普通中断。喂狗也不是把计数器写成零,而是把 IWDG_RLR 的重装载值重新装入计数器,使倒计时重新开始。
| 项目 | STM32F1 IWDG 的实际含义 |
|---|---|
| 时钟源 | 片内 LSI RC,数据手册标称 40 kHz,范围约 30--60 kHz |
| 计数方向 | 从重装载值递减,到 0x000 产生 IWDG 复位 |
| 计数器宽度 | 12 位,重装载值范围为 0--4095 |
| 启动后状态 | 软件或选项字节均可启动;一旦启动,除系统复位外不能关闭 |
| 喂狗动作 | HAL_IWDG_Refresh() 向键寄存器写入刷新键,将 Reload 装回计数器 |
超时近似公式为:
T_timeout = (Reload + 1) x Prescaler / f_LSI
这里的 +1 来自计数器从重装载值递减到零所经历的计数周期数。这个公式用于估算和选型;LSI 是 RC 振荡器,不能把标称频率误认为精密时基。
1.1 实验演示喂狗
- 配套工程先初始化 GPIO,再执行
MX_IWDG_Init()。HAL_IWDG_Init()会启动 IWDG、开放配置写入、写入预分频与重装载值,并在返回前刷新一次计数器;看门狗从这里开始计时。 - 板级信号在
main.h中定义为LED0 = PB5、KEY0 = PE4。GPIO 配置中 PB5 为推挽输出,PE4 为普通输入,均未启用片内上下拉。 - 初始化代码向 PB5 写低电平、延时 500 ms、再写高电平。课程现象中的“上电或复位时灯闪一下”来自这三行;它还表明该板 LED 是低电平点亮。这只描述此板连接方式,其他板的 LED 可能相反。
HAL_GPIO_ReadPin(PE4)返回低电平时才执行刷新。若 PE4 的按键电路确为“按下接地、松开由外部电阻上拉”,按住按键会在高速循环中反复喂狗;松开后约一个超时时间发生复位,随后再次执行 500 ms 闪灯。- 由于代码把 PE4 配成
GPIO_NOPULL,低电平有效依赖开发板已有的外部上拉和按键接地电路。工程中没有原理图,接线和电阻不能凭空假定;若改接自制按键,必须提供确定的上拉或下拉,悬空输入会随机读到 0/1。 - 该按键方案仅用于可见的课堂实验。产品中不应把“用户按着一个键”当作系统健康证明;应在所有关键任务都按时完成之后,才由集中位置刷新看门狗。否则程序即使卡在一个仍会执行
HAL_IWDG_Refresh()的错误循环里,也不会被复位。
1.2 窗口看门狗
独立看门狗只要求“在到期前刷新”,没有规定过早刷新会出错。窗口看门狗(WWDG)额外限定了允许刷新的时间窗,因此既能发现程序太久不运行,也能发现程序异常地跑得过快、过早刷新。
- 原稿以“从 0 向 100 上数”的示意说明窗口,这可用于直觉理解,但不是 STM32F1 WWDG 的寄存器计数方向。
- STM32F1 的 WWDG 使用 PCLK1 派生时钟并向下计数:计数器尚高于设定窗口值时刷新,属于过早刷新,会导致复位;当计数器继续递减到
0x3F以下时,也会复位。正确窗口是计数值已降至窗口值及以下、但仍高于下溢复位阈值的时段。 - WWDG 与 IWDG 的取舍:WWDG 的时钟依赖主时钟,窗口检测能力更强;IWDG 的 LSI 与主时钟独立,更适合主时钟失效或主程序整体卡死的恢复。两者都不是外部独立供电的监控芯片。
1.3 看门狗芯片
外部看门狗/复位监控芯片是 MCU 之外的独立器件。典型连接是 MCU 周期性翻转或脉冲驱动芯片的 WDI 输入,芯片的复位输出连接 MCU 的 NRST 或复位网络;在规定时间内没有有效边沿或电平变化时,芯片主动复位 MCU。
- 外部芯片的 WDI 触发方式、允许时间窗、复位输出极性与供电范围由具体型号决定,不能笼统认定“高电平、低电平或任意脉冲都可以”。
- 当内部时钟、片内看门狗配置或 MCU 自身状态不够可信时,外部监控能提供另一条监督链路;但它同样依赖正确的复位连接、供电设计和固件喂狗策略,不能替代电源完整性设计。
- 本节
15IWDG工程只使用 STM32 内部 IWDG,没有外置看门狗芯片的 GPIO 或原理图配置。
1.4 实验演示喂狗
- 该工程配置
IWDG_PRESCALER_64、Reload = 3125。按标称 LSI 40 kHz 计算,分频后为40 000 / 64 = 625 Hz,超时约为(3125 + 1) / 625 = 5.0016 s。原稿的“3125 对应正好 5 秒”忽略了一个计数周期,只能视作近似。 - 更重要的是 LSI 的数据手册范围约为 30--60 kHz。同一配置的理论超时约在
3.334--6.669 s之间,温度和电压也会影响 RC 频率。需要严格 5 秒的设计,应测量 LSI 并留出任务调度余量,或选用更适合的外部时基/监控方案。 - IWDG 没有 GPIO 输出脚,也不需要在 NVIC 中启用中断。LED 和按键是为了观察复位及决定是否刷新而添加的外围电路;IWDG 本身完全在芯片内部运行。
- 每次 IWDG 复位后,RCC 的
IWDGRSTF复位标志会被置位。当前示例没有读取该标志,所以只能从 LED 闪烁推测复位原因。实际调试应在启动早期记录复位标志,再按芯片手册清除,区分上电、外部复位、软件复位和 IWDG 复位。 - 调试暂停时,IWDG 可能继续倒计时并导致程序在断点处复位。F1 HAL 提供冻结/解冻 IWDG 的调试宏;它适合临时调试,不应被当作生产环境的失效保护策略。
二、总结
- IWDG 的核心链路是:LSI 时钟 -> 预分频 -> 12 位递减计数器 -> 到零产生系统复位。喂狗是把重装载值重新写入计数器,而不是清零。
- 本工程的参数是
40 kHz / 64 = 625 Hz(标称),Reload = 3125,故标称超时约 5 秒;严格公式应使用(Reload + 1),并必须考虑 LSI 的频率误差。 - 启动 IWDG 后不能靠普通代码将其关闭,只能通过系统复位重新开始。因此初始化顺序、最长阻塞时间和任务健康判据要在启用前设计好。
- IWDG 是故障恢复的最后一道措施,不是正确程序逻辑的替代品。要把刷新放在真正证明系统健康的位置,并在启动时记录复位原因,才能让看门狗既能复位,也能帮助定位故障。