STM32入门教程(WDG看门狗篇)

参考教程:[14-1] WDG看门狗_哔哩哔哩_bilibili

1、WDG(Watchdog)看门狗:

(1)看门狗可以监控程序的运行状态,当程序因为设计漏洞、硬件故障、电磁干扰等原因,出现卡死或跑飞现象时,看门狗能及时复位程序,避免程序陷入长时间的罢工状态,保证系统的可靠性和安全性。

(2)看门狗本质上是一个定时器,当指定时间范围内,程序没有执行喂狗(重置计数器)操作时,看门狗硬件电路就自动产生复位信号

(3)STM32内置两个看门狗:

①独立看门狗(IWDG):独立工作,对时间精度要求较低。

②窗口看门狗(WWDG):要求看门狗在精确计时窗口起作用。

2、独立看门狗(IWDG):

(1)IWDG框图:

①在时钟产生电路有4个震荡源,其中一个是内部的40kHz低速RC振荡器(LSI RC 40kHz),它负责给独立看门狗提供时钟,这个时钟不需要用户手动开启。

②LSI时钟进入预分频器进行分频,分频系数由预分频寄存器进行配置。

LSI时钟经过预分频后驱动递减计数器进行自减计数(12位计数器最大值为4095),当计数器的值自减为0时会产生IWDG复位信号

如果不想让IWDG产生复位信号,那么在计数器的值自减为0之前及时给计数器重装载一个值(也就是“喂狗”)即可,这个值通过重装载寄存器写入递减计数器,什么时候给递减计数器重装载由键寄存器控制

(2)IWDG键寄存器:

①键寄存器本质上是控制寄存器,用于控制硬件电路的工作

②在可能存在干扰的情况下,一般通过在整个键寄存器写入特定值来代替控制寄存器写入一位的功能,以降低硬件电路受到干扰的概率

写入键寄存器的值

作用

0xCCCC

启用独立看门狗

0xAAAA

IWDG_RLR中的值重新加载到计数器(喂狗)

0x5555

解除IWDG_PR和IWDG_RLR的写保护

0x5555之外的其他值

启用IWDG_PR和IWDG_RLR的写保护

(3)IWDG超时时间:

3、窗口看门狗(WWDG):

(1)WWDG框图:

①窗口看门狗的时钟源是PCLK1(36MHz),时钟进入预分频器前会进行4096分频(图上未体现)。

WWDG_CR将递减计数器T0~T5是有效计数位,T6是溢出标志位,计数值自减过程中T6位为0代表溢出和控制寄存器(WDGA位置为1,窗口看门狗启动)合二为一需要同时满足T6位为0、WDGA位为1两个条件WWDG才会产生复位信号;窗口看门狗没有重装载寄存器,需要重装载时(喂狗)直接往递减计数器中写值即可

窗口看门狗的最早喂狗时间写在WWDG_CFR中,当喂狗时间过早时,窗口看门狗会产生复位信号。

当对递减计数器进行写操作(喂狗)时,比较器使能,这时比较器会比较递减计数器(喂狗前一刻)的值和配置寄存器的值,如果递减计数器的值较大,说明喂狗时间过早,比较器输出高电平,如果WDGA=1,就会产生复位信号

(2)WWDG工作特性:

①递减计数器T[6:0]的值小于0x40(也就是T6=0)时(没有及时喂狗),WWDG产生复位。

②递减计数器T[6:0]在窗口W[6:0]外被重新装载时(喂狗时间过早),WWDG产生复位。

③递减计数器T[6:0]等于0x40时可以产生早期唤醒中断(EWI,又称作“死前中断”),可以在中断函数中重装载计数器以避免WWDG复位(在喂狗的最晚时间使用中断喂狗)。

④定期写入WWDG_CR寄存器(喂狗)以避免WWDG复位。

(3)WWDG超时时间:

4、IWDG和WWDG对比:

IWDG独立看门狗

WWDG窗口看门狗

复位

计数器减到0后

计数器T[5:0]减到0后、过早重装计数器

中断

早期唤醒中断

时钟源

LSI(40KHz)

PCLK1(36MHz)

预分频系数

4、8、32、64、128、256

1、2、4、8

计数器

12位

6位(有效计数)

超时时间

0.1ms~26214.4ms

113us~58.25ms

喂狗方式

写入键寄存器,重装固定值RLR

直接写入计数器,写多少重装多少

防误操作

键寄存器和写保护

用途

独立工作,对时间精度要求较低

要求看门狗在精确计时窗口起作用

5、独立看门狗使用例:

(1)按照下图所示接好电路,并将OLED显示屏的项目文件夹复制一份作为模板使用。

(2)在stm32f10x_iwdg.h文件中有IWDG模块相关的函数。

[1]IWDG_WriteAccessCmd函数:写使能控制(键寄存器写入0x5555,解除或开启IWDG_PR和IWDG_RLR的写保护)。

[2]IWDG_SetPrescaler函数:设置预分频器的分频系数(写IWDG_PR)。

[3]IWDG_SetReload函数:设置重装值(写IWDG_RLR)。

[4]IWDG_ReloadCounter函数:重装载递减计数器(键寄存器写入0xAAAA,即喂狗)。

[5]IWDG_Enable函数:启动独立看门狗(键寄存器写入0xCCCC)。

[6]IWDG_GetFlagStatus函数:获取状态标志位。

(3)在main.c文件中粘贴以下代码,然后编译,将程序下载到开发板中进行调试。

①正常情况下,将程序下载到开发板后OLED屏会显示一次“RST”,然后会不断闪烁显示“FFED”,如果按下复位按键,OLED屏会再显示一次“RST”,然后接着不断闪烁显示“FFED”。

