STM32标准库——(20)WDG看门狗

目录

1.WDG简介

2.IWDG框图

3.IWDG键寄存器

4.IWDG超时时间

5.WWDG框图

6.WWDG工作特性

7.WWDG超时时间

8.IWDG和WWDG对比

9.相关API

9.1 独立看门狗

9.1.1 IWDG_WriteAccessCmd

9.1.2 IWDG_SetPrescaler

9.1.3 IWDG_SetReload

9.1.4 IWDG_ReloadCounter

9.1.5 IWDG_Enable

9.1.6 IWDG_GetFlagStatus

9.1.7 RCC_GetFlagStatus

9.2 窗口看门狗

9.2.1 WWDG_SetPrescaler

9.2.2 WWDG_SetWindowValue

9.2.3 WWDG_SetCounter

9.2.4 WWDG_Enable

9.2.5 WWDG_GetFlagStatus

9.2.6 WWDG_ClearFlag

10.独立看门狗

10.1 接线图

10.2 相关代码

11.窗口看门狗

11.1 接线图

11.2 相关代码


1.WDG简介

独立看门狗(IWDG)由专用的低速时钟(LSI)驱动,即使主时钟发生故障它也仍然有效。窗口看门狗由从APB1时钟分频后得到的时钟驱动,通过可配置的时间窗口来检测应用程序非正常的过迟或过早的操作

2.IWDG框图

  • 它的结构和定时器是非常相似的,只不过是定时器溢出产生中断,而看门狗定时器溢出直接产生复位信号,然后喂狗操作其实也就是重置这个计数器,这是一个递减计数器减到零之后就复位,那程序正常运行时,为了避免复位,就得在这个计数器减到零之前,及时把记数值加大点,这个操作就是喂狗,如果你程序卡死了,没有及时加大这个记数值,那减到零之后就自动复位了,就是看门狗的工作逻辑。
  • 预分频器之前输入时钟是LSI内部低速时钟,时钟频率为40KHz,之后时钟进入预分频器进行分频,这个预分频器只有8位,所以它最大只能进行256分频,上面这个预分频寄存器,IWDG_PR可以配置分频系数,这个PR和定时器的PSC是一个意思,他们都是Prescaler的缩写,可能不是一个人设计的,所以这手册里很多缩写都不太一样,不过大家要知道他们其实是一个意思,后面经过预分配器分频之后,时钟驱动递减计数器,每来一个时钟自减一个数,另外这个计数器是12位的,所以最大值是2^12-1=4095,然后当自减到0之后,产生IEDG复位,正常运行时,为了避免复位,我们可以提前在重装寄存器写个值,IWDG_RLR和定时器的ARR是一样的,RLR是reloader,ARR是auto reloader,那当我们预先写好值之后,在运行过程中,我们在这个键寄存器里写个特定数据,控制电路进行喂狗,这时重装值就会复制到当前的计数器中,这样计数器就会回到重装值,重新自减运行了,然后这里有个状态寄存器SR,就是标志电路运行的状态了,其实这个SR里没什么东西,就只有两个更新同步位,基本不用看,最后上面这些寄存器位于1.8V供电区下面主要的工作电路都位于VDD供电区,所以这下面写了看门狗功能处于vdd供电区即在停机和待机模式时仍能正常工作,上节我们也说过,独立开门口也是唤醒待机模式的四个条件之一。

3.IWDG键寄存器

  1. 键寄存器(IWDG_KR)中写入0xCCCC,开始启用独立看门狗;此时计数器开始从其复位值0xFFF递减计数当计数器计数到末尾0x000时,会产生一个复位信号(IWDG_RESET)
  2. 无论何时,只要在键寄存器IWDG_KR中写入0xAAAA, IWDG_RLR中的值就会被重新加载到计数器,从而避免产生看门狗复位
  3. IWDG_PR和IWDG_RLR寄存器具有写保护功能。要修改这两个寄存器的值,必须先向IWDG_KR寄存器中写入0x5555。以不同的值写入这个寄存器将会打乱操作顺序,寄存器将重新被保护重装载操作(即写入0xAAAA)也会启动写保护功能。状态寄存器指示预分频值和递减计数器是否正在被更新。

