stm32看门狗系列

发布于:2025-02-13 ⋅ 阅读:(18) ⋅ 点赞:(0)

STM32 看门狗简介

看门狗(Watchdog) 是一种常用于微控制器中的定时器,它可以在程序出现故障或卡死时重新启动系统,以确保系统能够恢复正常运行。在 STM32 系列中,通常有两种类型的看门狗:独立看门狗(IWDG)窗口看门狗(WWDG)

1. 独立看门狗(IWDG)

独立看门狗(IWDG)是 STM32 系列中一个非常常见的看门狗,它用于在 MCU 出现故障时复位系统。

总结

这个框图描述了 STM32 的 独立看门狗(IWDG) 工作原理。IWDG 通过 LSI 时钟重载寄存器 定时,保证系统在遇到死循环或其他异常时能进行复位,恢复正常工作。看门狗的定时是独立于主系统时钟的,因此在系统发生故障时,IWDG 仍能继续工作,确保系统的可靠性。

  • 工作原理:IWDG 通过定期喂狗来重启 MCU。通过向看门狗寄存器写入一个特定的值来重置计数器,如果看门狗没有在预定的时间内被“喂食”,它会产生一个 复位信号,将 MCU 复位。

  • 独立看门狗(IWDG)框图功能说明:

  • LSI(低速内部时钟)

    • IWDG 使用 LSI(40 kHz) 作为定时器源。这个时钟源是独立于主系统时钟的,即使系统主时钟出现故障,IWDG 仍能工作,保证系统安全。
  • 预分频器(IWDG_PR)

    • IWDG_PR 是一个 8 位的预分频器,用来调整定时器的计数频率。通过调整预分频器,可以让 IWDG 计时器根据需要产生不同的超时周期。
  • 状态寄存器(IWDG_SR)

    • IWDG_SR 用于存储当前 IWDG 的状态,检测是否发生了复位或者其它状态信息。
  • 重载寄存器(IWDG_RLR)

    • IWDG_RLR 是 12 位的重载寄存器,它定义了 IWDG 定时器的周期(也就是定时器计时的上限)。如果在重载值设定的时间内没有进行“喂狗”操作,IWDG 会触发复位。
  • 12 位速率计数器(IWDG Counter)

    • IWDG 通过一个 12 位计数器来计算定时器超时,计数器会从重载寄存器加载的值开始计数,直到超时。
  • IWDG 控制寄存器(IWDG_KR)

    • IWDG_KR 是一个键寄存器,通过写入特定的密钥来启动或复位 IWDG 功能。
  • 复位功能

    • 如果 IWDG 计时器超时(即计时器未被“喂狗”),则触发 复位,以确保 MCU 被复位并重新启动。
  • 主要特点

    • 硬件独立性:即使主系统时钟故障,看门狗仍能正常工作。
    • 定时器:IWDG 内部使用 LSI(低速内部时钟) 作为定时源,具有独立于主系统时钟的特性。
    • 复位功能:超时后,IWDG 会触发一个 硬件复位,系统重新启动。
  • 使用方法

    1. 启动 IWDG,设置预分频器和计数器值。
    2. 在应用程序中定期“喂狗”(重新加载计数器)。
    3. 如果在规定时间内没有喂狗,IWDG 会复位 MCU。
  • 代码示例

#include "stm32f10x.h"

// 启动 IWDG 并设置计数器
void IWDG_Init(void) {
    // 使能 IWDG 外设时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_IWDG, ENABLE);

    // 配置 IWDG 时钟,设置预分频器和计数器值
    IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);  // 使能 IWDG 写访问
    IWDG_SetPrescaler(IWDG_Prescaler_64);  // 设置预分频器
    IWDG_SetReload(0xFFF);  // 设置重载值(最大值)
    
    // 启动 IWDG
    IWDG_Enable();
}

// 定期喂狗函数
void IWDG_Feed(void) {
    IWDG_ReloadCounter();  // 喂狗,重装计数器
}

int main(void) {
    SystemInit();  // 系统初始化
    IWDG_Init();  // 初始化看门狗

    while (1) {
        // 主循环中定期喂狗
        IWDG_Feed();
    }
}
2. 窗口看门狗(WWDG)

窗口看门狗(WWDG)与独立看门狗类似,但是它具有一个“窗口”功能,用于增强系统的可靠性。

