【STM32 学习笔记】WDR看门狗

发布于:2025-07-12 ⋅ 阅读:(14) ⋅ 点赞:(0)

WDR看门狗

STM32有两个看门狗,一个是独立看门狗另外一个是窗口看门狗,独立看门狗号称宠物狗,窗口看门狗号称警犬,本章我们主要分析独立看门狗的功能框图和它的应用。
在这里插入图片描述

独立看门狗

独立看门狗用通俗一点的话来解释就是一个12位的递减计数器,当计数器的值从某个值一直减到0的时候,系统就会产生一个复位信号,即IWDG_RESET。 如果在计数没减到0之前,刷新了计数器的值的话,那么就不会产生复位信号,这个动作就是我们经常说的喂狗。看门狗功能由 VDD 电压域供电, 在停止模式和待机模式下仍能工作

在键寄存器(IWDG_KR)中写入0xCCCC,开始启用独立看门狗;此时计数器开始从其复位值0xFFF递减计数。当计数器计数到末尾0x000时,会产生一个复位信号(IWDG_RESET)。
无论何时,只要在键寄存器IWDG_KR中写入0xAAAA, IWDG_RLR中的值就会被重新加载到计数器,从而避免产生看门狗复位 。

IWDG功能框图剖析

在这里插入图片描述
1. 独立看门狗时钟
独立看门狗的时钟由独立的RC振荡器LSI提供,即使主时钟发生故障它仍然有效,非常独立。LSI的频率一般在30~60KHZ之间, 根据温度和工作场合会有一定的漂移,我们一般取40KHZ,所以独立看门狗的定时时间并不一定非常精确,只适用于对时间精度要求比较低的场合。
在这里插入图片描述
2. 计数器时钟
递减计数器的时钟由LSI经过一个8位的预分频器得到,我们可以操作预分频器寄存器IWDG_PR来设置分频因子, 分频因子可以是:[4,8,16,32,64,128,256,256]。

3. 计数器
独立看门狗的计数器是一个12位的递减计数器,最大值为0XFFF,当计数器减到0时,会产生一个复位信号:IWDG_RESET, 让程序重新启动运行,如果在计数器减到0之前刷新了计数器的值的话,就不会产生复位信号,重新刷新计数器值的这个动作我们俗称喂狗

4. 重装载寄存器
重装载寄存器是一个12位的寄存器,里面装着要刷新到计数器的值,这个值的大小决定着独立看门狗的溢出时间。在这里插入图片描述TLSI=1/FLSI=0.025msT _{LSI}=1/F_{LSI}=0.025msTLSI=1/FLSI=0.025msTIWDG=0.025ms×PR预分频系数×(RL+1)T_{IWDG}= 0.025ms × PR预分频系数 × (RL + 1) TIWDG=0.025ms×PR预分频系数×RL+1)
RL计数目标自己定义(范围:0x0000~0xFFFF),计数器的最大值为4095。

5. 键寄存器
键寄存器IWDG_KR可以说是独立看门狗的一个控制寄存器,主要有三种控制方式,往这个寄存器写入下面三个不同的值有不同的效果。
在这里插入图片描述
通过写往键寄存器写0XCCCC来启动看门狗是属于软件启动的方式,一旦独立看门狗启动,它就关不掉,只有复位才能关掉。
无论何时,只要在键寄存器IWDG_KR中写入0xAAAA, IWDG_RLR中的值就会被重新加载到计数器,从而避免产生看门狗复位 。

6. 状态寄存器
状态寄存器SR只有位0:PVU和位1:RVU有效,这两位只能由硬件操作,软件操作不了。RVU:看门狗计数器重装载值更新, 硬件置1表示重装载值的更新正在进行中,更新完毕之后由硬件清0。PVU:看门狗预分频值更新,硬件置’1’指示预分频值的更新正在进行中, 当更新完成后,由硬件清0。所以只有当RVU/PVU等于0的时候才可以更新重装载寄存器/预分频寄存器。

IWDG键寄存器扩展

在这里插入图片描述
键寄存器实际上是一种特殊的控制寄存器,它用于触发硬件电路的特定操作。例如,执行喂狗操作时,我们通过向键寄存器写入特定的值(如0XAAAA)来完成。下面解释为什么使用键寄存器而不是简单的控制位:

键寄存器的作用

  • 使用键寄存器而非单个控制位的原因在于,键寄存器提供了一种更可靠的硬件控制方式。在可能存在干扰的环境中,如程序跑飞或受到电磁干扰,单独的控制位可能会因误操作而意外改变状态。
  • 通过在整个键寄存器中写入一个特定的值来执行控制操作,可以显著降低因干扰导致的误操作风险。例如,如果键寄存器是16位的,只有当写入特定的数值0XAAAA时,才会执行喂狗操作,这样就减少了误触发喂狗操作的可能性。