4.IWDG超时时间

FLSI是40KHz 则TLSI是0.025ms TIWDG是自己想要设置的值 再通过该值寻找最长时间里面哪个合适 对应的预分频系数写入 通过公式可以计算出RL(重装值)

5.WWDG框图

  • 时钟来源是PCLK1,也就是APB1的时钟,这个时钟默认是36MHz,所以就是36MHz的时钟进来,之后还是先经过一个预分频器进分频,这个和独立看门狗的预分频器,定时器的预分频器都是一个作用,就是灵活的调节后面计数器的时钟频率,同时预分频系数也是计算计数器溢出时间的重要参数,那接着分频之后的时钟驱动这个计数器进行计数,这个计数器和独立看门狗一样,也是一个递减计数器,每来一个时钟自减一次,不过这个计数器比较特殊,从图上来看,这里写了T6到T0,总共是七个位,但下面却写的是六位递减计数器,这是为什么呢,那这其实是因为这个计数器只有T5到T0这六位是有效的就值,最高位T6这里用来当做溢出标志位,第六位等于1时,表示计数器没溢出,T6位等于0时表示计数器溢出,不过对于硬件电路来说,T6位其实也是计数器的一部分,只不过是T6位被单独拎出来,当做标志位了而已。总结一下,就是如果你把T6位看作是计数器的一部分,那要是整个计数器值减到0X40之后移出,而如果你把T6位当成溢出标志位,低6位当做计数器,那就是低6位的计数值减到0之后溢出,这一点尤其要搞清楚。左边的复位(箭头指向复位)信号输出部分,首先这个WDGA是窗口看门狗的激活位,也就是使能,WDGA写入1启用窗口看门狗,使能位作用于这个与门
  • T6位一旦等于零(小圆圈取反),就表示计数器溢出,产生复位信号,那在程序正常运行状态下,我们必须始终保证T6位为一,这样才能避免复位,下面这一块实现的功能和独立看门狗基本是一样的,如果不及时喂狗,6位的计数器减到0后就产生复位

6.WWDG工作特性

7.WWDG超时时间

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

FPCLK1是36MHz 则TPCLK1是1/36

8.IWDG和WWDG对比

9.相关API

9.1 独立看门狗

9.1.1 IWDG_WriteAccessCmd
/**
  * @brief  Enables or disables write access to IWDG_PR and IWDG_RLR registers.
  * @param  IWDG_WriteAccess: new state of write access to IWDG_PR and IWDG_RLR registers.
  *   This parameter can be one of the following values:
  *     @arg IWDG_WriteAccess_Enable: Enable write access to IWDG_PR and IWDG_RLR registers
  *     @arg IWDG_WriteAccess_Disable: Disable write access to IWDG_PR and IWDG_RLR registers
  * @retval None
  */
void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess)
功能:
	使能或者失能对寄存器 IWDG_PR 和 IWDG_RLR 的写操作
参数:
	IWDG_WriteAccess:对寄存器 IWDG_PR 和 IWDG_RLR 的写操作的新状态
返回值:
	无
9.1.2 IWDG_SetPrescaler
/**
  * @brief  Sets IWDG Prescaler value.
  * @param  IWDG_Prescaler: specifies the IWDG Prescaler value.
  *   This parameter can be one of the following values:
  *     @arg IWDG_Prescaler_4: IWDG prescaler set to 4
  *     @arg IWDG_Prescaler_8: IWDG prescaler set to 8
  *     @arg IWDG_Prescaler_16: IWDG prescaler set to 16
  *     @arg IWDG_Prescaler_32: IWDG prescaler set to 32
  *     @arg IWDG_Prescaler_64: IWDG prescaler set to 64
  *     @arg IWDG_Prescaler_128: IWDG prescaler set to 128
  *     @arg IWDG_Prescaler_256: IWDG prescaler set to 256
  * @retval None
  */
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler)
功能:
	设置 IWDG 预分频值
参数:
	IWDG_Prescaler:IWDG 预分频值
返回值:
	无    
9.1.3 IWDG_SetReload
/**
  * @brief  Sets IWDG Reload value.
  * @param  Reload: specifies the IWDG Reload value.
  *   This parameter must be a number between 0 and 0x0FFF.
  * @retval None
  */
