WWDG窗口看门狗简介
窗口看门狗(WWDG)通常被用来监测由外部干扰或不可预见的逻辑条件造成的应用程序
背离正常的运行序列而产生的软件故障。除非递减计数器的值在 T6 位(WWDG->CR 的第六位)
变成 0 前被刷新,看门狗电路在达到预置的时间周期时,会产生一个 MCU 复位。在递减计数
器达到窗口配置寄存器(WWDG->CFR)数值之前,如果 7 位的递减计数器数值(在控制寄存器中)
被刷新, 那么也将产生一个 MCU 复位。这表明递减计数器需要在一个有限的时间窗口中被刷
新。他们的关系可以用图
T[6:0]就是 WWDG_CR 的低七位,W[6:0]即是 WWDG->CFR 的低七位。T[6:0]
就是窗口看门狗的计数器,而 W[6:0]则是窗口看门狗的上窗口,下窗口值是固定的(0X40)。
当窗口看门狗的计数器在上窗口值之外被刷新,或者低于下窗口值都会产生复位。
上窗口值(W[6:0])是由用户自己设定的,根据实际要求来设计窗口值,但是一定要确保
窗口值大于 0X40,否则窗口就不存在了。
窗口看门狗的超时公式如下:Twwdg=(4096×2^WDGTB×(T[5:0]+1)) /Fpclk1;
**
Twwdg:WWDG 超时时间(单位为 ms)
Fpclk1:APB1 的时钟频率(单位为 Khz)
WDGTB:WWDG 的预分频系数
T[5:0]:窗口看门狗的计数器低 6 位
控制寄存器WWDG_CR
WWDG_CR 只有低八位有效,T[6:0]用来存储看门狗的计数器值,
随时更新的,每个窗口看门狗计数周期(4096×2^ WDGTB)减 1。当该计数器的值从 0X40 变
为 0X3F 的时候,将产生看门狗复位。
配置寄存器WWDG_CFR
该位中的 EWI 是提前唤醒中断,也就是在快要产生复位的前一段时间(T[6:0]=0X40)来
提醒我们,需要进行喂狗了,否则将复位!因此,我们一般用该位来设置中断,当窗口看门狗
的计数器值减到 0X40 的时候,如果该位设置,并开启了中断,则会产生中断,我们可以在中
断里面向 WWDG_CR 重新写入计数器的值,来达到喂狗的目的。注意这里在进入中断后,必
须在不大于1个窗口看门狗计数周期的时间(在PCLK1频率为42M且WDGTB为0的条件下,
该时间为 97.52us)内重新写 WWDG_CR,否则,看门狗将产生复位!
状态寄存器器WWDG_SR
该寄存器用来记录当前是否有提前唤醒的标志,该寄存器仅有位 0 有效,当计数器值达到 40h 时,此位由硬件置 1。
它必须通过软件写 0 来清除
使用STM32F4的窗口看门狗步骤
1.使能WWDG时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // WWDG 时钟使能
2.设置窗口值和分频数
设置窗口值的函数是:void WWDG_SetWindowValue(uint8_t WindowValue);
设置分频数的函数是:void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);
3.开启WWDG中断并分组
开启WWDG中断的函数为:WWDG_EnableIT(); //开启窗口看门狗中断
接下来是进行中断优先级配置,使用 NVIC_Init()函数即可。
4.设置计数器初始值并使能看门狗
void WWDG_Enable(uint8_t Counter);
该函数既设置了计数器初始值,同时使能了窗口看门狗。
库函数还提供了一个独立的设置计数器值的函数为:void WWDG_SetCounter(uint8_t Counter);
5.编写中断服务函数
通过 DS0 来指示 STM32F4 是否被复位了,如果被复位了就会点亮 300ms。DS1 用来指
示中断喂狗,每次中断喂狗翻转一次。
喂狗要快!否则当窗口看门狗计数器值减到 0X3F 的时候,就会引起软复位了
wwdg.h
#ifndef __WWDG_H_
#define __WWDG_H_
#include "stm32f4xx.h"
#include "stm32f4xx_wwdg.h"
//初始化窗口看门狗
//tr :T[6:0],计数器值 wr :W[6:0],窗口值
//fprer:分频系数(WDGTB),仅最低 2 位有效
//Fwwdg=PCLK1/(4096*2^fprer). 一般 PCLK1=42Mhz
void WWDG_Init(u8 tr,u8 wr,u32 fprer);
//窗口看门狗中断服务程序
void WWDG_IRQHandler(void);
#endif
wwdg.c
#include "wwdg.h"
#include "led.h"
u8 WWDG_CNT=0X7F;
// WWDG_CNT,该变量用来保存最初设置 WWDG_CR 计数器的值。在后续的中断服务函数里面,就又通过 WWDG_SetCounter
//函数把该数值放回到 WWDG_CR 上。
//初始化窗口看门狗
//tr :T[6:0],计数器值 wr :W[6:0],窗口值
//fprer:分频系数(WDGTB),仅最低 2 位有效
void WWDG_Init(u8 tr,u8 wr,u32 fprer)
{
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
WWDG_CNT=tr&WWDG_CNT; //初始化 WWDG_CNT.
WWDG_SetPrescaler(fprer);//设置分频值
WWDG_SetWindowValue(wr);//设置窗口值
WWDG_SetCounter(WWDG_CNT);//设置计数值
WWDG_Enable(WWDG_CNT);//开启看门狗
NVIC_InitStructure.NVIC_IRQChannel=WWDG_IRQn; //窗口看门狗中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02; //抢占优先级为 2
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03; //响应优先级为 3
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能窗口看门狗
NVIC_Init(&NVIC_InitStructure);
WWDG_ClearFlag();//清除提前唤醒中断标志位
WWDG_EnableIT();//开启提前唤醒中断
}
//窗口看门狗中断服务程序
void WWDG_IRQHandler(void)
{
WWDG_SetCounter (WWDG_CNT); //重设窗口看门狗值
WWDG_ClearFlag();//清除提前唤醒中断标志位
LED1=!LED1;
}
main.c
#include "led.h" // 将接口驱动头文件包含进来
#include "key.h"
#include "beep.h"
#include "iwdg.h"
#include "delay.h"
#include "wwdg.h"
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组 2
delay_init(168); //初始化延时函数
LED_Init(); //初始化 LED 端口
KEY_Init(); //初始化按键
LED0=0; //点亮 LED0
delay_ms(300);
WWDG_Init(0x7F,0X5F,WWDG_Prescaler_8);
//计数器值为 7f,窗口寄存器为 5f,分频数为 8
while(1)
{
LED0=1; //熄灭 LED 灯
}
}