【STM32标准库】看门狗

1.看门狗简介

看门狗起始就是一个定时器,从功能上说它可以让微控制器在程序发生意外(程序进入死循环或跑飞)的时候,能重新恢复到系统刚上电状态,以保障系统出问题的时候可以重启一次。说的简单一点,看门狗就是能让程序出问题时能重新启动系统。STM32有两个看门狗,独立看门狗和窗口看门狗。

1.1独立看门狗(Independent Watchdog,IWDG)

独立看门狗号称宠物狗,它有一个12位的递减计数器,当计数器的值从某个值一直减到0的时候,系统就会产生一个复位信号,即IWDG_RESET。如果在计数器没有减到0之前,刷新了计数器的值,那么就不会产生复位信号,这个动作就是我们经常说的喂狗。

1.2独立看门狗时钟

独立看门狗的时候由独立的RC振荡器LSI提供,即使主时钟发生故障它仍然有效,非常独立。LSI的频率一般在30~60KHz之间,所以独立看门狗的定时时间并不一定非常准确,只适用于对时间精度要求比较低的场合。

在这里插入图片描述

上图中,配置的IWDG时钟CK_IWDG=32KHz。

1.3独立看门狗计数器时钟

递减计数器的时钟由LSI经过一个8位的预分频器得到,我们可以操作预分频器寄存器IWDG_PR来设置分频因子,分频因子可以是:[4,8,16,32,64,128,256],计数器时钟CK_CNT=CK_IWDG/IWDG_PR。

1.4重装载寄存器

重装载寄存器是一个12位的寄存器,里面装着要刷新到计数器的值,这个值的大小决定着独立看门狗的溢出时间。超时时间Tout=1/CK_CNT*rlv,rlv是重装载寄存器的值。

若IWDG_PR=32,rlv=2000,所以CK_CNT=32KHz/32=1KHz,Tout=1/1000*2000=2s。意味着2s之内我们就得喂狗,不然系统就会重启。

1.5标准库演示
#ifndef __BSP_IWDG_H
#define __BSP_IWDG_H

#ifdef __cplusplus
extern "C"{

#endif

#include "stm32f4xx.h"

void Init_IWDG(uint8_t prv,uint16_t rlv);
void IWDG_Feed(void);
	
#ifdef __cplusplus
}
#endif

#endifc
#include "bsp_iwdg.h"

/*
* 设置 IWDG 的超时时间
* Tout = prv/LSICLK * rlv (s)
*      prv可以是[4,8,16,32,64,128,256]
* prv:预分频器值,取值如下:
*     @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
*
*    独立看门狗使用LSI作为时钟。
*    LSI 的频率一般在 30~60KHZ 之间,根据温度和工作场合会有一定的漂移,我
*    们的STM32F407中为32KHz,所以独立看门狗的定时时间并不一定非常精确,只适用于对时间精度
*    要求比较低的场合。
*
* rlv:预分频器值,取值范围为:0-0XFFF
* 函数调用举例:
* Init_IWDG(IWDG_Prescaler_32 ,1000);  // IWDG 1s 超时溢出
*            (32/LSICLK)*1000 = 1s
*/
void Init_IWDG(uint8_t prv,uint16_t rlv)
{
	// 使能 预分频寄存器PR和重装载寄存器RLR可写
	IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
	
	// 设置预分频器值
	IWDG_SetPrescaler(prv);
	
	// 设置重装载寄存器值
	IWDG_SetReload(rlv);
	
	// 把重装载寄存器的值放到计数器中
	IWDG_ReloadCounter();
	
	// 使能 IWDG
	IWDG_Enable();
}

void IWDG_Feed(void)
{
    // 把重装载寄存器的值放到计数器中,喂狗,防止IWDG复位
    // 当计数器的值减到0的时候会产生系统复位
    IWDG_ReloadCounter();
}

int main(void)
{
	Init_LED();
	
//	//设置中断分组
//	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
//	
//	Init_USART();
	
	Init_IWDG(IWDG_Prescaler_32,1000);
	
  /* Infinite loop */
  while (1)
  {
  }
}

