[其他ST产品] 窗口看门狗(WWDG)详解

[复制链接]
2002|40
 楼主| 根特皇宫w 发表于 2022-11-30 18:55 | 显示全部楼层
    该寄存器用来记录当前是否有提前唤醒的标志。该寄存器仅有位 0 有效,其他都是保留位。当计数器值达到 40h 时,此位由硬件置 1。 它必须通过软件写 0 来清除。对此位写 1 无效。即使中断未被使能,在计数器的值达到 0X40的时候,此位也会被置 1。
 楼主| 根特皇宫w 发表于 2022-11-30 18:56 | 显示全部楼层
WWDG固件库函数

       窗口看门狗库函数相关源码和定义分布在文件 stm32f10x_wwdg.c 文件和头文件 stm32f10x_wwdg.h 中。
 楼主| 根特皇宫w 发表于 2022-11-30 18:57 | 显示全部楼层
使能 WWDG 时钟

WWDG 不同于IWDG,IWDG 有自己独立的 40Khz 时钟,不存在使能问题。而 WWDG使用的是 PCLK1 的时钟,需要先使能时钟。方法是:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // WWDG 时钟使能
 楼主| 根特皇宫w 发表于 2022-11-30 18:58 | 显示全部楼层
设置窗口值和分频数

        设置窗口值的函数是:

void WWDG_SetWindowValue(uint8_t WindowValue);
 楼主| 根特皇宫w 发表于 2022-11-30 18:58 | 显示全部楼层
   这个函数的入口参数 WindowValue 用来设置看门狗的上窗口值。

        设置分频数的函数是:

void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);
 楼主| 根特皇宫w 发表于 2022-11-30 18:59 | 显示全部楼层
这个函数同样只有一个入口参数,用来设置看门狗的分频值。
 楼主| 根特皇宫w 发表于 2022-11-30 18:59 | 显示全部楼层
开启 WWDG 中断并分组

        开启 WWDG 中断的函数为:

WWDG_EnableIT(); //开启窗口看门狗中断

        接下来是进行中断优先级配置,这里就不重复了,使用 NVIC_Init()函数即可。
 楼主| 根特皇宫w 发表于 2022-11-30 19:00 | 显示全部楼层
设置计数器初始值并使能看门狗

        这一步在库函数里面是通过一个函数实现的:

void WWDG_Enable(uint8_t Counter);

        该函数既设置了计数器初始值,同时使能了窗口看门狗。
 楼主| 根特皇宫w 发表于 2022-11-30 19:01 | 显示全部楼层
编写中断服务函数

        编写窗口看门狗的中断服务函数,通过该函数来喂狗,必须在不大于 1 个窗口看门狗计数周期的时间内完成喂狗,否则当窗口看门狗计数器值减到 0X3F 的时候,就会引起软复位了。在中断服务函数里面也要将状态寄存器的 EWIF 位清空。
 楼主| 根特皇宫w 发表于 2022-11-30 19:02 | 显示全部楼层
WWDG(窗口看门狗)实验

硬件设计

        1) 指示灯 DS0 和 DS1

        2) 窗口看门狗

        窗口看门狗属于 STM32 的内部资源,只需要软件设置好即可正常工作。我们通过 DS0 和 DS1 来指示 STM32 的复位情况和窗口看门狗的喂狗情况。
 楼主| 根特皇宫w 发表于 2022-11-30 19:03 | 显示全部楼层
软件设计

        在工程文件目录下面新建两个文件夹分别为:wdg.c和wdg.h。并在把源文件添加到工程,和添加头文件的路径。
 楼主| 根特皇宫w 发表于 2022-11-30 19:03 | 显示全部楼层
