STM32学习小记之窗口看门狗(WWDG)

Posted 修灯泡的老张

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32学习小记之窗口看门狗(WWDG)相关的知识,希望对你有一定的参考价值。

STM32学习小记之窗口看门狗(WWDG)

五一假期玩high了哈,本来想五一期间写这一篇的。

一、窗口看门狗(WWDG)有什么用?

窗口看门狗常被用来检测由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。递减计数器T6(WWDG->CR的第六位)变成0时,看门狗在到达预置时间周期时会产生复位。在递减计数器达到窗口配置寄存器(WWDG->CFR)数值之前,如果七位的递减计数器数值被刷新,那么也会产生一个复位。
(递减计数器与时间的关系如下图)
WWDGCNT与时间的关系
其中,T[6:0]就是WWDG->CR的低七位,W[6:0]是WWDG->CFR的低七位。T[6:0]是WWDG的计数器,W[6:0]是WWDG的上窗口(用户设定),其下窗口固定为0x40。当WWDG的计数器在上窗口值之外被刷新或是低于下窗口值都会被复位。

二、WWDG固件库文件的简单解读

#include "stm32f10x_wwdg.h"
#include "stm32f10x_rcc.h"


/* ----------- WWDG registers bit address in the alias region (WWDG寄存器位地址的别名)----------- */
#define WWDG_OFFSET       (WWDG_BASE - PERIPH_BASE)

/* Alias word address of EWI bit(作为EWI位的字地址) */
#define CFR_OFFSET        (WWDG_OFFSET + 0x04)
#define EWI_BitNumber     0x09
#define CFR_EWI_BB        (PERIPH_BB_BASE + (CFR_OFFSET * 32) + (EWI_BitNumber * 4))

/* --------------------- WWDG registers bit mask ------------------------ */

/* CR register bit mask(CR寄存器位掩码) */
#define CR_WDGA_Set       ((uint32_t)0x00000080)

/* CFR register bit mask */
#define CFR_WDGTB_Mask    ((uint32_t)0xFFFFFE7F)
#define CFR_W_Mask        ((uint32_t)0xFFFFFF80)
#define BIT_Mask          ((uint8_t)0x7F)

/**
  * @brief  Deinitializes the WWDG peripheral registers to their default reset values.(将WWDG外设寄存器取消初始化为其默认重置值。)
  * @param  None
  * @retval None
  */
void WWDG_DeInit(void)
{
  RCC_APB1PeriphResetCmd(RCC_APB1Periph_WWDG, ENABLE);
  RCC_APB1PeriphResetCmd(RCC_APB1Periph_WWDG, DISABLE);
}

/**
  * @brief  Sets the WWDG Prescaler.(设置WWDG预分频器。)
  * @param  WWDG_Prescaler: specifies the WWDG Prescaler.(指定WWDG预分频器。)
  *   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)
{
  uint32_t tmpreg = 0;
  /* Check the parameters(检查参数) */
  assert_param(IS_WWDG_PRESCALER(WWDG_Prescaler));
  /* Clear WDGTB[1:0] bits (清理WDGTB[1:0]位)*/
  tmpreg = WWDG->CFR & CFR_WDGTB_Mask;
  /* Set WDGTB[1:0] bits according to WWDG_Prescaler value(根据wwdg_precaler值设置WDGTB[1:0]位) */
  tmpreg |= WWDG_Prescaler;
  /* Store the new value(存储新值) */
  WWDG->CFR = tmpreg;
}

/**
  * @brief  Sets the WWDG window value.(设置WWDG窗口的值。)
  * @param  WindowValue: specifies the window value to be compared to the downcounter.(指定要与下行计数器比较的窗口值。)
  *   This parameter value must be lower than 0x80.(该参数值必须小于0x80。)
  * @retval None
  */
void WWDG_SetWindowValue(uint8_t WindowValue)
{
  __IO uint32_t tmpreg = 0;

  /* Check the parameters */
  assert_param(IS_WWDG_WINDOW_VALUE(WindowValue));
  /* Clear W[6:0] bits */

  tmpreg = WWDG->CFR & CFR_W_Mask;

  /* Set W[6:0] bits according to WindowValue value */
  tmpreg |= WindowValue & (uint32_t) BIT_Mask;

  /* Store the new value */
  WWDG->CFR = tmpreg;
}

/**
  * @brief  Enables the WWDG Early Wakeup interrupt(EWI).(启用WWDG早期唤醒中断(EWI)。)
  * @param  None
  * @retval None
  */
void WWDG_EnableIT(void)
{
  *(__IO uint32_t *) CFR_EWI_BB = (uint32_t)ENABLE;
}

/**
  * @brief  Sets the WWDG counter value.(设置WWDG计数器的值。)
  * @param  Counter: specifies the watchdog counter value.(看门狗计数器的值。)
  *   This parameter must be a number between 0x40 and 0x7F.(取值范围为0x40 ~ 0x7F之间的数字。)
  * @retval None
  */
