你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32心得:窗口看门狗(WWDG)实验及旧知识点复习

[复制链接]
STMCU小助手 发布时间:2022-11-20 19:25
主要内容:
1) 窗口看门狗概述;
2) 常用寄存器和库函数配置;
3) 窗口看门狗实验。
窗口看门狗实验内容:
为了对之前的知识进行总结复习,本人在教学案例的基础上又“意淫”了一些附加要求,具体内容为,启动后,
独立看门狗每次自动复位时,LED0先灭后亮,蜂鸣器不叫。按KEY2键可对独立看门狗进行手动喂狗,按下时,LED0灭,蜂鸣器叫,指令内容通过串口传至PC端,松开时,LED0亮,蜂鸣器不叫,长按KEY2时,LED0一直灭,蜂鸣器一直叫,但指令只传一次;
窗口看门狗启动提前唤醒中断,每次因中断自动喂狗时,LED1翻转一次(即由0至1或由1至0),蜂鸣器不叫,若喂狗同时KEY1按下,指令内容通过串口传至PC端。

1. 窗口看门狗的概念

由于喂狗时间是一个有上下限的范围内(窗口),通过设定相关寄存器,设定其上限时间(下限固定),喂狗的时间不能过早也不能过晚,所以称之为窗口看门狗;
独立看门狗限制喂狗时间在0-x内,x由键寄存器的低16位决定。喂狗的时间不能过晚。

2. 窗口看门狗工作示意图

20200414213540630.png

2.1 由上图所示,喂狗时间只能在刷新窗口间;
2.2 3Fh用二进制表示是0011 1111;
2.3 T6位至到达3Fh(0011 1111)前一时刻(0100 0000),当下一时刻到达3Fh时,变为0011 1111,即第六位由1变为0,执行复位。

3. 窗口看门狗框图

20200414213942825.png
3.1 窗口看门狗的时钟来源于PCLK1,PCLK1最高频率可达36MHz,PLCK1先除以4096,再进入看门狗预分频器,最后计算出的值作为窗口看门狗的时钟频率;;
3.2 控制寄存器WWDG_CR的第0~5位用来设置计数值,当第6位(即T6)由1变为0时,变产生一个复位,第7位WDGA为激活位,使能窗口看门狗;
3.3 通过比较器,当控制寄存器WWDG_CR的第0~6位(即T6:0)>配置寄存器WWDG_CFR的第0 ~6位(即W6:0),则比较结果为1;
3.5 因此,上图中,产生看门狗复位的条件有:
3.5.1 当满足3.3条件,即(T6:0)>(W6:0),此时,对控制寄存器WWDG_CFR进行写入,则经过或运算后,产生复位(因为处于不允许刷新的区域,不能喂狗);
3.5.2 当计数器的数值从0x40减到0x3F时(即T6位由1跳变到0),经过非运算,再经过或运算后,产生复位。
3.6 如果启动了看门狗并且允许中断,当递减计数器等于0x40时产生早期唤醒中断(EWI),它可以用于喂狗以避免WWDG复位;
3.7 上窗口值W[6:0]必须大于下窗口值0x40。否则就无窗口了。

4. 窗口看门狗超时时间

20200414235603381.png
根据上述公式,假设 Fpclk1为最大值36MHz,那么可以得到最小~最大超时时间表如下所示:

20200414235627960.png

5. 窗口看门狗作用

对于一般的看门狗,程序可在它产生复位前的任意时刻刷新看门狗,但是,有可能程序跑乱了又跑回到正常的地方,或跑乱的程序正好执行了刷新看门狗操作,这样的情况下一般的看门狗就检测不出来了;
若使用窗口看门狗,可以根据程序正常执行的时间设置刷新看门狗的一个时间窗口,保证不会提前刷新看门狗也不会滞后刷新看门狗,这样可以检测出程序没有按照正常的路径运行非正常地跳过了某些程序段的情况。

6. 窗口看门狗常用寄存器

6.1 控制寄存器WWDG_CR

2020041500034867.png

  1. void WWDG_Enable(uint8_t Counter);     //启动并设置初始值//
  2. void WWDG_SetCounter(uint8_t Counter); //喂狗//
复制代码

6.2 配置寄存器WWDG_CFR



  1. void WWDG_EnableIT(void);                         //使能提前唤醒中断//
  2. void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);  // 设置分频系数//
  3. void WWDG_SetWindowValue(uint8_t WindowValue);    //设置上窗口值//
复制代码

6.3 控制寄存器WWDG_CR

20200415000500134.png

  1. FlagStatus WWDG_GetFlagStatus(void);
  2. void WWDG_ClearFlag(void);
复制代码

7. 窗口看门狗配置过程