wdg.c 里面的代码如下:
  1. #include "wdg.h"
  2. #include "led.h"


  3. void IWDG_Init(u8 prer,u16 rlr)
  4. {       
  5.         IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);  //使能对寄存器IWDG_PR和IWDG_RLR的写操作
  6.        
  7.         IWDG_SetPrescaler(prer);  //设置IWDG预分频值:设置IWDG预分频值为64
  8.        
  9.         IWDG_SetReload(rlr);  //设置IWDG重装载值
  10.        
  11.         IWDG_ReloadCounter();  //按照IWDG重装载寄存器的值重装载IWDG计数器
  12.        
  13.         IWDG_Enable();  //使能IWDG
  14. }
  15. //喂独立看门狗
  16. void IWDG_Feed(void)
  17. {   
  18.         IWDG_ReloadCounter();        //重载计数值                                                                          
  19. }


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

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

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

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

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

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

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

  36.         WWDG_EnableIT(); //开启窗口看门狗中断
  37. }
  38. //重设置WWDG计数器的值
  39. void WWDG_Set_Counter(u8 cnt)
  40. {
  41.     WWDG_Enable(cnt);//使能看门狗 ,        设置 counter .         
  42. }
  43. //窗口看门狗中断服务程序
  44. void WWDG_NVIC_Init()
  45. {
  46.         NVIC_InitTypeDef NVIC_InitStructure;
  47.         NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;    //WWDG中断
  48.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;   //抢占2,子优先级3,组2       
  49.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;         //抢占2,子优先级3,组2       
  50.   NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
  51.         NVIC_Init(&NVIC_InitStructure);//NVIC初始化
  52. }

  53. void WWDG_IRQHandler(void)
  54.         {

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

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

  57.         LED1=!LED1;                 //LED状态翻转
  58.         }
 楼主| 根特皇宫w 发表于 2022-11-30 19:04 | 显示全部楼层
   第一个函数 void WWDG_Init(u8 tr,u8 wr,u8 fprer)用来设置 WWDG 的初始化值。包括看门狗计数器的值和看门狗比较值等。全局变量 WWDG_CNT,该变量用来保 存最初设置 WWDG_CR 计数器的值。在后续的中断服务函数里面,就又把该数值放回到WWDG_CR 上。
 楼主| 根特皇宫w 发表于 2022-11-30 19:05 | 显示全部楼层
  第二个函数WWDG_Set_Counter()是用来重设窗口看门狗的计数器值的。
 楼主| 根特皇宫w 发表于 2022-11-30 19:05 | 显示全部楼层
第三个函数是中断分组函数。
 楼主| 根特皇宫w 发表于 2022-11-30 19:06 | 显示全部楼层
第四个函数是中断服务函数,先重设窗口看门狗的计数器值,然后清除提前唤醒中断标志。函数中也对 LED1(DS1)取反,来监测中断服务函数的执行了状况。
 楼主| 根特皇宫w 发表于 2022-11-30 19:07 | 显示全部楼层
wdg.h 里面的代码如下:

    #ifndef __WDG_H
    #define __WDG_H
    #include "sys.h"
              
     
     
    void IWDG_Init(u8 prer,u16 rlr);
    void IWDG_Feed(void);
     
    void WWDG_Init(u8 tr,u8 wr,u32 fprer);//初始化WWDG
    void WWDG_Set_Counter(u8 cnt);       //设置WWDG的计数器
    void WWDG_NVIC_Init(void);
     
    #endif
 楼主| 根特皇宫w 发表于 2022-11-30 19:07 | 显示全部楼层
      把头文件中的几个函数名加入到头文件里面去,其他文件的文件可以调用。
 楼主| 根特皇宫w 发表于 2022-11-30 19:08 | 显示全部楼层
main.c中的代码:
  1. #include "led.h"
  2. #include "delay.h"
  3. #include "key.h"
  4. #include "sys.h"
  5. #include "usart.h"
  6. #include "wdg.h"


  7. int main(void)
  8. {               
  9.         delay_init();                     //延时函数初始化          
  10.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
  11.         uart_init(115200);         //串口初始化为115200
  12.         LED_Init();
  13.         KEY_Init();          //按键初始化         
  14.         LED0=0;
  15.         delay_ms(300);          
  16.         WWDG_Init(0X7F,0X5F,WWDG_Prescaler_8);//计数器值为7f,窗口寄存器为5f,分频数为8          
  17.         while(1)
  18.         {
  19.                 LED0=1;                                    
  20.         }   
  21. }
 楼主| 根特皇宫w 发表于 2022-11-30 19:08 | 显示全部楼层
该函数通过 LED0(DS0)来指示是否正在初始化。而 LED1(DS1)用来指示是否发生了中 断。我们先让 LED0 亮 300ms,然后关闭以用于判断是否有复位发生了。在初始化 WWDG 之后,我们回到死循环,关闭 LED1,并等待看门狗中断的触发/复位。

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部