void WWDG_SetCounter(uint8_t Counter)
{
  /* Check the parameters */
  assert_param(IS_WWDG_COUNTER(Counter));
  /* Write to T[6:0] bits to configure the counter value, no need to do
     a read-modify-write; writing a 0 to WDGA bit does nothing(写入T[6:0]位来配置计数器值,不需要这样做
读-修改-写;写0到WDGA位什么也不做) */
  WWDG->CR = Counter & BIT_Mask;
}

/**
  * @brief  Enables WWDG and load the counter value. (启用WWDG并加载计数器值。)                 
  * @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)
{
  /* Check the parameters */
  assert_param(IS_WWDG_COUNTER(Counter));
  WWDG->CR = CR_WDGA_Set | Counter;
}

/**
  * @brief  Checks whether the Early Wakeup interrupt flag is set or not.(检查是否设置了EWI标志。)
  * @param  None
  * @retval The new state of the Early Wakeup interrupt flag (SET or RESET)(EWI标志的新状态(SET或RESET))
  */
FlagStatus WWDG_GetFlagStatus(void)
{
  return (FlagStatus)(WWDG->SR);
}

/**
  * @brief  Clears Early Wakeup interrupt flag.(清除EWI标志。)
  * @param  None
  * @retval None
  */
void WWDG_ClearFlag(void)
{
  WWDG->SR = (uint32_t)RESET;
}

WWDG的超时计算公式

WWDG的超时计算公式
  其中:
     Twwdg:WWDG超时时间(单位为ms)
     Fpclk1:APB1的时钟频率(单位为Khz)
     WDGTB:WWDG的预分频系数
     T[5:0]:WWDG的计数器低六位
假设Fpclk1=36Khz时,我们可以得到下表:

三、WWDG源文件的编写

void IWDG_Init(u8 prer,u16 rlr) 
{	
 	IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);      //使能对寄存器IWDG_PR和IWDG_RLR的写操作
	
	IWDG_SetPrescaler(prer);                          //设置IWDG预分频值:设置IWDG预分频值为64
	
	IWDG_SetReload(rlr);                             //设置IWDG重装载值
	
	IWDG_ReloadCounter();                           //按照IWDG重装载寄存器的值重装载IWDG计数器
	
	IWDG_Enable();                                 //使能IWDG
}
                                                  //喂独立看门狗
void IWDG_Feed(void)
{   
 	IWDG_ReloadCounter();	                    //重载计数值									   
}


//保存WWDG计数器的设置值,默认为最大. 
u8 WWDG_CNT=0x7f; 
//初始化窗口看门狗 	
//tr   :T[6:0],计数器值 
//wr   :W[6:0],窗口值 
//fprer:分频系数(WDGTB),仅最低2位有效 
//Fwwdg=PCLK1/(4096*2^fprer). 

void WWDG_Init(u8 tr,u8 wr,u32 fprer)
{ 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);  //   WWDG时钟使能

	WWDG_CNT=tr&WWDG_CNT;   //初始化WWDG_CNT.   
	WWDG_SetPrescaler(fprer);设置IWDG预分频值

	WWDG_SetWindowValue(wr);//设置窗口值

	WWDG_Enable(WWDG_CNT);	 //使能看门狗 ,	设置 counter .                  

	WWDG_ClearFlag();//清除提前唤醒中断标志位 

	WWDG_NVIC_Init();//初始化窗口看门狗 NVIC

	WWDG_EnableIT(); //开启窗口看门狗中断
} 
//重设置WWDG计数器的值
void WWDG_Set_Counter(u8 cnt)
{
    WWDG_Enable(cnt);//使能看门狗 ,	设置 counter .	 
}
//窗口看门狗中断服务程序
void WWDG_NVIC_Init()
{
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;    //WWDG中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;   //抢占2,子优先级3,组2	
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;	 //抢占2,子优先级3,组2	
  NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; 
	NVIC_Init(&NVIC_InitStructure);//NVIC初始化
}

void WWDG_IRQHandler(void)
	{

	WWDG_SetCounter(WWDG_CNT);	  //当禁掉此句后,窗口看门狗将产生复位

	WWDG_ClearFlag();	  //清除提前唤醒中断标志位

	}

四、结束语

  在我写这两个看门狗系列的时候,跟我一同学习的小伙伴拍了拍我的肩膀,语重心长地说:“兄弟,咱俩现在层次太低,学这个没啥用。”
  我:“……”
      唉,心塞啊!下期预告:串口通信(1)

以上是关于STM32学习小记之窗口看门狗(WWDG)的主要内容,如果未能解决你的问题,请参考以下文章

STM32学习小记之独立看门狗(IWDG)

STM32之独立看门狗(IWDG)与窗口看门狗(WWDG)总结

STM32F103五分钟入门系列(十四)窗口看门狗WWDG

06 STM32F4的窗口看门狗(WWDG)

STM32之窗口看门狗

19 . 窗口看门狗(WWDG)实验