上述代码思路为:Init_LED()中会将LED点亮,然后开启独立看门狗,设置的溢出时间为1s,那么1s后由于没有喂狗,mcu会复位,LED也会灭,但是由于时间太快了,肉眼应该无法看到。所以,我们使用了示波器进行测试LED的输入电平。

在这里插入图片描述

int main(void)
{
	Init_LED();
	
//	//设置中断分组
//	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
//	
//	Init_USART();
	
	Init_IWDG(IWDG_Prescaler_32,1000);
	
  /* Infinite loop */
  while (1)
  {
	  IWDG_Feed();
  }
}

如果我们在巡航中一直喂狗,那么mcu就不会复位。

2.窗口看门狗(Window Watchdog,WWDG)

窗口看门狗号称警犬,它也有一个递减计数器不断的往下递减计数,当减到一个固定值0x40时还不喂狗的话,就会产生复位,这个值叫窗口的下限,是固定值,不能改变。不同的是,窗口看门狗的计数器在减到某一个数之前喂狗也会产生复位,这个值叫窗口的上限,上限值由用户独立设置。窗口看门狗计数器的值必须在上窗口和下窗口之间才可以喂狗,这就是窗口看门狗中窗口两个字的含义。

IWDG与WWDG区别

RLR是重装载寄存器,用来设置独立看门狗的计数器的值。TR是窗口看门狗的计数器的值,由用户独立设置,WR是窗口看门狗的上窗口值,由用户独立设置。

在出现下述两种情况之一时产生看门狗复位:

  1. 当喂狗的时候如果计数器的值大于窗口上限值。
  2. 当计数器的数值从0x40减到0x3F。

如果启动了看门狗并且使能中断,当递减计数器等于0x40时产生早期唤醒中断(EWI),这个中断我们称它为死前中断或者叫遗嘱中断, 在中断函数里面我们应该出来最重要的事情,而且必须得快,因为递减计数器再减一次,就会产生系统复位。

注意事项:

  1. 上限值必须大于0x40,否则就无窗口了。
  2. 窗口看门狗时钟来源PCLK1(APB1总线时钟)分频后。
2.1标准库演示
#ifndef __BSP_WWDG_H
#define __BSP_WWDG_H

#ifdef __cplusplus
extern "C"{

#endif

#include "stm32f4xx.h"

#define WWDG_CNT    0x7F

void Init_WWDG(uint8_t tr, uint8_t wr, uint32_t prv);
void WWDG_Feed(void);

#ifdef __cplusplus
}
#endif

#endif


#include "bsp_wwdg.h"
#include "stdio.h"

/* WWDG 配置函数
* tr :递减计时器的值, 取值范围为:0x7f~0x40
* wr :窗口值,取值范围为:0x7f~0x40
* prv:预分频器值,取值可以是
*      @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
*/
void Init_WWDG(uint8_t tr, uint8_t wr, uint32_t prv)
{
	//使能窗口看门狗时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);
	
	// 设置预分频器值
	WWDG_SetPrescaler(prv);
	
	// 设置重装载寄存器值
	WWDG_SetWindowValue(wr);
	
	// 使能 WWDG
	WWDG_Enable(WWDG_CNT&tr);
	
	//配置中断控制器并使能中断
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel=WWDG_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=3;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;
	NVIC_Init(&NVIC_InitStruct);
	
	WWDG_ClearFlag();//清楚标志位
	WWDG_EnableIT();//使能中断
}

void WWDG_IRQHandler(void)
{
	WWDG_SetCounter(WWDG_CNT);
	WWDG_ClearFlag();
}

void WWDG_Feed(void)
{
	printf("WWDG_Feed\r\n");
    // 把重装载寄存器的值放到计数器中,
    WWDG_SetCounter(WWDG_CNT);
}

