【STM32学习笔记】(15)——窗口看门狗(WWDG)详解

STM32的窗口看门狗(WWDG)是一种用于监控软件故障的安全机制,它会在应用程序偏离正常运行序列时触发MCU复位。WWDG具有可编程的递减计数器和窗口限制,当计数器值超出预设范围时,会产生复位。在中断服务程序中,可以刷新计数器以避免复位。WWDG的配置包括设置窗口值、分频系数和计数器初始值,并可以通过中断在复位前发出警告。实验中,通过LED状态观察中断触发情况,展示了WWDG功能的正确运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

窗口看门狗(WWDG)概述

       窗口看门狗通常被用来监测,由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。除非递减计数器的值在T6位变成0前被刷新,否则看门狗电路在达到预置的时间周期时,会产生一个MCU复位。

        在递减计数器达到窗口寄存器数值之前,如果7位的递减计数器数值(在控制寄存器中)被刷新, 那么也将产生一个MCU复位。这表明递减计数器需要在一个有限的时间窗口中被刷新。

WWDG主要特性

        ● 可编程的自由运行递减计数器

        ● 条件复位         ─ 当递减计数器的值小于0x40,(若看门狗被启动)则产生复位。

                                   ─ 当递减计数器在窗口外被重新装载,(若看门狗被启动)则产生复位。

        ● 如果启动了看门狗并且允许中断,当递减计数器等于0x40时产生早期唤醒中断(EWI),它可以被用于重装载计数器以避免WWDG复位。

WWDG功能描述

        如果看门狗被启动(WWDG_CR寄存器中的WDGA位被置’1’), 并且当7位(T[6:0])递减计数器从0x40翻转到0x3F(T6位清零)时,则产生一个复位。

        如果软件在计数器值大于窗口寄存器中的数值时重新装载计数器,将产生一个复位。

        应用程序在正常运行过程中必须定期地写入WWDG_CR寄存器以防止MCU发生复位。只有当计数器值小于窗口寄存器的值时,才能进行写操作。储存在WWDG_CR寄存器中的数值必须在0xFF和0xC0之间:

        ● 启动看门狗

        在系统复位后,看门狗总是处于关闭状态,设置WWDG_CR寄存器的WDGA位能够开启看门狗,随后它不能再被关闭,除非发生复位。

        ● 控制递减计数器

        递减计数器处于自由运行状态,即使看门狗被禁止,递减计数器仍继续递减计数。当看门狗被启用时,T6位必须被设置,以防止立即产生一个复位。

        T[5:0]位包含了看门狗产生复位之前的计时数目;复位前的延时时间在一个最小值和一个最大值之间变化,这是因为写入WWDG_CR寄存器时,预分频值是未知的。

        配置寄存器(WWDG_CFR) 中包含窗口的上限值:要避免产生复位,递减计数器必须在其值小于窗口寄存器的数值并且大于0x3F时被重新装载。

        另一个重装载计数器的方法是利用早期唤醒中断(EWI)。设置WWDG_CFR寄存器中的WEI位开启该中断。当递减计数器到达0x40时,则产生此中断,相应的中断服务程序(ISR)可以用来加载计数器以防止WWDG复位。在WWDG_SR寄存器中写’0’可以清除该中断。

        注: 可以用T6位产生一个软件复位(设置WDGA位为’1’,T6位为’0’)。

 

        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 位

        根据上面的公式,假设 Fpclk1=36Mhz,那么可以得到最小-最大超时时间如下表

调试模式

        当微控制器进入调试模式时(Cortex-M3核心停止),根据调试模块中的DBG_WWDG_STOP 配置位的状态,WWDG的计数器能够继续工作或停止。

窗口看门狗(WWDG)寄存器

控制寄存器(WWDG_CR)

 

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

        WDGA 位则是看门狗的激活位,该位由软件置 1,以启动看门狗,并且一定要注意的是该 位一旦设置,就只能在硬件复位后才能清零了。