写保护逻辑

  • 为了进一步增强指令的抗干扰能力,键寄存器的设计包含了写保护逻辑。这意味着执行任何写操作前,必须先写入一个指定的键值。
  • 在我们的系统中,除了键寄存器,还有PR(预分频器寄存器)、SR(状态寄存器)和RLR(重装载寄存器)等其他寄存器。由于SR是只读的,不需要写保护,但PR和RLR需要防止误写操作。
  • 为了保护PR和RLR,可以设置一个写保护机制。只有在键寄存器中写入特定的值(如5555)后,才能解除写保护。如果写入其他值,PR和RLR将再次受到保护,从而防止了误写操作
  • 这种设计确保了PR和RLR与键寄存器一起,得到了有效的保护,从而提高了系统的稳定性和可靠性。

通过这种方式,键寄存器不仅作为控制硬件电路的关键元素,还作为保护系统免受意外干扰的重要机制。

怎么用IWDG

独立看门狗一般用来检测和解决由程序引起的故障,比如一个程序正常运行的时间是50ms, 在运行完这个段程序之后紧接着进行喂狗,我们设置独立看门狗的定时溢出时间为60ms,比我们需要监控的程序50ms多一点, 如果超过60ms还没有喂狗,那就说明我们监控的程序出故障了,跑飞了,那么就会产生系统复位,让程序重新运行。

  1. 开启LSI时钟:
    虽然独立看门狗的时钟源是LSI(低速内部时钟),但这一步通常不需要手动操作。根据手册6.2.9的说明,一旦独立看门狗被使能,LSI时钟会自动开启,并且稳定后自动为IWDG提供时钟。因此,这一步在代码中通常不需要显式地开启LSI时钟。
  2. 解除写保护:
    在写入预分频器和重装载寄存器之前,必须先解除写保护。这通过写入特定的键值0X5555到IWDG_KR(键寄存器)来完成。
    在这里插入图片描述
  3. 写入预分频器和重装载值:
    解除写保护后,可以写入预分频器值到IWDG_PR(预分频器寄存器)和重装载值到IWDG_RLR(重装载寄存器)。
    在这里插入图片描述
    在这里插入图片描述
  4. 启动独立看门狗:
    配置完预分频器和重装载值后,通过向IWDG_KR写入0xCCCC来启动独立看门狗。这一步将使能看门狗并开始计数。
    在这里插入图片描述
  5. 喂狗:
    在主循环中,为了防止看门狗超时导致系统复位,需要定期向IWDG_KR写入0xAAAA来刷新计数器。这被称为“喂狗”。
    在这里插入图片描述
    喂狗和使能的时候会在键寄存器写入0x5555之外的值,这时就顺便给寄存器写保护了,所以写完寄存器器后我们不用手动执行写保护了。
    核心示例代码
    在这里插入图片描述

窗口独立狗

主要特性

  • 可编程的自由运行递减计数器
  • 条件复位
    • 当递减计数器的值小于0x40,(若看门狗被启动)则产生复位。
    • 当递减计数器在窗口外被重新装载,(若看门狗被启动)则产生复位。
  • 如果启动了看门狗并且允许中断,当递减计数器等于0x40时产生早期唤醒中断(EWI),它可以被用于重装载计数器以避免WWDG复位

功能描述

在这里插入图片描述
窗口看门狗的设计和操作流程与独立看门狗有显著差异,这可能是由于它们的设计理念和应用重点不同。以下是窗口看门狗的关键组成部分和工作流程:

时钟源和预分频器

  • 窗口看门狗的时钟源是PCLK1,通常是APB1的时钟,默认频率为36MHz。
  • 时钟源右侧是预分频器,称为WDGTB。它与独立看门狗的PR和定时器的PSC功能相同,用于调整计数器的时钟频率,从而影响计数器溢出时间。

6位递减计数器CNT

  • 计数器CNT位于控制寄存器CR内,它是一个6位递减计数器,尽管标记为T6到T0共七个位,但只有T5到T0这六位是有效的计数值。
  • 最高位T6用作溢出标志位。当T6位为1时,表示计数器未溢出;当T6位为0时,表示计数器已溢出,这时会触发系统复位。