7.1 使能看门狗时钟:

  1. RCC_APB1PeriphClockCmd();
复制代码

7.2 设置分频系数:
  1. WWDG_SetPrescaler();
复制代码

7.3 设置上窗口值:

  1. WWDG_SetWindowValue();
复制代码

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

  1. WWDG_EnableIT();
  2. NVIC_Init();
复制代码

7.5 使能看门狗:

  1. WWDG_Enable();
复制代码

7.6 喂狗:
  1. WWDG_SetCounter();
复制代码

7.7 编写中断服务函数

  1. WWDG_IRQHandler();
复制代码

8. 实验代码部分解读

跑马灯、蜂鸣器、按键输入、串口等相关代码可参考以前的文章。
8.1 exti.c代码解读
将KEY2键作为外部中断,按下时,

  1. #include "led.h"
  2. #include "beep.h"
  3. #include "key.h"
  4. #include "exti.h"
  5. #include "usart.h"
  6. #include "sys.h"
  7. //编写EXTIx_Init初始化函数,包括中断线配置和每个中断线的优先级配置//
  8. void EXTIx_Init(void)
  9. {
  10.     //*申明一个结构体,名字为EXTI_InitStructure,结构体原型由EXTI_InitTypeDef确定*//
  11.     EXTI_InitTypeDef EXTI_InitStructure;
  12.     //*申明一个结构体,名字为NVIC_InitStructure,结构体原型由NVIC_InitTypeDef确定*//
  13.     NVIC_InitTypeDef NVIC_InitStructure;
  14.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);                //使能复用功能时钟AFIO//
  15.     //设置I/O口与中断线的映射关系//
  16.     GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);         //PE2对应KEY2//
  17.     //PE2中断线初始化配置,中断模式,下降沿触发,使能//
  18.     EXTI_InitStructure.EXTI_Line=EXTI_Line2;                           //GPIOx,Pin2对应EXTI2中断线//
  19.     EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;                //中断模式//
  20.     EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;     //双边沿触发//
  21.     EXTI_InitStructure.EXTI_LineCmd = ENABLE;                          //使能//
  22.     //中断线初始化,GPIOE,Pin2映射到EXTI2中断线,中断模式,下降沿触发,使能//
  23.     EXTI_Init(&EXTI_InitStructure);                                                               
  24.     //对上述配置好的每个中断进行优先级初始化//
  25.     NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;                  //选择EXTI2外部中断通道,即PE2,即KEY2
  26.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;      //抢占优先级2,
  27.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;             //响应优先级2
  28.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                   //使能//
  29.     NVIC_Init(&NVIC_InitStructure);      
  30. }
  31. //编写EXTI2中断服务函数,对应KEY2按键,对独立看门狗的相应工作//
  32. void EXTI2_IRQHandler(void)
  33. {
  34. if(KEY2==0)                          //判断KEY2按键是按下还是松开,按下则KEY2==0,if(1)
  35. {
  36.    BEEP=1;                           //按下时蜂鸣器叫//
  37.    LED0=1;                          //按下时LED0灭//
  38.    printf("KEY2按下,对独立看门狗进行手动喂狗(在main.c中执行),LED0灭,蜂鸣器叫\r\n");
  39. }
  40. else
  41. {
  42.    BEEP=0;                           //松开时蜂鸣器不叫//
  43.    LED0=0;                           //松开时LED0亮//
  44.    IWDG_ReloadCounter();  
  45.    printf("KEY2松开,对独立看门狗进行手动喂狗,LED0亮,蜂鸣器不叫\r\n");
  46. }  
  47. EXTI_ClearITPendingBit(EXTI_Line2);  //清除LINE0上的中断标志位  
  48. }
复制代码