配置寄存器(WWDG_CFR)

        该位中的 EWI位是提前唤醒中断位,也就是在快要产生复位的前一段时间(T[6:0]=0X40)来提醒我们,需要进行喂狗了,否则将复位!

        因此,我们一般用该位来设置中断,当窗口看门狗的计数器值减到 0X40 的时候,如果该位设置,并开启了中断,则会产生中断,我们可以在中断里面向 WWDG_CR 重新写入计数器的值,来达到喂狗的目的。注意这里在进入中断后,必须在不大于 1 个窗口看门狗计数周期的时间(在 PCLK1 频率为 36M 且 WDGTB 为 0 的条件下, 该时间为 113us)内重新写 WWDG_CR,否则,看门狗将产生复位!

 状态寄存器(WWDG_SR)

        该寄存器用来记录当前是否有提前唤醒的标志。该寄存器仅有位 0 有效,其他都是保留位。当计数器值达到 40h 时,此位由硬件置 1。 它必须通过软件写 0 来清除。对此位写 1 无效。即使中断未被使能,在计数器的值达到 0X40的时候,此位也会被置 1。

窗口看门狗(WWDG)寄存器映像

WWDG固件库函数

       窗口看门狗库函数相关源码和定义分布在文件 stm32f10x_wwdg.c 文件和头文件 stm32f10x_wwdg.h 中。

       1)使能 WWDG 时钟

WWDG 不同于IWDG,IWDG 有自己独立的 40Khz 时钟,不存在使能问题。而 WWDG使用的是 PCLK1 的时钟,需要先使能时钟。方法是:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // WWDG 时钟使能

        2)设置窗口值和分频数

        设置窗口值的函数是:

void WWDG_SetWindowValue(uint8_t WindowValue);

        这个函数的入口参数 WindowValue 用来设置看门狗的上窗口值。

        设置分频数的函数是:

void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);

        这个函数同样只有一个入口参数,用来设置看门狗的分频值。

        3)开启 WWDG 中断并分组

        开启 WWDG 中断的函数为:

WWDG_EnableIT(); //开启窗口看门狗中断

        接下来是进行中断优先级配置,这里就不重复了,使用 NVIC_Init()函数即可。

        4)设置计数器初始值并使能看门狗

        这一步在库函数里面是通过一个函数实现的:

void WWDG_Enable(uint8_t Counter);

        该函数既设置了计数器初始值,同时使能了窗口看门狗。

        5)编写中断服务函数

        编写窗口看门狗的中断服务函数,通过该函数来喂狗,必须在不大于 1 个窗口看门狗计数周期的时间内完成喂狗,否则当窗口看门狗计数器值减到 0X3F 的时候,就会引起软复位了。在中断服务函数里面也要将状态寄存器的 EWIF 位清空。

WWDG(窗口看门狗)实验

硬件设计

        1) 指示灯 DS0 和 DS1

        2) 窗口看门狗

        窗口看门狗属于 STM32 的内部资源,只需要软件设置好即可正常工作。我们通过 DS0 和 DS1 来指示 STM32 的复位情况和窗口看门狗的喂狗情况。

软件设计

        在工程文件目录下面新建两个文件夹分别为:wdg.c和wdg.h。并在把源文件添加到工程,和添加头文件的路径。

wdg.c 里面的代码如下:

#include "wdg.h"
#include "led.h"
 

void IWDG_Init(u8 prer,u16 rlr) 
{	
 	IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);  //使能对寄存器IWDG_PR和IWDG_RLR的写操作
	
	IWDG_SetPrescaler(prer);  //设置IWDG预分频值:设置IWDG预分频值为64
	
	IWDG_SetReload(rlr);  //设置IWDG重装载值
	
	IWDG_ReloadCounter();  //按照IWDG重装载寄存器的值重装载IWDG计数器
	
	IWDG_Enable();  //使能IWDG
}
//喂独立看门狗
void IWDG_Feed(void)
{   
 	IWDG_ReloadCounter();	//重载计数值									   
}


