窗口看门狗本质上是一个能产生系统复位信号和提前唤醒中断的定时器。它通常被用来监测,由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。除非递减计数器的值在T6位变成0前被刷新,否则看门狗电路在达到预置的时间周期时,会产生一个MCU复位。
根据系统时钟频率,装载一个初始值到向下计数器值(假设为1000),并且设置一个窗口值(小于装载到计数器的初始值,假设是500)。窗口看门狗一般会确定的窗口下限值是64。
当窗口看门狗启动之后,计数器从1000开始向下减,在减到500之前(1000到500间),是不允许你去喂狗的,一旦喂狗,就会产生复位信号。只有计数器值减到上限值之后和下限值之前(500到64),才允许你去喂狗。当计数器减到下限值(64到0之间),如果喂狗,也会产生复位信号,当减到0之后,自动产生复位信号。所以窗口看门狗实际上就是设置一个窗口(上下限),在这个范围内,你才允许你去喂狗,只要不在这个范围之内,都会复位。
窗口看门狗和独立看门狗的区别是:
1、窗口看门狗计时时间比独立看门狗精准; 窗口看门狗使用的是系统时钟源。
2、窗口看门狗严格限定喂狗时间段,独立看门狗则是只要没有到时间,都能喂狗。
接下来介绍关于窗口期喂狗的相关知识。
在下图中,我们暂时取最大值T的[6:0]127为例,进行讲解。在定时器启动后,CNT定时器从计数器初始值开始递减,逐渐靠近窗口上限值。当到达窗口下限值0x40(即64)之后,会产生一个中断,使用者自选中断是否触发,到达0x3F时候触达窗口下限,产生复位。下限值64是由系统规定的,是无法由用户进行改变的,但计数器初始值、窗口上限值是可以由用户自定义改变的。
最后介绍输出时间的计算Tout=4096*2^WDGTB*(deltaT+1)/Fwwdg(Fwwdg=36M)
----------------------------------------------------------------------------------
实验要求我们设置计数器值为0x7F,窗口值为0x5F,预分频系数为8(2^WDGTB=8),则此处的计算出的T1为29ms左右,T2为58ms左右。
接下来编写我们的实验程序代码。
首先编写函数头文件wwdg.h:
#ifndef __WWDG_H
#define __WWDG_H
#include "./SYSTEM/sys/sys.h"
#include "./BSP/LED/led.h"
extern WWDG_HandleTypeDef g_wwdg_handle;
void wwdg_init(uint8_t tr, uint8_t wr, uint32_t fprer);
void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwwdg);
void WWDG_IQRHandler(void);
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg);
#endif
接下来再编写函数文件wwdg.c:
#include "./BSP/WWDG/wwdg.h"
WWDG_HandleTypeDef g_wwdg_handle;
void wwdg_init(uint8_t tr, uint8_t wr, uint32_t fprer){
g_wwdg_handle.Instance = WWDG;
g_wwdg_handle.Init.Counter = tr;
g_wwdg_handle.Init.Window = wr;
g_wwdg_handle.Init.Prescaler = fprer;
g_wwdg_handle.Init.EWIMode = WWDG_EWI_ENABLE;
HAL_WWDG_Init(&g_wwdg_handle);
}
void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwwdg){
if(hwwdg->Instance == WWDG){
__HAL_RCC_WWDG_CLK_ENABLE();
HAL_NVIC_SetPriority(WWDG_IRQn, 2, 3);
HAL_NVIC_EnableIRQ(WWDG_IRQn);
}
}
void WWDG_IQRHandler(void){
HAL_WWDG_IRQHandle(&g_wwdg_handle);
}
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg){
LED0_TOGGLE();
}
接下来编写主函数main.c:
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/dalay.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/WWDG/wwdg.h"
#include "./BSP/LED/led.h"
int main(void){
HAL_Init();
sys_stm32_clock_init(RCC_PLL_MUL9);
delay_init(72);
led_init();
usart_init(115200);
wwdg_init(0x7f, 0x5f, WWDG_PRESCALER_8);
if(__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST) != RESET){
printf("WWDG_RESET\n");
__HAL_RCC_CLEAR_RESET_FLAGS();
}
else{
printf("External resetting.\n");
}
printf("Please feed the wwdg.\n");
while(1){
delay_ms(30);
HAL_WWDG_Refresh(&g_wwdg_handle);
printf("The WWDG has been fed.\n");
}
}
如此我们的实验代码便写好了。