8.2 wwdg.c代码解读
包括IWDG_Init和WWDG_Init初始化函数,并编写了窗口看门狗早期唤醒中断服务函数。

  1. #include "wdg.h"
  2. #include "led.h"
  3. #include "key.h"
  4. #include "usart.h"
  5. //编写IWDG_Init初始化函数//
  6. void IWDG_Init(u8 IWDG_PR,u16 IWDG_RLR)
  7. {
  8. IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//取消寄存器写保护//
  9. IWDG_SetPrescaler(IWDG_PR);                  //设置独立看门狗的预分频系数//
  10. IWDG_SetReload(IWDG_RLR);                    //设置看门狗重装载值//
  11. IWDG_ReloadCounter();                        //喂狗,否则将从0xFFF算起//
  12. IWDG_Enable();                               //使能独立看门狗//
  13. }
  14. //定WWDG_CR控制寄存器第0~6位值,默认为最大0111 1111//
  15. u8 WWDG_CNT=0x7f;  
  16. //窗口看门狗计数频率的计算公式为:Fwwdg=PCLK1/(4096*2^fprer)//
  17. //编写WWDG_Init初始化函数,WWDG_TV(CR寄存器0~6位计数值),WWDG_WV(用来设置上窗口值)和WWDG_PR(用来设置预分频系数)//
  18. void WWDG_Init(u8 WWDG_TV,u8 WWDG_WV,u32 WWDG_PR)
  19. {
  20. //先WWDG时钟使能//
  21. RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);  
  22. WWDG_CNT=WWDG_TV&WWDG_CNT;           //初始化WWDG_CNT,一般0x40≤WWDG_TV≤0x7F,则实际意思是将WWDG_TV赋值给WWDG_CNT//
  23. WWDG_SetPrescaler(WWDG_PR);          //设置WWDG预分频值//
  24. WWDG_SetWindowValue(WWDG_WV);        //设置上窗口值,且0x40≤WWDG_WV≤0x7F//
  25. WWDG_Enable(WWDG_CNT);               //使能看门狗,并载入计数值,且0x40≤WWDG_CNT≤0x7F//               
  26. WWDG_ClearFlag();                    //清除提前唤醒中断标志位
  27. WWDG_NVIC_Init();                    //初始化窗口看门狗中断服务函数//
  28. WWDG_EnableIT();                     //开启窗口看门狗中断,即到计数到0x40时,发生一次中断//
  29. }
  30. //重置WWDG计数器的值,即执行WWDG_Enable(cnt)函数//
  31. void WWDG_Set_Counter(u8 cnt)
  32. {
  33.      WWDG_Enable(cnt);                //使能看门狗,并载入计数值,且0x40≤cnt≤0x7F//  
  34. }
  35. //编写窗口看门狗中断服务初始化函数//
  36. void WWDG_NVIC_Init()
  37. {
  38. NVIC_InitTypeDef NVIC_InitStructure;
  39. NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;              //WWDG中断
  40. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;    //抢占优先级为2
  41. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;           //响应优先级为3
  42. NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
  43. NVIC_Init(&NVIC_InitStructure);
  44. }
  45. //编写窗口看门狗中断服务函数//
  46. void WWDG_IRQHandler(void)
  47. {
  48.   //喂狗,实际执行 WWDG_Enable(cnt)函数//
  49.   WWDG_SetCounter(WWDG_CNT);    //当禁掉此句后,窗口看门狗将产生复位//
  50.   WWDG_ClearFlag();             //清除提前唤醒中断标志位//
  51.   LED1=!LED1;                   //LED状态翻转
  52.   if(KEY1==0)                   //判断KEY1按键是否按下,按下则KEY2==0,if(1)
  53. {
  54.   printf("对窗口看门狗进行手动喂狗,LED1闪烁\r\n");
  55. }
  56. }
复制代码

8.3 main.c代码解读
主函数中,死循环里写了KEY2按下时,对独立看门狗的喂狗方式。

  1. #include "led.h"
  2. #include "beep.h"
  3. #include "key.h"
  4. #include "wdg.h"
  5. #include "exti.h"
  6. #include "delay.h"
  7. #include "sys.h"
  8. #include "usart.h"
  9. int main(void)
  10. {  
  11. u8 key;
  12. delay_init();        //延时函数初始化//  
  13. //设置中断优先级分组为组2:2位抢占优先级,2位响应优先级//  
  14. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  15. //usart1串口初始化,波特率为115200//
  16. LED_Init();          //LED端口初始化,LED0和LED0默认灭//
  17. BEEP_Init();         //初始化蜂鸣器端口,不叫//
  18. KEY_Init();          //按键初始化//
  19. EXTIx_Init();        //外部中断初始化//
  20. uart_init(115200);   //串口USART1初始化//
  21. delay_ms(300);
  22. LED0=0;              //LED0点亮//
  23. IWDG_Init(4,3125);                      //根据预分配值和重装载值确定溢出时间,根据参数,溢出时间大约为//
  24. WWDG_Init(0X7F,0X4F,WWDG_Prescaler_8);  //设置计数器值,上窗口值,分频系数为8//   
  25. //系统进入死循环后,LED0是亮的//  
  26.   while(1)
  27. {
  28.   key=KEY_Scan(1);                      //支持连按//
  29.       if(key)
  30.     {        
  31.        switch(key)
  32.       {      
  33.           case 3:                       //若KEY2按下,则对独立看门狗进行喂狗//
  34.           IWDG_ReloadCounter();                        
  35.           break;
  36.         }   
  37.         }
  38.    }
  39. }
复制代码

最后调试效果如下图

20200415003239467.jpg
————————————————
版权声明:天亮继续睡


20200415000059219.png
收藏 评论0 发布时间:2022-11-20 19:25

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版