//保存WWDG计数器的设置值,默认为最大. 
u8 WWDG_CNT=0x7f; 
//初始化窗口看门狗 	
//tr   :T[6:0],计数器值 
//wr   :W[6:0],窗口值 
//fprer:分频系数(WDGTB),仅最低2位有效 
//Fwwdg=PCLK1/(4096*2^fprer). 

void WWDG_Init(u8 tr,u8 wr,u32 fprer)
{ 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);  //   WWDG时钟使能

	WWDG_CNT=tr&WWDG_CNT;   //初始化WWDG_CNT.   
	WWDG_SetPrescaler(fprer);设置IWDG预分频值

	WWDG_SetWindowValue(wr);//设置窗口值

	WWDG_Enable(WWDG_CNT);	 //使能看门狗 ,	设置 counter .                  

	WWDG_ClearFlag();//清除提前唤醒中断标志位 

	WWDG_NVIC_Init();//初始化窗口看门狗 NVIC

	WWDG_EnableIT(); //开启窗口看门狗中断
} 
//重设置WWDG计数器的值
void WWDG_Set_Counter(u8 cnt)
{
    WWDG_Enable(cnt);//使能看门狗 ,	设置 counter .	 
}
//窗口看门狗中断服务程序
void WWDG_NVIC_Init()
{
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;    //WWDG中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;   //抢占2,子优先级3,组2	
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;	 //抢占2,子优先级3,组2	
  NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; 
	NVIC_Init(&NVIC_InitStructure);//NVIC初始化
}

void WWDG_IRQHandler(void)
	{

	WWDG_SetCounter(WWDG_CNT);	  //当禁掉此句后,窗口看门狗将产生复位

	WWDG_ClearFlag();	  //清除提前唤醒中断标志位

	LED1=!LED1;		 //LED状态翻转
	}

        第一个函数 void WWDG_Init(u8 tr,u8 wr,u8 fprer)用来设置 WWDG 的初始化值。包括看门狗计数器的值和看门狗比较值等。全局变量 WWDG_CNT,该变量用来保 存最初设置 WWDG_CR 计数器的值。在后续的中断服务函数里面,就又把该数值放回到WWDG_CR 上。

        第二个函数WWDG_Set_Counter()是用来重设窗口看门狗的计数器值的。

        第三个函数是中断分组函数。

        第四个函数是中断服务函数,先重设窗口看门狗的计数器值,然后清除提前唤醒中断标志。函数中也对 LED1(DS1)取反,来监测中断服务函数的执行了状况。

wdg.h 里面的代码如下:

#ifndef __WDG_H
#define __WDG_H
#include "sys.h"
	  


void IWDG_Init(u8 prer,u16 rlr);
void IWDG_Feed(void);

void WWDG_Init(u8 tr,u8 wr,u32 fprer);//初始化WWDG
void WWDG_Set_Counter(u8 cnt);       //设置WWDG的计数器
void WWDG_NVIC_Init(void);

#endif

        把头文件中的几个函数名加入到头文件里面去,其他文件的文件可以调用。

main.c中的代码:

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "wdg.h"

 
 int main(void)
 {		
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 //串口初始化为115200
 	LED_Init();
	KEY_Init();          //按键初始化	 
	LED0=0;
	delay_ms(300);	  
	WWDG_Init(0X7F,0X5F,WWDG_Prescaler_8);//计数器值为7f,窗口寄存器为5f,分频数为8	   
 	while(1)
	{
		LED0=1;			  	   
	}   
}

        该函数通过 LED0(DS0)来指示是否正在初始化。而 LED1(DS1)用来指示是否发生了中 断。我们先让 LED0 亮 300ms,然后关闭以用于判断是否有复位发生了。在初始化 WWDG 之后,我们回到死循环,关闭 LED1,并等待看门狗中断的触发/复位。

实验现象

        DS0 亮一下之后熄灭,紧接着 DS1 开始不停的闪烁。每秒钟闪烁 5 次左右。

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狂飙的犇牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值