void IWDG_SetReload(uint16_t Reload)
功能:
	设置 IWDG 重装载值
参数:
	IWDG_Reload:IWDG 重装载值
返回值:
	无     
9.1.4 IWDG_ReloadCounter
/**
  * @brief  Reloads IWDG counter with value defined in the reload register
  *   (write access to IWDG_PR and IWDG_RLR registers disabled).
  * @param  None
  * @retval None
  */
void IWDG_ReloadCounter(void)
功能:
	按照 IWDG 重装载寄存器的值重装载 IWDG 计数器
参数:
	无
返回值:
	无     
    
9.1.5 IWDG_Enable
/**
  * @brief  Enables IWDG (write access to IWDG_PR and IWDG_RLR registers disabled).
  * @param  None
  * @retval None
  */
void IWDG_Enable(void)
功能:
	使能 IWDG
参数:
	无
返回值:
	无      
9.1.6 IWDG_GetFlagStatus
/**
  * @brief  Checks whether the specified IWDG flag is set or not.
  * @param  IWDG_FLAG: specifies the flag to check.
  *   This parameter can be one of the following values:
  *     @arg IWDG_FLAG_PVU: Prescaler Value Update on going
  *     @arg IWDG_FLAG_RVU: Reload Value Update on going
  * @retval The new state of IWDG_FLAG (SET or RESET).
  */
FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG)
功能:
	检查指定的 IWDG 标志位被设置与否
参数:
	IWDG_FLAG:待检查的 I2C 标志位
返回值:
	IWDG_FLAG 的新状态(SET 或者 RESET)       
9.1.7 RCC_GetFlagStatus
/**
  * @brief  Checks whether the specified RCC flag is set or not.
  * @param  RCC_FLAG: specifies the flag to check.
  *   
  *   For @b STM32_Connectivity_line_devices, this parameter can be one of the
  *   following values:
  *     @arg RCC_FLAG_HSIRDY: HSI oscillator clock ready
  *     @arg RCC_FLAG_HSERDY: HSE oscillator clock ready
  *     @arg RCC_FLAG_PLLRDY: PLL clock ready
  *     @arg RCC_FLAG_PLL2RDY: PLL2 clock ready      
  *     @arg RCC_FLAG_PLL3RDY: PLL3 clock ready                           
  *     @arg RCC_FLAG_LSERDY: LSE oscillator clock ready
  *     @arg RCC_FLAG_LSIRDY: LSI oscillator clock ready
  *     @arg RCC_FLAG_PINRST: Pin reset
  *     @arg RCC_FLAG_PORRST: POR/PDR reset
  *     @arg RCC_FLAG_SFTRST: Software reset
  *     @arg RCC_FLAG_IWDGRST: Independent Watchdog reset
  *     @arg RCC_FLAG_WWDGRST: Window Watchdog reset
  *     @arg RCC_FLAG_LPWRRST: Low Power reset
  * 
  *   For @b other_STM32_devices, this parameter can be one of the following values:        
  *     @arg RCC_FLAG_HSIRDY: HSI oscillator clock ready
  *     @arg RCC_FLAG_HSERDY: HSE oscillator clock ready
  *     @arg RCC_FLAG_PLLRDY: PLL clock ready
  *     @arg RCC_FLAG_LSERDY: LSE oscillator clock ready
  *     @arg RCC_FLAG_LSIRDY: LSI oscillator clock ready
  *     @arg RCC_FLAG_PINRST: Pin reset
  *     @arg RCC_FLAG_PORRST: POR/PDR reset
  *     @arg RCC_FLAG_SFTRST: Software reset
  *     @arg RCC_FLAG_IWDGRST: Independent Watchdog reset
  *     @arg RCC_FLAG_WWDGRST: Window Watchdog reset
  *     @arg RCC_FLAG_LPWRRST: Low Power reset
  *   
  * @retval The new state of RCC_FLAG (SET or RESET).
  */
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG)
功能:
	检查指定的 RCC 标志位设置与否
参数:
	RCC_FLAG:待检查的 RCC 标志位
返回值:
	RCC_FLAG 的新状态(SET 或者 RESET)   