如果按住按键不放,程序会卡死在Key_GetNum函数的死循环中程序不能及时喂狗,于是看门狗会产生复位信号并置IWDGRST为1,程序从头开始运行,由于是IWDG导致的复位,OLED屏不显示“RST”而显示“IWDGRST”,然后接着不断闪烁显示“FFED”

#include "stm32f10x.h"                  // Device headerCmd
#include "OLED.h"
#include "Delay.h"
#include "Key.h"

int main()
{
	OLED_Init();
Key_Init();
	
	OLED_ShowString(1,1,"IWDG TEXT");
	
	if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET)  //判断IWDG是否产生复位
	{
		OLED_ShowString(2,1,"IWDGRST");  //看门狗导致的复位
		Delay_ms(500);
		OLED_ShowString(2,1,"       ");
		Delay_ms(100);
		
		RCC_ClearFlag();  //清除复位标志
	}
	else
	{
		OLED_ShowString(3,1,"RST");  //不是看门狗导致的复位
		Delay_ms(500);
		OLED_ShowString(3,1,"   ");
		Delay_ms(100);
	}
	
	//解除IWDG的写保护
	IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
	
	//配置分频系数(40MHz经过16分频为2.5MHz)
	IWDG_SetPrescaler(IWDG_Prescaler_16);
	
	//配置重装值
	IWDG_SetReload(2500 - 1);  //超时时间为1000ms
	
	//先喂一次狗(键寄存器写入0x5555以外的值,同时开启写保护)
	IWDG_ReloadCounter();
	
	//启动看门狗
	IWDG_Enable();
	
	while(1)
	{
		Key_GetNum();
		//按下按键不放,程序会卡死在Key_GetNum函数的死循环中
		
		IWDG_ReloadCounter();   //喂狗
		
		OLED_ShowString(4,1,"FFED");
		Delay_ms(400);
		OLED_ShowString(4,1,"FFED");
		Delay_ms(200);
	}
}

6、窗口看门狗使用例:

(1)按照下图所示接好电路,并将上例的项目文件夹复制一份作为模板使用。

(2)在stm32f10x_wwdg.h文件中有WWDG模块相关的函数。

[1]WWDG_DeInit函数:恢复缺省配置。

[2]WWDG_SetPrescaler函数:配置预分频器的分频系数。

[3]WWDG_SetWindowValue函数:配置窗口值,也就是设置最早喂狗时间(写WWDG_CFR)。

[4]WWDG_EnableIT函数:使能早期唤醒中断。

[5]WWDG_SetCounter函数:重装载递减计数器(写WWDG_CR,即喂狗)。

[6]WWDG_Enable函数:启动窗口看门狗(并给递减计数器一个初值)。

[7]WWDG_GetFlagStatus函数:获取标志位。

[8]WWDG_ClearFlag函数:清除标志位。

(3)在main.c文件中粘贴以下代码,然后编译,将程序下载到开发板中进行调试。

①正常情况下,将程序下载到开发板后OLED屏会显示一次“RST”,然后会不断闪烁显示“FFED”,如果按下复位按键,OLED屏会再显示一次“RST”,然后接着不断闪烁显示“FFED”。

如果按住按键不放,程序会卡死在Key_GetNum函数的死循环中程序不能及时喂狗,于是看门狗会产生复位信号并置WWDGRST为1,程序从头开始运行,由于是WWDG导致的复位,OLED屏不显示“RST”而显示“WWDGRST”,然后接着不断闪烁显示“FFED”

③修改while循环中的延时函数参数,使喂狗时间早于30ms,那么喂狗后一样会产生复位信号并置WWDGRST为1,程序从头开始运行,由于是WWDG导致的复位,OLED屏不显示“RST”而显示“WWDGRST”,然后接着不断闪烁显示“FFED”

#include "stm32f10x.h"                  // Device headerCmd
#include "OLED.h"
#include "Delay.h"
#include "Key.h"

int main()
{
	OLED_Init();
	Key_Init();
	
	OLED_ShowString(1,1,"WWDG TEXT");
	
	if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET)  //判断WWDG是否产生复位
	{
		OLED_ShowString(2,1,"WWDGRST");  //看门狗导致的复位
		Delay_ms(500);
		OLED_ShowString(2,1,"       ");
		Delay_ms(100);
		
		RCC_ClearFlag();  //清除复位标志
	}
	else
	{
		OLED_ShowString(3,1,"RST");  //不是看门狗导致的复位
		Delay_ms(500);
		OLED_ShowString(3,1,"   ");
		Delay_ms(100);
	}
	
	//开启WWDG时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
	
	//配置分频系数(36MHz经过8×4096分频为1098.63Hz)
	WWDG_SetPrescaler(WWDG_Prescaler_8);
	
	//配置窗口值(这个值多多少少会有误差,但不大)
	WWDG_SetWindowValue(21|0x40);  //最早喂狗时间为30ms,过早喂狗会复位(0x40的作用是置W6为1,21由公式计算而得)
	
	//启动看门狗(这个值多多少少会有误差,但不大)
	WWDG_Enable(54|0x40);          //最晚喂狗时间为50ms,过晚喂狗会复位(0x40的作用是置T6为1,54由公式计算而得)
	
	while(1)
	{
		Key_GetNum();
		//按下按键不放,程序会卡死在Key_GetNum函数的死循环中
		
		OLED_ShowString(4,1,"FFED");
		Delay_ms(20);
		OLED_ShowString(4,1,"    ");
		Delay_ms(20);
		
		WWDG_SetCounter(54|0x40);   //喂狗(0x40的作用是置T6为1)
	}
}

猜你喜欢

转载自blog.csdn.net/Zevalin/article/details/134804944