窗口看门狗(WWDG)的6位递减计数器CNT的工作原理如下:

  1. 初始化:
  • 在窗口看门狗被启用之前,必须首先设置计数器的初始值。这个值通常是一个大于0x40的数(因为0x40是计数器的最小可设置值),以确保计数器在开始递减之前有足够的计数周期
    时钟源:
  • 计数器CNT的时钟源通常是PCLK1(APB1时钟),这个时钟源经过预分频器(WDGTB)分频后,提供给CNT作为计数脉冲。
  1. 预分频器(WDGTB):
  • 预分频器用于调整计数器的递减速率。它可以设置不同的分频系数,以改变计数器溢出的时间。
  1. 递减计数:
  • 一旦窗口看门狗被启用,并且计数器的初始值被设置,计数器CNT开始在每个时钟周期递减。由于CNT是6位递减计数器,它的最大值为0x3F(二进制111111)。
  1. 溢出标志(T6位):
  • 计数器的最高位T6用作溢出标志。当计数器的值从0x40(二进制1000000)递减到0x3F(二进制0111111)时,T6位从1变为0,这表示计数器溢出
  1. 喂狗操作:
  • 为了防止计数器溢出导致系统复位,必须在计数器值小于窗口值时更新计数器的值。这个过程称为“喂狗”。通过向控制寄存器CR写入一个新的计数值来更新CNT。
  1. 复位条件:
  • 如果计数器的值递减到0x3F并且T6位变为0,而没有及时“喂狗”,窗口看门狗会产生一个复位信号,导致系统复位。
  • 如果在窗口期内(即在计数器的值大于窗口值时)“喂狗”,也会产生复位,因为这是不允许的操作。

喂狗操作

  • 窗口看门狗没有单独的重装寄存器。要“喂狗”,即重置计数器,可以直接向CNT写入一个值。
  • 计数器的窗口值W6到W0用于设置喂狗的最早时间界限。这个值一旦设置,就不会改变。

复位信号输出逻辑

  • WDGA是窗口看门狗的激活位,写入1以启用窗口看门狗。
  • 当T6位为0时,表示计数器溢出,通过或门产生复位信号。在正常运行状态下,需要保持T6位为1以避免复位。
  • 如果不及时“喂狗”,计数器减到0后会产生复位。

喂狗时间窗口的实现流程

  • 在“喂狗”时,系统会比较当前计数器的值和预设的窗口值。
  • 如果当前计数器的值大于窗口值,表示“喂狗”得太早,比较器输出1,通过或门可以申请复位。
  • 这确保了只有在特定的时间窗口内“喂狗”才是有效的,从而提高了系统的安全性。

在这里插入图片描述
递减计数器T[6:0]等于0x40时可以产生早期唤醒中断(EWI),用于重装载计数器以避免WWDG复位
以下是这个过程的具体步骤和用途:

  1. 早期唤醒中断(EWI)触发:
  • 当计数器的值递减到0x40时,如果启用了EWI功能,则会触发一个中断。这个中断是在计数器溢出(即T6位从1变为0)之前触发的,因此它提供了一个“最后的机会”来执行一些紧急操作。
  1. 中断服务例程(ISR):
  • 在中断服务例程中,可以执行以下操作:
    • 保存重要数据: 如果系统中有正在处理的重要数据,可以在中断中将其保存到非易失性存储器中。
    • 关闭危险设备: 如果系统控制着某些可能造成伤害或损坏的设备,可以在中断中安全地关闭这些设备。
    • 执行紧急任务: 可以执行一些紧急的任务,以防止系统因超时而复位。
  1. 喂狗操作:
  • 在中断服务例程中,可以选择重新加载计数器的值(即“喂狗”),以防止系统复位。这样做可以允许系统继续运行,即使它已经接近了超时阈值。
  • 如果超时不是非常严重的问题,或者在某些情况下,系统可以容忍轻微的超时,可以在中断中执行喂狗操作,并可能只是记录一个错误或者向用户显示一个警告信息,而不是让系统复位。
  1. 防止系统复位:
  • 通过在中断中执行喂狗操作,可以防止系统复位,这对于那些不希望因看门狗超时而重启的系统来说非常有用。

WWDG超时时间

这里要多乘一个4096,是因为这里PCLK1进来之后,其实是先执行了一个固定的4096分频,这里框图没画出来,实际上是有的,因为36M的频率还是太快了,先来个固定分频给降一降。
在这里插入图片描述

IWDG和WWDG对比

在这里插入图片描述

代码实战:独立看门狗&窗口看门狗

  • 独立看门狗
    在这里插入图片描述
    在这里插入图片描述
    main.c
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Key.h"

int main(void)
{
	/*模块初始化*/
	OLED_Init();						//OLED初始化
	Key_Init();							//按键初始化
	
	/*显示静态字符串*/
	OLED_ShowString(1, 1, "IWDG TEST");
	
	/*判断复位信号来源*/
	if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET)	//如果是独立看门狗复位
	{
		OLED_ShowString(2, 1, "IWDGRST");			//OLED闪烁IWDGRST字符串
		Delay_ms(500);
		OLED_ShowString(2, 1, "       ");
		Delay_ms(100);
		
		RCC_ClearFlag();							//清除标志位
	}
	else											//否则,即为其他复位
	{
		OLED_ShowString(3, 1, "RST");				//OLED闪烁RST字符串
		Delay_ms(500);
		OLED_ShowString(3, 1, "   ");
		Delay_ms(100);
	}
	
	/*IWDG初始化*/
	IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);	//独立看门狗写使能
	IWDG_SetPrescaler(IWDG_Prescaler_16);			//设置预分频为16
	IWDG_SetReload(2499);							//设置重装值为2499,独立看门狗的超时时间为1000ms
	IWDG_ReloadCounter();							//重装计数器,喂狗
	IWDG_Enable();									//独立看门狗使能
	
	while (1)
	{
		Key_GetNum();								//调用阻塞式的按键扫描函数,模拟主循环卡死
		
		IWDG_ReloadCounter();						//重装计数器,喂狗
		
		OLED_ShowString(4, 1, "FEED");				//OLED闪烁FEED字符串
		Delay_ms(200);								//喂狗间隔为200+600=800ms
		OLED_ShowString(4, 1, "    ");
		Delay_ms(600);
	}
}

  • 窗口看门狗
    在这里插入图片描述
    在这里插入图片描述
  1. 开启窗口看门狗的APB1时钟:
    由于窗口看门狗的时钟来源是PCLK1(APB1时钟),因此第一步是开启APB1时钟。这与独立看门狗不同,后者使用LSI时钟,会自动开启。开启APB1时钟通常通过RCC(Reset and Clock Control)寄存器来完成。
  2. 配置寄存器:
    第二步是配置窗口看门狗的各个寄存器,包括预分频器和窗口值。窗口看门狗没有写保护机制,因此可以直接写入这些寄存器。
    预分频器(WWDG_CFR的WDGTB位)用于设置计数器的分频系数,窗口值(WWDG_CFR的W位)用于设置喂狗的时间窗口。
  3. 写入控制寄存器(CR):
    第三步是写入控制寄存器(WWDG_CR),这个寄存器包含了看门狗使能位(WDGA)、计数器溢出标志位(WDGON)和计数器有效位(T6)等。这些位需要一起设置,以使能窗口看门狗并开始计数。
  4. 喂狗:
    在系统运行过程中,需要定期向计数器写入新的重装载值来喂狗。这通过向WWDG_CR写入特定的值来完成,同时这个操作也必须在设定的时间窗口内执行,以避免系统复位。

main.c

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

int main(void)
{
	/*模块初始化*/
	OLED_Init();						//OLED初始化
	Key_Init();							//按键初始化
	
	/*显示静态字符串*/
	OLED_ShowString(1, 1, "WWDG TEST");
	
	/*判断复位信号来源*/
	if (RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET)	//如果是窗口看门狗复位
	{
		OLED_ShowString(2, 1, "WWDGRST");			//OLED闪烁WWDGRST字符串
		Delay_ms(500);
		OLED_ShowString(2, 1, "       ");
		Delay_ms(100);
		
		RCC_ClearFlag();							//清除标志位
	}
	else											//否则,即为其他复位
	{
		OLED_ShowString(3, 1, "RST");				//OLED闪烁RST字符串
		Delay_ms(500);
		OLED_ShowString(3, 1, "   ");
		Delay_ms(100);
	}
	
	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);	//开启WWDG的时钟 PCLK1时钟
	
	/*WWDG初始化*/
	WWDG_SetPrescaler(WWDG_Prescaler_8);			//设置预分频为 8
	WWDG_SetWindowValue(0x40 | 21);					//设置窗口值,窗口时间为30ms  T6位也要设置成1,所以或上0x40
	WWDG_Enable(0x40 | 54);							//使能并第一次喂狗,超时时间为50ms T6位也要设置成1,所以或上0x40
	
	while (1)
	{
		Key_GetNum();								//调用阻塞式的按键扫描函数,模拟主循环卡死
		
		OLED_ShowString(4, 1, "FEED");				//OLED闪烁FEED字符串
		Delay_ms(20);								//喂狗间隔为20+20=40ms
		OLED_ShowString(4, 1, "    ");
		Delay_ms(20);
		
		WWDG_SetCounter(0x40 | 54);					//重装计数器,喂狗
	}
}


网站公告

今日签到

点亮在社区的每一天
去签到