STM32窗口看门狗——用LED灯来模拟(正点原子精英板)

什么是窗口看门狗:

窗口看门狗也是一种让系统复位的机制,只不过窗口看门狗是针对软件层次的错误。

那么窗口看门狗的工作原理是怎样的?

根据上图1我们就可以知道,窗口看门狗其实也是一个递减的计数器。只不过它的复位方式与独立看门狗有所不同。首先我们可以将其分为两个阶段,非窗口期和窗口期,而窗口期又有一个特殊的时刻,也就是在纵坐标为0x40时的产生中断时刻。那么根据此我将对这两个阶段和一个时刻做出解释,首先是非窗口期,如果在非窗口期我们进行喂狗系统就会复位,如果在窗口期喂狗那么我们就会相当于独立看门狗一样进行重新计数。而独立看门狗有一个产生中断时刻,这个时刻是独立看门狗自己自动进行中断操作。最后如果我们没有进行任何操作那么窗口看门狗也会跟独立看门狗一样当时间递减到0x3f后自动复位。

那么了解了窗口看门狗的工作原理我们直接进行相关的配置

首先我们应该了解窗口看门狗超时时间的计算公式

超时时间就是我们的窗口看门狗经过多长时间就进行复位。WWDG的时钟频率根据STM32的型号不同而不同,在我们精英板中窗口看门狗的时钟频率是36kHz,4096是固定的一个参数我们记下就可以,预分频系数跟独立看门狗的类似只不过窗口看门狗的最大就为8,如下图所示:

在上图中0,1,2,3是公式中WDGTB的值经过计算最小值就是2的0次方,最大值就是2的3次方,所以最小值是1最大值是8。T[5:0]是WWDG的计数器低六位,我们只需要知道他是一个6位的2进制数即可。最小值是0最大值是63,而在计算公式中+1,所以最小值为1最大值是64。

那么我们可以据此以WDGTB设置为3为例计算其最大超时值:

从下往上看这个计算器的步骤就可以理解了。

那么接下来我们直接进行WWDG的配置,下面是其步骤:

上图2就是独立看门狗的配置步骤

下面是整个wdg.c的代码

#include "./BSP/WDG/wdg.h"
#include "./BSP/LED/led.h"
#include "./SYSTEM/delay/delay.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;	//WWDG使能
	HAL_WWDG_Init(&g_wwdg_handle);	//调用HAL库的WWDG初始化函数
}
/* WWDG MSP回调函数 */
void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwwdg)
{
	__HAL_RCC_WWDG_CLK_ENABLE();
	
	HAL_NVIC_SetPriority(WWDG_IRQn,2,3);	//设置WWDG的优先级设置,这里因为HAL库默认是分组2,所以就没做优先级分组的设置直接用了默认的
	HAL_NVIC_EnableIRQ(WWDG_IRQn);	//中断使能
}
/* WWDG中断服务函数 */
void WWDG_IRQHandler(void)
{
    HAL_WWDG_IRQHandler(&g_wwdg_handle);	//调用WWDG的中断公共服务函数
}

/* WWDG提前唤醒回调函数 */
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
{
    HAL_WWDG_Refresh(&g_wwdg_handle);	//WWDG的喂狗函数
    LED1(0);	//点亮LED1
}

首先就是WWDG的初始化,其内部与IWDG的初始化差不多,都先是设置其基地址。只不过窗口看门狗还要设置计数值(图一中纵坐标的最大值,是一个7位二进制数,最大值为x07f),和窗口值(我们自行根据需求判断选择设置多少合适),以及上述讲过的预分频系数。这样我们就设置好的第1步

WWDG MSP回调函数 的编写:

我们通过代码可以看到这其中包含了第2和第3步。而这其中其实就是中断的操作这里我不做解释,又不懂的可以参考我的STM32中断的那篇文章。

WWDG中断服务函数就是内部调用一下WWDG的中断公共服务函数,与中断类似不做解释。

这里解释一下WWDG的提前唤醒回调函数,其实这个函数里我们就可以编写我们想要实现的操作了,因为我想要模拟窗口看门狗的功能所以我点亮的LED1,这里我们其实就可以将回调函数理解成图1中的产生中断的那个时刻。所以可以看到我在这里编写了喂狗函数,那么不管窗口期还是非窗口期,每当看门狗执行到0X40的时候(也就是产生中断),都会喂狗那么其实就相当于这个窗口看门狗失灵了,因为它永远都不会进行系统的复位操作。

接下来看一下我的主函数部分:

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/WDG/wdg.h"


int main(void)
{
    HAL_Init();                                 /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);         /* 设置时钟,72M */
    delay_init(72);                             /* 初始化延时函数 */
    led_init();                                 /* 初始化LED */     
    wwdg_init(0x7f, 0x5f, WWDG_PRESCALER_8);	//窗口看门狗初始化
    while(1)
    {
        delay_ms(5000);
        //HAL_WWDG_Refresh(&g_wwdg_handle);	//喂狗
		LED0(0);	//点亮LED0
    }
}

在函数开始是对各项的初始化,包括窗口看门狗(计数值我设置为0x7f,窗口值:0x5f,预分频系数查看HAL库中的宏定义设置为了8也就是2的3次方=8),这里我点亮了LED1便于实验的观察。

循环中可以看到我注释了喂狗函数并在延迟5秒后点亮了LED0。那么我们的实验现象就应该是LED1先亮起(窗口看门狗进行到了产生中断操作,也就是运行了回调函数),之后过段时间LED0也会亮起,并且不会熄灭,因为我再回调函数里也调用了喂狗函数,这样独立窗口函数就不会进行复位。

那么如果我们注释掉回调函数里喂狗函数并且将主函数里的延时设置为30ms,取消注释喂狗函数,实验现象就是LED1永远都不会亮起,并且LED0常亮,这是因为我们在窗口进行了喂狗,窗口看门狗会重新计时(也就跟独立看门狗喂狗一样了),而产生中断操作在这之后,所以窗口看门狗并不会产生中断操作,LED1也就不会亮起。

到这里有关于窗口看门狗的工作原理已经讲解完毕,可以自行调控函数,来实现自己想要得到的现象。

这里最后进行一个解释:在实际应用中窗口看门狗的回调函数中一定不要有喂狗函数!!!。因为这会使窗口看门狗失效,我们一般是将窗口看门狗的回调函数里写入我们想要保存的数据,这样我们就可以在窗口看门狗即将进行复位操作时保存下数据。

注:图一中的纵坐标就是窗口看门狗的最大时间和最小时间,即0x7f到0x3f,所以我们称中断操作是窗口看门狗的最后操作(因为其值是0x40)。

  • 30
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值