int main(void)
{
	Init_USART();
	
	Init_LED();
	
	//设置中断分组
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
		
	Init_WWDG(0x7f,0x5f,WWDG_Prescaler_8);
	
	printf("hello,this is stm32f407\r\n");
  /* Infinite loop */
  while (1)
  {
        //-----------------------------------------------------
        // 这部分应该写需要被WWDG监控的程序,这段程序运行的时间
        // 决定了窗口值应该设置成多大。
        //-----------------------------------------------------
      
	    // 计时器值,初始化成最大0X7F,当开启WWDG时候,这个值会不断减小
        // 当计数器的值大于窗口值时喂狗的话,会复位,当计数器减少到0X40
        // 还没有喂狗的话就非常非常危险了,计数器再减一次到了0X3F时就复位
        // 所以要当计数器的值在窗口值和0X40之间的时候喂狗,其中0X40是固定的。
        if ( (WWDG->CR & 0X7F) < 0x5f )
		{
            // 喂狗,重新设置计数器的值为最大0X7F
            WWDG_Feed();
        }
  }
}

注意,我们试过了在死前中断中喂狗,但是好像来不及,mcu还是重启了。所以,我们在main函数中进行了计数判断喂狗。

主函数中我们把WWDG的计数器的值设置 为0X7F,上窗口值设置为0X5F,分频系数为8分频。在while死循环中,我们不断读取计数器的值, 当计数器的值减小到小于上窗口值的时候,我们喂狗,让计数器重新计数。

在while死循环中,一般是我们需要监控的程序,这部分代码的运行时间,决定了上窗口值应该设置为多少,当监控的程序运行完毕之后, 我们需要执行喂狗程序,比起独立看门狗,这个喂狗的窗口时间是非常短的,对时间要求很精确。如果没有在这个窗口时间内喂狗的话, 那就说明程序出故障了,会产生提前唤醒中断,最后系统复位。

  • 28
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
STM32看门狗(Watchdog)是一种硬件机制,用于监测程序是否正常运行。如果程序发生死循环或者挂起等异常情况,看门狗会在一定时间内未收到喂狗信号时,自动重启系统,确保系统能够正常运行。 下面是使用STM32看门狗的步骤: 1. 配置看门狗定时器 通过设置看门狗计数器(IWDG_PR)和重载值(IWDG_RLR)来配置看门狗定时器。这里以STM32F103为例,设置看门狗定时器时钟为40KHz,重载值为625,则看门狗定时器的定时时间为625/40KHz=15.625ms。 ```c RCC->APB1ENR |= RCC_APB1ENR_IWDGEN; // 使能看门狗时钟 IWDG->KR = 0x5555; // 开始寄存器操作 IWDG->PR = 4; // 分频系数为256,时钟为40KHz IWDG->RLR = 625; // 设置重载值,定时时间为15.625ms IWDG->KR = 0xAAAA; // 操作完成 ``` 2. 喂狗 在程序正常运行时,需要定期喂狗,以避免看门狗的复位。喂狗的方法是向看门狗喂狗寄存器(IWDG_KR)写入0xAAAA,然后再写入0x5555。 ```c IWDG->KR = 0xAAAA; // 喂狗 IWDG->KR = 0x5555; ``` 3. 启动看门狗 配置看门狗定时器和喂狗后,需要启动看门狗,使其开始工作。启动看门狗的方法是向看门狗控制寄存器(IWDG_KR)写入0xCCCC。 ```c IWDG->KR = 0xCCCC; // 启动看门狗 ``` 4. 处理看门狗超时复位 在程序运行过程中,需要处理看门狗超时复位,以避免程序出现死循环或挂起等异常情况。当看门狗定时器到达重载值时,会自动触发复位,导致系统重启。程序需要在重启后重新初始化系统,并处理异常情况。 ```c if (RCC->CSR & RCC_CSR_IWDGRSTF) { // 判断是否是看门狗复位 RCC->CSR |= RCC_CSR_RMVF; // 清除复位标志位 // 处理异常情况 ... } ``` 以上就是STM32看门狗的使用步骤。需要注意的是,在配置看门狗时,要确保看门狗的定时时间足够长,以保证程序能够正常运行。另外,在程序中也要定期喂狗,以避免看门狗的复位。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值