9.2 窗口看门狗

9.2.1 WWDG_SetPrescaler
/**
  * @brief  Sets the WWDG Prescaler.
  * @param  WWDG_Prescaler: specifies the WWDG Prescaler.
  *   This parameter can be one of the following values:
  *     @arg WWDG_Prescaler_1: WWDG counter clock = (PCLK1/4096)/1
  *     @arg WWDG_Prescaler_2: WWDG counter clock = (PCLK1/4096)/2
  *     @arg WWDG_Prescaler_4: WWDG counter clock = (PCLK1/4096)/4
  *     @arg WWDG_Prescaler_8: WWDG counter clock = (PCLK1/4096)/8
  * @retval None
  */
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler)
功能:
	设置 WWDG 预分频值值
参数:
	WWDG_Prescaler:指定 WWDG 预分频
返回值:
	无           
9.2.2 WWDG_SetWindowValue
/**
  * @brief  Sets the WWDG window value.
  * @param  WindowValue: specifies the window value to be compared to the downcounter.
  *   This parameter value must be lower than 0x80.
  * @retval None
  */
void WWDG_SetWindowValue(uint8_t WindowValue)
功能:
	设置 WWDG 窗口值
参数:
	WindowValue r:指定的窗口值。该参数取值必须在 0x40 与 0x7F 之间。
返回值:
	无    
9.2.3 WWDG_SetCounter
/**
  * @brief  Sets the WWDG counter value.
  * @param  Counter: specifies the watchdog counter value.
  *   This parameter must be a number between 0x40 and 0x7F.
  * @retval None
  */
void WWDG_SetCounter(uint8_t Counter)
功能:
	设置 WWDG 计数器值
参数:
	Counter:指定看门狗计数器值。该参数取值必须在 0x40 与 0x7F 之间。
返回值:
	无      
9.2.4 WWDG_Enable
/**
  * @brief  Enables WWDG and load the counter value.                  
  * @param  Counter: specifies the watchdog counter value.
  *   This parameter must be a number between 0x40 and 0x7F.
  * @retval None
  */
void WWDG_Enable(uint8_t Counter)
功能:
	使能 WWDG 并装入计数器值
参数:
	Counter:指定看门狗计数器值。该参数取值必须在 0x40 与 0x7F 之间。
返回值:
	无      
9.2.5 WWDG_GetFlagStatus
/**
  * @brief  Checks whether the Early Wakeup interrupt flag is set or not.
  * @param  None
  * @retval The new state of the Early Wakeup interrupt flag (SET or RESET)
  */
FlagStatus WWDG_GetFlagStatus(void)
功能:
	检查 WWDG 早期唤醒中断标志位被设置与否
参数:
	无
返回值:
	早期唤醒中断标志位的新状态(SET 或者 RESET)        
9.2.6 WWDG_ClearFlag
/**
  * @brief  Clears Early Wakeup interrupt flag.
  * @param  None
  * @retval None
  */
void WWDG_ClearFlag(void)
功能:
	清除早期唤醒中断标志位
参数:
	无
返回值:
	无

10.独立看门狗

10.1 接线图

10.2 相关代码

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();							//清除标志位 若不清除标志位 则即使按下复位键 也不会自动清0 则会产生看门狗复位 就算下次是正常的复位键复位 也会判断为看门狗复位
	}
	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();							//重装计数器,喂狗,这样子之后第一行周期就是1000ms,因为喂完一次狗 计数器会从1000开始自减
	IWDG_Enable();									//独立看门狗使能
	
	while (1)
	{
		Key_GetNum();								//调用阻塞式的按键扫描函数,模拟主循环卡死,即程序不会执行下面代码,则不会喂狗,则会产生独立看门狗复位
		
		IWDG_ReloadCounter();						//重装计数器,喂狗,每800ms喂一次狗
		
		OLED_ShowString(4, 1, "FEED");				//OLED闪烁FEED字符串
		Delay_ms(200);								//喂狗间隔为200+600=800ms
		OLED_ShowString(4, 1, "    ");
		Delay_ms(600);
	}
}

