WWDG窗口看门狗简介

窗口看门狗(WWDG)通常被用来监测由外部干扰或不可预见的逻辑条件造成的应用程序
背离正常的运行序列而产生的软件故障。除非递减计数器的值在 T6 位(WWDG->CR 的第六位)
变成 0 前被刷新,看门狗电路在达到预置的时间周期时,会产生一个 MCU 复位。在递减计数
器达到窗口配置寄存器(WWDG->CFR)数值之前,如果 7 位的递减计数器数值(在控制寄存器中)
被刷新, 那么也将产生一个 MCU 复位。这表明递减计数器需要在一个有限的时间窗口中被刷
新。他们的关系可以用图
image.png
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 位

image.png
控制寄存器WWDG_CR
WWDG_CR 只有低八位有效,T[6:0]用来存储看门狗的计数器值,
随时更新的,每个窗口看门狗计数周期(4096×2^ WDGTB)减 1。当该计数器的值从 0X40 变
为 0X3F 的时候,将产生看门狗复位。

配置寄存器WWDG_CFR
image.png
该位中的 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

  1. #ifndef __WWDG_H_
  2. #define __WWDG_H_
  3. #include "stm32f4xx.h"
  4. #include "stm32f4xx_wwdg.h"
  5. //初始化窗口看门狗
  6. //tr :T[6:0],计数器值 wr :W[6:0],窗口值
  7. //fprer:分频系数(WDGTB),仅最低 2 位有效
  8. //Fwwdg=PCLK1/(4096*2^fprer). 一般 PCLK1=42Mhz
  9. void WWDG_Init(u8 tr,u8 wr,u32 fprer);
  10. //窗口看门狗中断服务程序
  11. void WWDG_IRQHandler(void);
  12. #endif

wwdg.c

  1. #include "wwdg.h"
  2. #include "led.h"
  3. u8 WWDG_CNT=0X7F;
  4. // WWDG_CNT,该变量用来保存最初设置 WWDG_CR 计数器的值。在后续的中断服务函数里面,就又通过 WWDG_SetCounter
  5. //函数把该数值放回到 WWDG_CR 上。
  6. //初始化窗口看门狗
  7. //tr :T[6:0],计数器值 wr :W[6:0],窗口值
  8. //fprer:分频系数(WDGTB),仅最低 2 位有效
  9. void WWDG_Init(u8 tr,u8 wr,u32 fprer)
  10. {
  11. NVIC_InitTypeDef NVIC_InitStructure;
  12. RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
  13. WWDG_CNT=tr&WWDG_CNT; //初始化 WWDG_CNT.
  14. WWDG_SetPrescaler(fprer);//设置分频值
  15. WWDG_SetWindowValue(wr);//设置窗口值
  16. WWDG_SetCounter(WWDG_CNT);//设置计数值
  17. WWDG_Enable(WWDG_CNT);//开启看门狗
  18. NVIC_InitStructure.NVIC_IRQChannel=WWDG_IRQn; //窗口看门狗中断
  19. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02; //抢占优先级为 2
  20. NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03; //响应优先级为 3
  21. NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能窗口看门狗
  22. NVIC_Init(&NVIC_InitStructure);
  23. WWDG_ClearFlag();//清除提前唤醒中断标志位
  24. WWDG_EnableIT();//开启提前唤醒中断
  25. }
  26. //窗口看门狗中断服务程序
  27. void WWDG_IRQHandler(void)
  28. {
  29. WWDG_SetCounter (WWDG_CNT); //重设窗口看门狗值
  30. WWDG_ClearFlag();//清除提前唤醒中断标志位
  31. LED1=!LED1;
  32. }

main.c

  1. #include "led.h" // 将接口驱动头文件包含进来
  2. #include "key.h"
  3. #include "beep.h"
  4. #include "iwdg.h"
  5. #include "delay.h"
  6. #include "wwdg.h"
  7. int main(void)
  8. {
  9. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组 2
  10. delay_init(168); //初始化延时函数
  11. LED_Init(); //初始化 LED 端口
  12. KEY_Init(); //初始化按键
  13. LED0=0; //点亮 LED0
  14. delay_ms(300);
  15. WWDG_Init(0x7F,0X5F,WWDG_Prescaler_8);
  16. //计数器值为 7f,窗口寄存器为 5f,分频数为 8
  17. while(1)
  18. {
  19. LED0=1; //熄灭 LED 灯
  20. }
  21. }