STM32 学习笔记 -- 基于stm32f4的看门狗配置和实验代码

基于stm32f4的看门狗配置和实验代码

以下本人对stm32f4xx的独立看门狗和窗口看门狗学习、理解和总结,程序的说明和解释均在注释中,仔细阅读不难理解。我已经过验证,有问题或错误请指出。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_45003437/article/details/102876242

#include "xwdg.h"
#include "gpio.h"
#include "time.h"

/*=================================================================================================
* 函数名 : Iwdg_Init
* 功能   : 初始化独立看门狗
* 设计者 : rsl
* 日期   : 2019-11-01
* 版本	 : V1.0
* 备注   : 时钟范围为 30K~60K ,可用延函数进行测试
===================================================================================================*/
void Iwdg_Init(uint8_t pre ,uint16_t rlr)
{
  //使能 预分频寄存器PR和重装载寄存器RLR可写
	IWDG->KR  = 0X5555;
  //设置预分频器值
	IWDG->PR  = pre;
  //设置重装载寄存器值(0~4095)
	IWDG->RLR = rlr;
  //把重装载寄存器的值放到计数器中
	IWDG->KR  = 0XAAAA;
  //使能计数
	IWDG->KR  = 0XCCCC;
  //喂狗操作
	IWDG->KR  = 0XAAAA;
}
/*=================================================================================================
* 设置 IWDG 的超时复位时间计算:
*      Tout = pre / 40 * rlr (ms)
* 名称   : Iwdg_LibConfig
* 参数   : pre 可以是[0~6] -> [4,8,16,32,64,128,256]
*           rlr 重装载寄存器的值,取值范围为:0 ~ 0XFFF(0~4095)
* 设计者 : rsl
* 日期   : 2019-11-02
* 版本	 : V1.0
* 备注   : 独立看门狗使用LSI作为时钟, LSI 的频率一般在 30~60KHZ 之间, 根据温度和工作场合会发生一定的
*           漂移,一般取 40KHZ ,所以独立看门狗的定时时间并不一定非常精确, 只适用于对时间精度要求比较低
*           的场合。
* --------------------------------------------
* 调用举例:
*   Iwdg_LibConfig(IWDG_Prescaler_64 ,625);
*   (64/40)*625 = 1000ms = 1s //IWDG 1s 超时溢出
===================================================================================================*/
void Iwdg_LibConfig(uint8_t pre ,uint16_t rlr)
{
  // 使能 预分频寄存器PR和重装载寄存器RLR可写
  IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
  // 设置预分频器值
  IWDG_SetPrescaler(pre);
  // 设置重装载寄存器值
  IWDG_SetReload(rlr);
  // 把重装载寄存器的值放到计数器中
  IWDG_ReloadCounter();
  // 使能 IWDG
  IWDG_Enable();
}
/*=================================================================================================
* 函数名 : Iwdg_Feed
* 功能   : 喂独立看门狗
* 设计者 : rsl		
* 日期   : 2019-11-01
* 版本	 : V1.0
* 备注   : 把重装载寄存器的值放到计数器中(喂狗),防止IWDG复位;当计数器的值减到0的时候会产生系统复位
===================================================================================================*/
void Iwdg_Feed(void)
{
  //IWDG->KR = 0XAAAA;
  IWDG_ReloadCounter();//喂狗操作
}
/*=================================================================================================
* 函数名 : Iwdg_Test
* 功能   : 独立看门狗测试程序
* 设计者 : rsl		
* 日期   : 2019-11-02
* 版本	 : V1.0
* 备注   : 因为看门狗初始化程序计数器会消耗一定时间,故看门狗复位指示灯实际闪烁频率比设定的会略慢些
===================================================================================================*/
void Iwdg_Test(uint32_t Nms)
{
  //LED 端口初始化
  //延时一定时间,此时间是用于控制看门狗复位指示灯(LED1)闪烁频率的
  Delay_ms(Nms);
	
  /* 检查是否为 独立看门狗复位 */
  if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET)
  {
    /* 独立看门狗复位 */
    //清除 RCC 的复位标志位
    RCC_ClearFlag();
    /*如果一直不喂狗,会一直复位,加上前面的延时,会看到LED1灯闪烁;
      在 设定的 时间内喂狗的话,则会持续亮LED4灯.*/
		LED1_ON;
  }
  else
  {
    /* 不是独立看门狗复位(可能为上电复位或者手动按键复位之类的) */
    //LED4灯亮
    LED4_ON;
  }
}
/*=================================================================================================
* WWDG 的超时复位时间计算:
*     Twwdg =(4096 × 2^pre ×(T[5:0]+1)) / PCLK1 ; 单位为(ms)
*     T[5:0] 窗口看门狗的计数器低 6 位,可取值为0x00~0x3F;(0~63)
*     PCLK1  42Mhz --> 42000KHz, 即取42000;
* 函数名 : Wwdg_Init
* 功能   : 初始化窗口看门狗
* 参数   : cnt 表示 T[6:0], 7 位计数器值, 其范围 0x40 ~ 0x7F(64~127)
*           win 表示 W[6:0], 7 位窗口值(上窗口), 与递减计数器值进行比较, 其值要小于0x80(0~128)
*           pre 表示 WDGTB[1:0] 分频系数(位8:7 -> 00~11)
*               取 WWDG_Prescaler_x ,x 为 1, 2, 4, 8
* 设计者 : rsl
* 日期   : 2019-11-02
* 版本	 : V1.0
* 备注   : 窗口看门狗时钟为APB1(PCLK1)时钟总线,42MHz;窗口范围:下窗口固定(0x3F)~上窗口可设(W[6:0])
* --------------------------------------------
* 调用举例:
*   Wwdg_Init(0x7F,0x5F,WWDG_Prescaler_8);
*   (4096 * 2^8 * (63 + 1)) / 42000kHz = 1198 ms
===================================================================================================*/
void Wwdg_Init(u8 cnt, u8 win, u32 pre)
{
	//WWDG 时钟使能
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
	//设置IWDG预分频值
	WWDG_SetPrescaler(pre);
	//设置窗口值
	WWDG_SetWindowValue(win);
	//清除提前唤醒中断标志位 
	WWDG_ClearFlag();
	//初始化窗口看门狗 NVIC
	WWDG_NVIC_Init();
	//开启窗口看门狗中断(递减计数器减到0x40时产生中断)
	WWDG_EnableIT();
	//设置 7位计数器值并使能看门狗
	WWDG_Enable(cnt & 0x7F);
} 
/* 配置窗口看门狗中断向量控制器 */
void WWDG_NVIC_Init(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;//WWDG中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//抢占2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//子优先级1
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
	NVIC_Init(&NVIC_InitStructure);//NVIC初始化
}
/*=================================================================================================
* 函数名 : Wwdge_Feed
* 功能   : 喂窗口看门狗
* 设计者 : rsl		
* 日期   : 2019-11-02
* 版本	 : V1.0
* 备注   : 输入窗口看门狗定时器值(类似于重装载计数值),低7位有效; 第8位(bit7)为激活位,使能看门狗.
===================================================================================================*/
void Wwdge_Feed(u8 cnt)
{
    WWDG_Enable(cnt & 0x7F);//使能看门狗, 重设置WWDG计数器的值
}
/*=================================================================================================
* 函数名 : Wwdg_Test
* 功能   : 窗口看门狗测试程序
* 设计者 : rsl		
* 日期   : 2019-11-02
* 版本	 : V1.0
* 备注   : 
===================================================================================================*/
void Wwdg_Test(uint32_t Nms)
{
  //LED 端口初始化
  //延时一定时间,此时间是用于控制看门狗复位指示灯(LED1)闪烁频率的
  Delay_ms(Nms);
	
  /* 检查是否为 窗口看门狗复位 */
  if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST) != RESET)
  {
    /* 独立看门狗复位 */
    //清除 RCC 的复位标志位
    RCC_ClearFlag();
    /*如果一直不喂狗,会一直复位,加上前面的延时,会看到LED1灯闪烁;
      在 设定的 时间内喂狗的话,则会持续亮LED4灯.*/
		LED2_ON;
  }
  else
  {
    /* 不是独立看门狗复位(可能为上电复位或者手动按键复位之类的) */
    //LED4灯亮
    LED4_ON;
  }
}
/**************************************************************************************************
  *独立看门狗应用举例:
  int main(void)
  {
    //初始化按键
    Key_GPIO_Config();    

    //设置 IWDG 500ms 超时溢出
    IWDG_Config(IWDG_Prescaler_16 ,1250); 

    //while部分是我们在项目中具体需要写的代码,这部分的程序可以用独立看门狗来监控;
    //如果我们知道这部分代码的执行时间,比如是500ms,那么我们可以设置独立看门狗的
    //溢出时间是600ms(有一定误差),比500ms多一点;如果要被监控的程序没有跑飞正常执
    //行的话,那么执行完毕之后就会执行喂狗的程序,如果程序跑飞了那程序就会超时,到
    //达不了喂狗的程序,此时就会产生系统复位。但是也不排除程序跑飞了又跑回来了,刚
    //好喂狗了,歪打正着。所以要想更精确的监控程序,可以使用窗口看门狗,窗口看门狗
    //规定必须在规定的窗口时间内喂狗。
    while(1)                            
    {       
      if(Key_Scan() == KEY_DWN)
      {
        //喂狗,如果不喂狗,系统则会复位,复位后亮红灯,如果在500 ms
        //时间内准时喂狗的话,则会亮绿灯
        Iwdg_Feed();        
        //喂狗后亮绿灯
        LED_GREEN;
      }
    }
  }
	------------------------------------------------------------------------------
	*窗口看门狗一般步骤:
	1)使能看门狗时钟;              调用函数:RCC_APB1PeriphClockCmd();
	2)设置分频系数;                调用函数:WWDG_SetPrescaler();
	3)设置上窗口值;                调用函数:WWDG_SetWindowValue();
	4)开启提前唤醒中断并分组;      调用函数:WWDG_EnableIT()、NVIC_Init();
	5)使能看门狗;                  调用函数:WWDG_Enable();
	6)喂狗(通常在中断服务中调用);  调用函数:WWDG_SetCounter();
	7)编写中断服务函数.            调用函数:WWDG_IRQHandler()。
	
	☆窗口看门狗工作过程总结:
	(1)STM32F的窗口看门狗中有一个7位的递减计数器T[6:0],它会在出现下述2种情况之一时产生看门狗复位:
		① 当喂狗的时候如果计数器的值大于某一设定数值W[6:0](上窗口值)时;
		② 当计数器的数值从 0x40 减到 0x3F 时[由T6位跳变到0]。
	(2)在窗口看门狗的递减计数器递减至窗口配置寄存器配置的上窗口(W[6:0])之前,以及在递减计数器递减到下窗口(0x3F)之后
	是不能刷新递减计数器的数值(喂狗操作)的; 否则这两种状况都会产生复位信号的。也即喂狗操作只能发生在上、下窗口之间。
	
	注意:如果启动了看门狗并且开启了中断,当在递减计数器递减到0x40时会产生提前唤醒中断(EWI),可以在中断处理函数中
	      向 WWDG_CR 重新写入计数器值来达到喂狗的目的。
	      进入中断之后,必须在不长于一个窗口看门狗计数周期的时间(在PCLK1频率为36MHz且WDGTB为0的情况下,该值为 113us)
	      内重新向WWDG_CR写入计数器值,否则看门狗也将产生复位!	      
	------------------------------------------------------------------------------

参考网资:
独立看门狗
https://blog.csdn.net/weibo1230123/article/details/80705866
窗口看门狗
https://blog.csdn.net/qq_38410730/article/details/79966441

你可能感兴趣的:(STM32 学习笔记 -- 基于stm32f4的看门狗配置和实验代码)