STM32-笔记26-WWDG窗口看门狗
一、简介
窗口看门狗用于监测单片机程序运行时效是否精准,主要检测软件异常,一般用于需要精准检测程序运行时间的场合。
窗口看门狗的本质是一个能产生系统复位信号和提前唤醒中断的6位计数器(有的地方说7位。其实都无所谓,本质是一样的)。
产生复位条件:
- 当递减计数器值从 0x40 减到 0x3F 时复位(即T6位跳变到0)
- 计数器的值大于 W[6:0] 值时喂狗会复位。
产生中断条件:
- 当递减计数器等于 0x40 时可产生提前唤醒中断 (EWI)。
在窗口期内重装载计数器的值,防止复位,也就是所谓的喂狗。
二、WWDG工作原理及框图
三、WWDG寄存器及函数介绍
窗口看门狗内有一个7位的递减计数器,并可以设置成自由运行。它可以被当成看门狗用于在发生问题时复位整个系统。它由主时钟驱动,具有早期预警中断功能;在调试模式下,计数器可以被冻结。
3.1 控制寄存器
3.2 配置寄存器
3.3 状态寄存器
3.4 寄存器映像
3.5 函数
等......
配置步骤
四、WWDG溢出时间计算
在上面的超时公式中:周期(时间 = Tpclk1) = 频率的倒数 = PCLK1(频率)
4096 * 2^WDGTB / PCLK1 = 数一个数的时间单位是ms
PCLK1 = 36MHZ( 常等于)
(T[5:0]+1) = 个数
五、看门狗实验
5.1 实验目的
开启窗口看门狗,计数器值设置为 0X7F ,窗口值设置为 0X5F ,预分频系数为 8 。在 while 循环里喂狗,同时翻转 LED1 状态;在提前唤醒中断服务函数进行喂狗,同时翻转 LED2 状态。
这里设置的窗口上限值为:
从开始计数,到记完数要复位的地方,也就是0X7F - 0X3F这段记58.25ms
复制项目文件夹19-串口打印功能,重命名位28-WWDG窗口看门狗
新建文件夹wwdg
打开项目
加载文件
加入wwdg驱动文件
代码:
main.c
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "wwdg.h"
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
led_init();//初始化led灯
uart1_init(115200);
wwdg_init(0x7f,0x5f,WWDG_PRESCALER_8);
printf("hello word!\r\n");
if(__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST) != RESET)
{
printf("窗口看门狗复位!\r\n");
__HAL_RCC_CLEAR_RESET_FLAGS();
}
else
printf("外部复位!\r\n");
while(1)
{
// delay_ms(50);
// wwdg_feed();
// led1_Toggle();
}
}
wwdg.c
#include "wwdg.h"
#include "led.h"
WWDG_HandleTypeDef wwdg_handle = {0};
//初始化窗口看门狗函数
void wwdg_init(uint8_t tr,uint8_t wr,uint32_t psc)
{
wwdg_handle.Instance = WWDG;
wwdg_handle.Init.Counter = tr;//计数器的值
wwdg_handle.Init.Prescaler = psc;//预分频系数
wwdg_handle.Init.Window = wr;//窗口上限值
wwdg_handle.Init.EWIMode = WWDG_EWI_ENABLE;//窗口看门狗早期唤醒启用
HAL_WWDG_Init(&wwdg_handle);
}
//msp函数初始化
void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwwdg)
{
__HAL_RCC_WWDG_CLK_ENABLE();
HAL_NVIC_SetPriority(WWDG_IRQn,2,2);//抢占优先级和响应优先级
HAL_NVIC_EnableIRQ(WWDG_IRQn);
}
//中断服务函数
void WWDG_IRQHandler(void)
{
HAL_WWDG_IRQHandler(&wwdg_handle);
}
//提前唤醒回调函数
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
{
//wwdg_feed();
led2_Toggle();
}
//喂狗函数
void wwdg_feed(void)
{
HAL_WWDG_Refresh(&wwdg_handle);
}
wwdg.h
#ifndef __WWDG_H__
#define __WWDG_H__
#include "sys.h"
void wwdg_init(uint8_t tr,uint8_t wr,uint32_t psc);
void wwdg_feed(void);
#endif
5.2 出现的结果
5.2.1 检验出现的结果1
当主函数为下面这段代码时,出现的结果是:
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "wwdg.h"
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
led_init();//初始化led灯
uart1_init(115200);
wwdg_init(0x7f,0x5f,WWDG_PRESCALER_8);
printf("hello word!\r\n");
while(1)
{
}
}
此时wwdg.c文件中,有喂狗操作。
串口窗口显示结果为
并且开发板LED2疯狂闪烁,表示在唤醒回调函数中成功喂狗
5.2.2 检验出现的结果2
当主函数为下面代码时:
此时wwdg.c文件中,有喂狗操作。
串口窗口显示结果为
并且开发板LED2疯狂闪烁,表示由外部复位,并且在此时成功喂狗
5.2.3 检验出现的结果3
主函数代码不变,wwdg.c文件如下图所示:
串口窗口显示结果为
并且开发板LED2疯狂闪烁,表示此时没有喂狗,看数数溢出由,窗口看门狗是否复位
5.2.4 检验出现的结果4
主函数代码如下图所示:
wwdg.c文件代码如下:
串口窗口显示结果为
LED1疯狂闪烁,这个时候延迟10ms喂狗的,此时喂狗在窗口期前,这个时候数数溢出由看门狗会复位
5.2.5 检验出现的结果5
主函数代码如下:
串口窗口显示如下:
LED1疯狂闪烁,在while函数中喂狗成功
5.3 关于疑问
在wwdg.c文件中,psc预分频器的定义,这里使用的是uint16_t,没有报错
我的理解是:4096 * 8 = 32768 = 1000 0000 0000 0000,十六位够用
这里如果定义的是uint8,则会报错,如下图所示:
翻译如下: