【STM32】基础知识 第十六课 窗口看门狗 WWDG 深入浅出
- 概述
- 窗口看门狗 (WWDG)
- WWDG_SR 状态寄存器
- WWDG 配置与使用
- 使用 WWDG 进行故障检测
- 案例
概述
在嵌入式开发中, 可靠性和稳定性是至关重要的. 这就是为什么许多单片机, 比如 STM32, 提供了窗口看门狗 (Window Watchdog, WWDF) 的功能. WWDG 是一种硬件定时器, 其目的在于防止软件错误导致的系统故障. WWDG 是通过监控软件运行的正常新, 并在检测到异常情况时自动重启系统, 从而防止系统长时间处于错误状态. 虽然 STM32 同时提供了独立看门狗 (Independent Watchdog, IWDG) 和 WWDG, 但 WWDG 具有更高精度和更灵活的配置选项, 使其在一些需要精确定时或特殊需求的应用中具有优势.
窗口看门狗 (WWDG)
WWDG 的核心是一个 7 位的定时器 (取值范围 0-127). 用户可以设定一个窗口值和一个计数重载值. 当定时器计数值在重载值到窗口值之间倒数时, 称为窗口期. 窗口期是唯一可以刷新 WWDG 的时机. 也就是说, 只有在 “窗口” 打开期间, 才可以 “喂狗”.
如果在窗口未打开前就重载了 WWDG, 或者在窗口打开后没有及时重载 WWDG, 那么 WWDG 都会产生系统复位.
这样的设计能够使系统检测到两种软件错误:
- 执行过快: 窗口未打开前就重载了 WWDG
- 执行过慢: 窗口打开后没有及时重载 WWDG
WWDG_SR 状态寄存器
在 STM32 中, WWDG_SR 是窗口看门狗状态寄存器 (Windows Watchdog Status Register). WWDG_SR 只有一个比特位, 即比特 0 (EWIF), 又称为早早期唤醒中断标志 (Early Wakeup Interrupt Flag). 这个标志位用来表示窗口看门狗定时器已达到了 63 (也就是 127-64), 即将达到重载值. 这个功能可以用来唤醒 CPU, 让它有足够的时间去刷新窗口看门狗, 防止系统复位.
注: 虽热 EWIF 位可以通过软件清零, 但是在窗口看门狗启动后, 这个标志位会自动置位, 所以在大多数情况下, 我们需要手动清零这个标志位.
WWDG 配置与使用
在 STM32 中, 使用 WWDG 首先需要启动 WWDG 时钟, 并设置预分频器和窗口值. 通过访问 WWDG 的控制寄存器 (WWDG_CR) 和配置寄存器 (WWDG_CFR) 来实现.
具体步骤如下:
- 启动 WWDG 时钟: 通过访问复位和时钟控制 (RCC) 的 APB1 使能寄存器 (RCC_APB1ENR), 能使 WWDG 时钟
- 设置 WWDG 的预分频器和窗口值:通过访问 WWDG 的配置寄存器 (WWFG_CRF), 设置预分频器 (WDGTB) 和窗口值 (W). 同时, 可以使能窗口看门狗早期中断 (EWI)
- 设置 WWDG 的计数器重载值: 通过访问 WWDG 的控制寄存器 (WWDG_CR), 设置计数器的重载值, 并使能 WWDG
使用 WWDG 进行故障检测
WWDG 能够检测出软件中心过快和执行过慢两种类型的错误. 当主程序在窗口打开后没有及时重载 WWDG, 说明团建执行过慢, 这两种情况都会引发 WWDG 产生系统复位.
因为在实际应用中, 软件执行的速度往往与任务的完成密切相关. 如果软件执行过快, 可能意味着某些任务被跳过或者未被正确处理. 如果软件执行过慢, 可能意味着系统的性能无法满足需求, 或者某些任务执行时间过长. 通过 WWDG, 我们可以确保软件在预定的时间范围内正确的运行.
案例
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/WDG/wdg.h"
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
LED0(0); /* 点亮LED0 红灯 */
delay_ms(300); /* 延时300ms再初始化看门狗,LED0的变化"可见" */
wwdg_init(0X7F, 0X5F, WWDG_PRESCALER_8);/* 计数器值为7f,窗口寄存器为5f,分频数为8 */
while (1)
{
LED0(1); /* 关闭红灯 */
}
}