STM32看门狗(独立看门狗与窗口看门狗)

简介

STM32 有两个看门狗,一个是独立看门狗(IWDG)另外一个是窗口看门狗(WWDG),独立看门狗号称宠物狗,窗口看门狗号称警犬。

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

窗口看门狗就是一个7位的递减计数器往下记,设定一个上窗口值,下窗口值固定,只能在上窗口和下窗口值之间进行复位,复位前可以触发一次紧急中断,可以做复位前觉得最重要的事件。STM32看门狗(独立看门狗与窗口看门狗)_第1张图片
STM32看门狗(独立看门狗与窗口看门狗)_第2张图片

分频

我的看门狗所在时钟是APB1的时钟主频是42M,数据手册上规定看门狗必须除于4096,你还可以通过CFR寄存器再进行一次分频(1,2,4,8)。CNT_CK=PCLK1/4096/(2^WDGTB)

窗口值

窗口值是由CFR寄存器决定的,下窗口值是固定的,寄存器的初始化值是0x7F,二进制为01111111,下窗口值为0x3F,所以上窗口值设定只能在0x3F到0X7F之间,即63到127之间。

超时计算

STM32看门狗(独立看门狗与窗口看门狗)_第3张图片

寄存器介绍

STM32看门狗(独立看门狗与窗口看门狗)_第4张图片
STM32看门狗(独立看门狗与窗口看门狗)_第5张图片

代码

中断优先级初始化

// WWDG 中断优先级初始化

static void WWDG_NVIC_Config(void)

{
	
  NVIC_InitTypeDef NVIC_InitStructure; 
  
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); 
  NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

WWDG配置函数

/* WWDG 配置函数
 * tr :递减计时器的值, 取值范围为:0x7f~0x40,超出范围会直接复位
 * wr :窗口值,取值范围为:0x7f~0x40
 * prv:预分频器值,取值可以是
	 *      @arg WWDG_Prescaler_1: WWDG counter clock = (PCLK1(42MHz)/4096)/1  约10253Hz 97us
	 *      @arg WWDG_Prescaler_2: WWDG counter clock = (PCLK1(42MHz)/4096)/2	 约5126Hz	195us
	 *      @arg WWDG_Prescaler_4: WWDG counter clock = (PCLK1(42MHz)/4096)/4	 约2563Hz	390us
	 *      @arg WWDG_Prescaler_8: WWDG counter clock = (PCLK1(42MHz)/4096)/8  约1281Hz	780us
	 *      
	 *			例:tr = 127(0x7f,tr的最大值)  wr = 80(0x50, 0x40为最小wr最小值)  prv =  WWDG_Prescaler_8
	 *			~780 * (127-80) = 36.6ms < 刷新窗口 < ~780 * 64 = 49.9ms
	 *			也就是说调用WWDG_Config进行这样的配置,若在之后的36.6ms前喂狗,系统会复位,在49.9ms后没有喂狗,系统也会复位。
	 *			需要在刷新窗口的时间内喂狗,系统才不会复位。	
 */
void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv)
{
	// 开启 WWDG 时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
	
	// 设置递减计数器的值
	WWDG_SetCounter( tr );
	
	// 设置预分频器的值
	WWDG_SetPrescaler( prv );
	
	// 设置上窗口值
	WWDG_SetWindowValue( wr );
	
	// 设置计数器的值,使能 WWDG
	WWDG_Enable(WWDG_CNT);
	
	// 清除提前唤醒中断标志位
	WWDG_ClearFlag();
	
	// 配置 WWDG 中断优先级
	WWDG_NVIC_Config();
	
	// 开 WWDG 中断
	WWDG_EnableIT();
}

死前中断函数

// WWDG 中断复服务程序,如果发生了此中断,表示程序已经出现了故障,
// 这是一个死前中断。在此中断服务程序中应该干最重要的事,
// 比如保存重要的数据等,这个时间具体有多长,要
// 由 WDGTB 的值决定:
// WDGTB:0 113us
// WDGTB:1 227us
// WDGTB:2 455us
// WDGTB:3 910us
void WWDG_IRQHandler(void)

{
	// 清除中断标志位
	WWDG_ClearFlag();

	//LED2 亮,点亮 LED 只是示意性的操作,
	//真正使用的时候,这里应该是做最重要的事情
	LED2(ON);
}

喂狗函数

// 喂狗
void WWDG_Feed(void)
{
	// 喂狗,刷新递减计数器的值,设置成最大WDG_CNT=0X7F
	WWDG_SetCounter( wwdg_cnt );
}

main函数

int main(void)
{
	Debug_USART_Config();
	printf("\r\n这是一个看门狗例程\r\n");
	
	uint8_t wwdg_tr, wwdg_wr;
	
	/* LED 端口初始化 */
	LED_GPIO_Config();
  
	// BLUE 蓝色灯亮
	LED3(ON);
	Delay(0XFFFFFF);	
	
	// WWDG配置
	
/* WWDG 配置函数
 * tr :递减计时器的值, 取值范围为:0x7f~0x40,超出范围会直接复位
 * wr :窗口值,取值范围为:0x7f~0x40
 * prv:预分频器值,取值可以是
	 *      @arg WWDG_Prescaler_1: WWDG counter clock = (PCLK1(42MHz)/4096)/1  约10253Hz 97us
	 *      @arg WWDG_Prescaler_2: WWDG counter clock = (PCLK1(42MHz)/4096)/2	 约5126Hz	195us
	 *      @arg WWDG_Prescaler_4: WWDG counter clock = (PCLK1(42MHz)/4096)/4	 约2563Hz	390us
	 *      @arg WWDG_Prescaler_8: WWDG counter clock = (PCLK1(42MHz)/4096)/8  约1281Hz	780us
	 *      
	 *			例:tr = 127(0x7f,tr的最大值)  wr = 80(0x50, 0x40为最小wr最小值)  prv =  WWDG_Prescaler_8
	 *			~780 * (127-80) = 36.6ms < 刷新窗口 < ~780 * 64 = 49.9ms
	 *			也就是说调用WWDG_Config进行这样的配置,若在之后的36.6ms前喂狗,系统会复位,在49.9ms后没有喂狗,系统也会复位。
	 *			需要在刷新窗口的时间内喂狗,系统才不会复位。	
*/	
	// 初始化WWDG:配置计数器初始值,配置上窗口值,启动WWDG,使能提前唤醒中断
	WWDG_Config(127,80,WWDG_Prescaler_8);	
	
	// 窗口值我们在初始化的时候设置成0X5F,这个值不会改变
	wwdg_wr = WWDG->CFR & 0X7F;
	
	while(1)
	{	
		// BLUE 蓝色灯
		LED3(OFF);
		//-----------------------------------------------------
		// 这部分应该写需要被WWDG监控的程序,这段程序运行的时间
		// 决定了窗口值应该设置成多大。
		//-----------------------------------------------------
		
		// 计时器值,初始化成最大0X7F,当开启WWDG时候,这个值会不断减小
		// 当计数器的值大于窗口值时喂狗的话,会复位,当计数器减少到0X40
		// 还没有喂狗的话就非常非常危险了,计数器再减一次到了0X3F时就复位
		// 所以要当计数器的值在窗口值和0X40之间的时候喂狗,其中0X40是固定的。
		wwdg_tr = WWDG->CR & 0X7F;
		
		if( wwdg_tr < wwdg_wr )
		{
			// 喂狗,重新设置计数器的值为最大0X7F
			WWDG_Feed();
		}
	}
}

你可能感兴趣的:(单片机,stm32,arm)