总结

  • 工作原理:WWDG 会在设定的时间窗口内等待“喂狗”。如果在此窗口内没有喂狗,WWDG 将重置系统。不同的是,窗口看门狗要求喂狗操作在特定的时间窗口内完成,超过窗口时间将触发复位。

  • 框图分析:

    这个框图展示了 STM32 的 窗口看门狗(WWDG) 工作原理。窗口看门狗(WWDG)是一个定时器,常用于确保系统不会进入死循环或卡死状态。通过定期喂狗,可以避免系统复位。

    主要功能组件分析:
  • PCLK1 时钟(来自 RCC 时钟控制器)

    • WWDG 的时钟源是来自 PCLK1 时钟,该时钟可以是系统时钟的一部分,通过 RCC 时钟控制器 进行配置。
  • 窗口看门狗预分频器(WDGTB)

    • 用于生成用于看门狗计数器的时钟信号。通过预分频器调整时钟频率,确保看门狗的计时周期符合系统要求。
  • 窗口看门狗计数器(CNT)

    • 这是一个 6 位的计数器,每次递增。当计数器达到重载值时,会触发看门狗复位,除非在指定的“窗口”内进行了喂狗操作。
    • 窗口机制:窗口看门狗不同于独立看门狗,窗口机制要求在设定的时间窗口内喂狗,否则会触发复位。
  • 窗口看门狗配置寄存器(WWDG_CFR)

    • 配置寄存器用来设定 重载值窗口值,影响看门狗的计时行为。
    • W6 ~ W0:这些位用于设置窗口值,以定义喂狗操作必须发生的窗口。
  • 窗口看门狗 是一个可以在特定的时间窗口内进行喂狗操作的定时器。
  • 如果在这个时间窗口内没有喂狗,系统将会触发复位,保证系统的可靠性。
  • 该框图显示了 WWDG 的时钟、计数器、配置寄存器等各个模块是如何协同工作,来监控系统状态并确保其稳定运行的。
  • 窗口看门狗控制寄存器(WWDG_CR)

    • WDGA:启动窗口看门狗操作。写入此寄存器启用看门狗计数。
    • T6 ~ T0:这些位设置计数器的初始值,并决定计数器的重载值。
  • 比较器(Comparator)

    • 用于比较 WWDG_CR 寄存器的值与 WWDG_CFR 寄存器的窗口值,来决定是否可以喂狗。
    • 如果比较结果是 1,即在窗口内喂狗,那么系统将继续运行;如果比较结果是 0,则触发复位。
  • 主要特点

    • 时间窗口:需要在规定的时间窗口内进行喂狗操作,否则会复位系统。
    • 快速复位:通过控制喂狗的时间窗口,可以更严格地控制系统的稳定性。
  • 使用方法

    1. 启动 WWDG,设置计数器和窗口值。
    2. 在应用程序中定期“喂狗”,并确保在窗口内进行操作。
    3. 如果在窗口外喂狗,WWDG 会复位 MCU。
  • 代码示例

#include "stm32f10x.h"

// 启动 WWDG 并设置计数器和窗口值
void WWDG_Init(void) {
    // 使能 WWDG 外设时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);

    // 设置窗口值、计数器和预分频器
    WWDG_SetWindowValue(0x7F);  // 设置窗口值
    WWDG_SetCounter(0x7F);  // 设置计数器值
    WWDG_Enable(0x7F);  // 启动 WWDG
}

// 定期喂狗函数
void WWDG_Feed(void) {
    WWDG_SetCounter(0x7F);  // 在窗口内喂狗
}

int main(void) {
    SystemInit();  // 系统初始化
    WWDG_Init();  // 初始化窗口看门狗

    while (1) {
        // 主循环中定期喂狗
        WWDG_Feed();
    }
}

总结

  • 独立看门狗(IWDG):硬件独立、使用低速内部时钟,适用于系统保护,超时后会触发复位。
  • 窗口看门狗(WWDG):具有更严格的时间窗口控制,只有在指定时间内喂狗,才能避免复位。

两种看门狗的使用方式和设置方法有所不同,IWDG 更加简单且适用于大多数场景,而 WWDG 提供了更高的灵活性和保护。

项目:对IDWG进行一个检测,进行“喂狗”检测IWDG防止其复位,通过OLDE屏来显示检测结果

操作:

1判断IWDG的复位状态,可通过OLED屏来观察

2开始IWDG模式(LSI会被自动开启时钟设置)调用函数:IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);

3对键寄存器进行解除预分频值和重装载值的写保护

4设置预分频值和重装载值的参数(也就设置"喂狗"的时间) (设置1000ms的喂狗时间)

5调试喂狗的时间,在while循环里面延时一定时间定时喂狗观察设置的喂狗时间是否一致

#include "stm32f10x.h"                  // Device header
#include "Dog.h"
#include "oled.h"
#include "Delay.h"
void iwdg_Init()
{
	  OLED_Init();
	  OLED_ShowString (1,1,"IWDG TEST");
	if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST)!=RESET )
	{
	    OLED_ShowString (2,1,"IWDGRESET");
		  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);
      RCC_ClearFlag();
			
	}
	//WWDG的初始化
	//Tiwdg=TLSI*PR预分频系数*(RC+1)
	 IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
	 IWDG_SetPrescaler(IWDG_Prescaler_16);       //选择16分频
	IWDG_SetReload(2499);           //选择2499重装载值  总计算为1000ms
	IWDG_ReloadCounter();         //先提前喂狗一次
	IWDG_Enable();
	 while(1)
	 {
		 IWDG_ReloadCounter(); //每隔xxms喂狗一次
		 delay_ms (1100);     
		 
	 }
	
	
	
	
}

通过按键来进行喂狗操作:

#include "stm32f10x.h"                  // Device header
#include "Dog.h"
#include "oled.h"
#include "Delay.h"
#include  "key.h"
void iwdg_Init()
{  
	   key_Init();
	  OLED_Init();
	  OLED_ShowString (1,1,"IWDG TEST");
	if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST)!=RESET )
	{
	    OLED_ShowString (2,1,"IWDGRESET");
		  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);
      RCC_ClearFlag();
			
	}
	//WWDG的初始化
	//Tiwdg=TLSI*PR预分频系数*(RC+1)
	 IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
	 IWDG_SetPrescaler(IWDG_Prescaler_16);       //选择16分频
	IWDG_SetReload(2499);           //选择2499重装载值  总计算为1000ms
	IWDG_ReloadCounter();         //先提前喂狗一次
	IWDG_Enable();
	 while(1)
	 {
		 Get_keynum (); //如果一致按下按键,那么无法进行后面喂狗,就会复位
		 IWDG_ReloadCounter(); //每隔xxms喂狗一次
		 OLED_ShowString (4,1,"FEED");
		 delay_ms (200);
		 OLED_ShowString (4,1,"   ");
		 delay_ms (600);     
		  
	 }
	#include "stm32f10x.h"                  // Device header
#include "key.h"
#include  "Delay.h"


//按键模块,该模块建议独立文件
void key_Init()
{
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );
	GPIO_InitTypeDef key_inItsturt;
	key_inItsturt.GPIO_Mode = GPIO_Mode_IPU ;
	key_inItsturt.GPIO_Pin =GPIO_Pin_1 ;
	key_inItsturt.GPIO_Speed =GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &key_inItsturt);
	
	
	
}
uint8_t Get_keynum(void)
{
	uint8_t keynum=0;
	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1 )==RESET)
	{
		delay_ms (20);
		while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1 )==RESET);
		delay_ms (20);		
		keynum=1;
		
	}
	
	return keynum; 
}

IWDG(独立看门狗)的超时时间公式可以通过以下公式来计算:

超时时间=(重载值+1)×(预分频器值+1)LSI_频率\text{超时时间} = \frac{(重载值 + 1) \times (预分频器值 + 1)}{LSI\_频率}"

  • 重载值(IWDG_RLR):设置IWDG定时器的计数器上限,通常为12位(0~4095),表示计时器的计数周期。
  • 预分频器值(IWDG_PR):设置IWDG定时器的预分频器。该值可以是 4、8、16、32、64、128、256 中的一个。
  • LSI 频率:IWDG 使用 LSI(低速内部时钟) 作为时钟源,其频率为 40 kHz(标准值),但可以根据实际情况略有不同。

公式中的每个部分:

  • 重载值:设置定时器计数的最大值。
  • 预分频器:决定了定时器计数的频率。
  • LSI频率:独立时钟源频率,通常为 40 kHz。

举个例子

假设:

  • 重载值 = 0x0FFF (4095)
  • 预分频器 = 0x03(预分频器为 64)
  • LSI频率 = 40 kHz

则超时时间计算为:

超时时间计算为: 超时时间 = ( 4095 + 1 ) × ( 64 + 1 ) 40000 = 4096 × 65 40000 = 6.656 秒 超时时间= 40000 (4095+1)×(64+1) ​ = 40000 4096×65 ​ =6.656秒

WWDG(窗口看门狗)项目

操作:

1调用APB窗口看门狗的时钟,

2初始化窗口看门狗,包括设置预分频参数,窗口时间WDGTB(T位6保证为1,后五位设置想要"喂狗的时间区段")

3使能    WWDG_Enable()窗口看门狗,同时也要保证WDGTB T位6为1(进行一次初始喂狗)

4在while循环里面进行按键喂狗操作以及测试喂狗的时间

代码案例:


void wwdg_Init()
{
	  key_Init();
	  OLED_Init();
	  OLED_ShowString (1,1,"WWDG TEST");
		if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST )!=RESET )//判断WWDG复位情况
		{
			
			OLED_ShowString (2,1,"WWDGRESET");
		  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);
     
			
			
		}
		//初始化窗口看门狗
		RCC_APB1PeriphClockCmd( RCC_APB1Periph_WWDG,ENABLE );
		WWDG_SetPrescaler(WWDG_Prescaler_8);//2*2*2=8;
		WWDG_SetWindowValue(0x40|21);   //到窗口时间30ms
		WWDG_Enable(0x40|54);           //最晚一共50ms
		while(1)
		{ 
			

			 
			Get_keynum (); //如果一致按下按键,那么无法进行后面喂狗,就会复位
					 
	    //每隔xxms喂狗一次
		 OLED_ShowString (4,1,"FEED");
		 delay_ms (20);
		 OLED_ShowString (4,1,"   ");
		 delay_ms (10);       
		WWDG_SetCounter(0x40|54);
			
		}
	
}





void key_Init()
{
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );
	GPIO_InitTypeDef key_inItsturt;
	key_inItsturt.GPIO_Mode = GPIO_Mode_IPU ;
	key_inItsturt.GPIO_Pin =GPIO_Pin_1 ;
	key_inItsturt.GPIO_Speed =GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &key_inItsturt);
	
	
	
}
uint8_t Get_keynum(void)
{
	uint8_t keynum=0;
	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1 )==RESET)
	{
		delay_ms (20);
		while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1 )==RESET);
		delay_ms (20);		
		keynum=1;
		
	}

关于 窗口看门狗(WWDG)时间范围公式:

窗口看门狗的超时时间由两个因素决定:

  1. 计数器值(CNT):6位计数器的值,范围从 0 到 63(即 0x00 到 0x3F)。
  2. 窗口值:控制在指定的时间窗口内喂狗的时限。

公式

窗口看门狗的超时时间 T_window 的计算公式如下:

Twindow=(预分频器值+1)×(计数器值+1)PCLK1 时钟T_{window} = \frac{(预分频器值 + 1) \times (计数器值 + 1)}{PCLK1 \, 时钟}

  • 预分频器值(WDGTB):该值控制看门狗时钟的频率,常见值有 1, 2, 4, 8。具体选择哪个预分频器值取决于你的系统时钟(PCLK1)。
  • 计数器值(CNT):6 位计数器,范围从 0 到 0x3F。
  • PCLK1 时钟:这是窗口看门狗的时钟源,通常与系统时钟相同,可能是 72 MHz

举个例子

假设:

  • PCLK1 时钟 = 72 MHz
  • 预分频器值 = 4
  • 计数器值 = 0x3F(最大值)

窗口看门狗时间范围 为:

Twindow=(4+1)×(63+1)72×106=5×6472×106≈0.0000444 秒=44.4 μsT_{window} = \frac{(4 + 1) \times (63 + 1)}{72 \times 10^6} = \frac{5 \times 64}{72 \times 10^6} \approx 0.0000444 \, \text{秒} = 44.4 \, \mu s