Stm32 第三十讲:窗口看门狗


窗口看门狗概述

之所以称为窗口就是因为其喂狗时间是一个有上下限的范围内,可以通过设定相关寄存器,设定其上限时间(下限固定)。喂狗的时间不能过早也不能过晚。

为什么要窗口看门狗?

对于一般的看门狗,程序可以在它产生复位前的任意时刻刷新看门狗,但这有一个隐患,有可能程序跑乱了又跑回到正常的地方,或跑乱的程序正好执行了刷新看门狗操作,这样的情况下一般的看门狗就检测不出来了。

如果使用串口看门狗,程序员可以根据程序正常执行的时间设置刷新看门狗的一个时间窗口,保证不会提前刷新看门狗也不会滞后刷新看门狗,这样可以检测出程序没有按照正常的路径运行非正常地跳过了某些程序段的情况。

工作示意图

窗口_工作示意图

窗口看门狗框图

窗口看门狗框图

工作过程总结

STM32F的窗口看门狗中有一个7位的递减计数器T[6:0],它会在出现下述2种情况之一时产生看门狗复位:

  1. 喂狗的时候如果计数器的值大于某一设定数值W[6:0]时,此设定数值在WWDG_CFR寄存器定义。
  2. 当计数器的数值从0x40减到0x3F时[T6位跳变为0]。

如果启动了看门狗并且允许中断,当递减计数器等于0x40时产生早期唤醒中断(EWI),它可以用于喂狗以避免WWDG复位。

窗口看门狗超时时间

窗口_超时时间

36M时钟下窗口看门狗的最小最大超时表:

超时表

其他注意事项

  • 上窗口值W[6:0]必须大于下窗口值0x40,否则就没有窗口了。
  • 窗口看门狗时钟来源PCLK1(APB1总线时钟)分频后。

相关寄存器

控制寄存器WWDG_CR

窗口_CR

相关库函数

void WWDG_Enable(uint8_t Counter); //启动并设置初始值
void WWDG_SetCounter(uint8_t Counter); //喂狗

配置寄存器WWDG_CFR

窗口_CFR

相关库函数

void WWDG_EnableIT(void); //使能提前唤醒中断
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler); //设置预分频系数
void WWDG SetWindowValue(uint8_t WindowValue); //设置窗口值

状态寄存器WWDG_SR

窗口_SR

相关库函数

FlagStatus WWDG_GetFlagStatus(void); //查看标志位
void WWDG_ClearFlag(void); //清除标志位

窗口看门狗配置过程

  1. 使能看门狗时钟:

    RCC_APB1PeriphClockCmd();

  2. 设置分频系数:

    WWDG_SetPrescaler();

  3. 设置上窗口值:

    WWDG_SetWindowValue();

  4. 开启提前唤醒中断并分组(可选):

    WWDG_EnableIT();
    NVIC_Init();

  5. 使能看门狗:

    WWDG_Enable();

  6. 喂狗:

    WWDG_SetCounter();

  7. 编写中断服务函数:

    WWDG_IRQHandler();

窗口看门狗实验

led.c和led.h文件内容与跑马灯中的一样,直接移植过来即可,在这里不再展示。

by库函数

wwdg.h

  #ifndef __WWDG_H
  #define __WWDG_H
  #include "sys.h"

  void WWDG_Init(u8 tr,u8 wr,u32 fprer); //初始化WWDG
  void WWDG_Set_Counter(u8 cnt); //设置WWDG的计数器
  void WWDG_NVIC_Init(void); //WWDG NVIC中断初始化

  #endif

wwdg.c

  #include "wwdg.h"
  #include "sys.h"
  #include "led.h"

  //保存WWDG计数器的设置值,默认最大
  u8 WWDG_CNT=0X7F;
  //初始化窗口看门狗
  //tr: T[6:0],计数值
  //wr: W[6:0],窗口值
  //fprer: 预分频系数
  //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);//设置预分频系数
      WWDG_SetWindowValue(wr);//设置上窗口值
      WWDG_Enable(WWDG_CNT);//使能看门狗,并设置计数值
      WWDG_ClearFlag();//清除提前唤醒中断标志位
      WWDG_NVIC_Init();//初始化窗口看门狗NVIC
      WWDG_EnableIT();//开启窗口看门狗中断
  }
  //冲设置WWDG计数器的值,即喂狗
  void WWDG_Set_Counter(u8 cnt)
  {
      WWDG_SetCounter(cnt);//喂狗
  }
  //窗口看门狗中断服务程序
  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=2;//响应优先级2
      NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能中断
      NVIC_Init(&NVIC_InitStructure);//NVIC初始化
  }

  void WWDG_IRQHandler(void)
  {
    WWDG_SetCounter(WWDG_CNT);//喂狗    
      WWDG_ClearFlag();//清除提前唤醒中断标志位
      LED1=!LED1;
  }

main.c

  #include "wwdg.h"
  #include "led.h"
  #include "delay.h"
  #include "sys.h"

  int main(void)
  {
      delay_init();//延时函数初始化
      LED_Init();//LED初始化
      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//NVIC中断分组为2
      LED0=0;//LED0灯亮
      delay_ms(500);
      WWDG_Init(0X7F,0X5F,WWDG_Prescaler_8);//窗口看门狗初始化
      while(1)
      {
          LED0=1;
      }
  }

by寄存器

wwdg.h

  #ifndef __WWDG_H
  #define __WWDG_H
  #include "sys.h"

  void WWDG_Init(u8 tr,u8 wr,u32 fprer);//初始化WWDG
  void WWDG_Set_Counter(u8 cnt);//设置WWDG的计数器,喂狗
  void WWDG_NVIC_Init(void);

  #endif

wwdg.c

  #include "wwdg.h"
  #include "sys.h"
  #include "led.h"

  u8 WWDG_CNT=0X7F;

  void WWDG_Init(u8 tr,u8 wr,u32 fprer)
  {
      RCC->APB1ENR|=1<<11;//使能WWDG时钟
      WWDG->CFR|=fprer<<7;//设置预分频系数
      WWDG_CNT=tr&WWDG_CNT;//初始化WWDG_CNT
      WWDG->CR|=WWDG_CNT<<0;//设置计数器值
      WWDG->CFR&=0xff80;//上窗口值清零
      WWDG->CFR|=wr;//初始化上窗口值
      WWDG->CR|=1<<7;//使能窗口看门狗
      MY_NVIC_Init(2,2,WWDG_IRQn,2);//设置WWDG NVIC中断
      WWDG->SR=0x00;//清除提前中断标志    
      WWDG->CFR|=1<<9;//使能窗口看门狗中断
  }

  void WWDG_Set_Counter(u8 cnt)
  {
      WWDG->CR|=cnt;//设置上窗口值    
  }

  void WWDG_IRQHandler()
  {
      WWDG->CR|=WWDG_CNT<<0;//设置上窗口值,喂狗    
      WWDG->SR=0x00;//清除提前中断标志
      LED1=!LED1;
  }

main.c

  #include "sys.h"
  #include "delay.h"     
  #include "led.h"
  #include "wwdg.h"

  int main(void)
  {                 
      Stm32_Clock_Init(9);    //系统时钟设置
      delay_init(72);              //延时初始化
    LED_Init();
      LED0=0;
      delay_ms(500);
      WWDG_Init(0x7f,0x5f,0x03);//计数值为0x7f,上窗口值0x5f,预分频数8
    while(1)
      {
          LED0=1;
      }     
  } 

文章作者: Mat Jenin
文章链接: http://matjenin.xyz
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Mat Jenin !
  目录