现象:上电之后先喂一次狗 后续计数值为1000 进入循环后每隔800ms喂一次狗 oled屏闪烁FEED字样 若按下复位键复位 则会出现RST字样 若按下独立按键不放 则不会800ms喂一次狗 触发看门狗复位 oled屏出现IDWRST字样

11.窗口看门狗

11.1 接线图

11.2 相关代码

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的时钟
	
	/*WWDG初始化*/
	WWDG_SetPrescaler(WWDG_Prescaler_8);			//设置预分频为8
	WWDG_SetWindowValue(0x40 | 21);					//设置窗口值,窗口时间为30ms,|0x40(0100 0000)是让T6位置1 才能参与与门打开复位
	WWDG_Enable(0x40 | 54);							//使能并第一次喂狗,超时时间为50ms,|0x40(0100 0000)是让T6位置1 才能参与与门打开复位
	
	while (1)
	{
		Key_GetNum();								//调用阻塞式的按键扫描函数,模拟主循环卡死
		
//      WWDG_SetCounter(0x40 | 54);					//重装计数器,喂狗
//不放在这里而放在delay函数后面的原因是:上面定义30-50ms内不会触发喂狗 若在这里喂狗 则时间可能在30ms之前 会触发看门狗复位 所以需要在闪烁字符串后喂狗 则在30-50之间
		OLED_ShowString(4, 1, "FEED");				//OLED闪烁FEED字符串
		Delay_ms(20);								//喂狗间隔为20+20=40ms
		OLED_ShowString(4, 1, "    ");
		Delay_ms(20);
		
		WWDG_SetCounter(0x40 | 54);					//重装计数器,喂狗
	}
}

现象:接上电源后喂狗一次 设置窗口时间和超时时间分别是30ms和50ms 在此范围内不发生看门狗复位 在此范围外则发生看门狗复位 函数进入主循环 若按键没按下则OLED显示FEED字样不断闪烁 后面喂狗一次则在30-50之间 不会产生看门狗复位 按下按键 程序阻塞无法执行下面延时 则相当于超时喂狗 会产生看门狗复位 若要观察过快喂狗现象 则可以将一个Delay注释掉 让另一个Delay的值小于或等于30 则每次喂狗在30ms之前 会产生看门狗复位

  • 19
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32F103C8T6是一款基于ARM Cortex-M3内核的微控制器,它具有看门狗(Watchdog)功能。看门狗是一种硬件定时器,用于监控系统的运行状态,当系统出现异常情况时,看门狗会自动重启系统,保证系统的稳定性和可靠性。 在STM32F103C8T6中,看门狗的配置需要以下步骤: 1. 使能看门狗时钟:通过RCC寄存器使能看门狗时钟。 2. 配置看门狗预分频器和重载值:看门狗预分频器和重载值用于确定看门狗计数器的计数周期,通过IWDG_PR和IWDG_RLR寄存器进行配置。 3. 启动看门狗:配置好看门狗后,通过IWDG_KR寄存器启动看门狗。 4. 定时喂狗:在系统运行正常时,需要定时喂狗,以避免看门狗超时,导致系统重启。通过IWDG_KR寄存器定时喂狗。 以下是一个简单的示例代码,演示如何配置和使用看门狗: ``` #include "stm32f10x.h" void WDG_Init(void) { RCC_APB1PeriphResetCmd(RCC_APB1Periph_IWDG, ENABLE); // 使能看门狗时钟 IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); // 允许写入IWDG_PR和IWDG_RLR寄存器 IWDG_SetPrescaler(IWDG_Prescaler_256); // 配置预分频器,分频系数为256 IWDG_SetReload(0xFFF); // 配置重载值,最大值为0xFFF IWDG_ReloadCounter(); // 重载看门狗计数器 IWDG_Enable(); // 启动看门狗 } int main(void) { WDG_Init(); // 初始化看门狗 while(1) { // 定时喂狗 IWDG_ReloadCounter(); // 喂狗 } } ``` 在上面的例子中,预分频器的分频系数为256,重载值为0xFFF,这意味着看门狗计数器的计数周期为256*4096/40M=26.2144ms,如果系统在这个周期内没有重载看门狗计数器,那么看门狗就会超时,导致系统重启。通过定时喂狗,可以避免这种情况的发生。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值