[RISC-V MCU 应用开发] 六、CH32V103应用教程——WWDG

[复制链接]
 楼主| RISCVLAR 发表于 2020-10-30 19:04 | 显示全部楼层 |阅读模式
本帖最后由 RISCVLAR 于 2020-10-30 19:03 编辑

CH32V103应用教程——WWDG

本章教程通过串口调试助手打印显示程序运行状态,具体现象如下:
  • 若计数器值在上窗口值和下窗口值0X40之间的时候,进行喂狗操作,计数器重新计数,程序正常运行,串口打印显示:The program runs normally;
  • 若程序在快要减到0X3F时候通过中断函数进行喂狗操作,则串口打印显示:Execute interrupt function The program runs normally;
  • 若程序没有在窗口时间内进行喂狗操作,则程序会不停进行复位。

1、WWDG简介及相关函数介绍
窗口看门狗(WWDG)通常用来监测系统运行的软件故障,例如外部干扰、不可预见的逻辑错误等情况。其需要在一个特定的窗口时间(有上下限)内进行计数器刷新(喂狗),否则早于或者晚于这个窗口时间看门狗电路都会产生系统复位。

CH32V103的窗口看门狗具有可编程的7位自减型计数器;具有双条件复位,当计数器值小于0X40,或者计数器值在窗口时间外被重装载;具有唤醒提前通知功能(EWI),用于及时喂狗动作防止系统复位。


CH32V103的窗口看门狗运行基于一个可编程的7 位的自减型计数器,其挂载在 APB1 总线下,计数时基 WWDG_CLK 来源(PCLK1/4096)时钟的分频,分频系数在配置寄存器 WWDG_CFGR 中的 WDGTB[1:0]域设置。递减计数器处于自由运行状态,无论看门狗功能是否开启,计数器一直循环递减计数。 关于CH32V103窗口看门狗具体信息,可参考CH32V103应用手册。

本章教程通过调用窗口看门狗库函数中相关函数进行程序编写,关于库函数相关介绍如下:

  1. void WWDG_DeInit(void);
  2. void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);
  3. void WWDG_SetWindowValue(uint8_t WindowValue);
  4. void WWDG_EnableIT(void);
  5. void WWDG_SetCounter(uint8_t Counter);
  6. void WWDG_Enable(uint8_t Counter);
  7. FlagStatus WWDG_GetFlagStatus(void);
  8. void WWDG_ClearFlag(void);
1.1、void WWDG_DeInit(void)
功  能:将WWDG外围寄存器初始化为其默认重置值
输  入:无

1.2、void WWDG_SetPrescaler(uint32_t WWDG_Prescaler)
功  能:设置WWDG预分频器
输  入:WWDG_预分频器:指定WWDG预分频器。

1.3、void WWDG_SetWindowValue(uint8_t WindowValue)
功  能:设置WWDG窗口值。
输  入:WindowValue:指定要与downcounter比较的窗口值,该值必须小于0x80

1.4、void WWDG_EnableIT(void)
功  能:启用WWDG早期唤醒中断(EWI)
输  入:无

1.5、void WWDG_SetCounter(uint8_t Counter)
功  能:设置WWDG计数器值
输  入:Counter:指定看门狗计数器值,该值必须是介于0x40和0x7F之间的数字。

1.6、void WWDG_Enable(uint8_t Counter)
功  能:启用WWDG并加载计数器值
输  入:Counter:指定看门狗计数器值,该值必须是介于0x40和0x7F之间的数字。

1.7、FlagStatus WWDG_GetFlagStatus(void)
功  能:检查是否设置了早期唤醒中断标志
输  入:无

1.8、void WWDG_ClearFlag(void)
功  能:清除提前唤醒中断标志
输  入:无

2、硬件设计
窗口看门狗属于CH32V103内部资源,无需进行任何硬件设计,只需通过串口调试助手打印显示观察其运行状态即可。

3、软件设计
本教程中窗口看门狗主要通过在窗口时间内喂狗或在中断服务函数内喂狗保证系统程序正常运行,其具体程序如下:
wwdg.h文件
  1. #ifndef __WWDG_H
  2. #define __WWDG_H

  3. #include "ch32v10x_conf.h"
  4. #define  WWDG_CNT  0x7f

  5. void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv);
  6. void WWDG_NVIC_Config(void);
  7. void WWDG_IRQHandler(void);
  8. void WWDG_Feed(void);

  9. #endif
wwdg.h文件主要是相关定义及函数声明。
wwdg.c文件
  1. #include "wwdg.h"

  2. void WWDG_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

  3. //初始化窗口看门狗,tr:递减计数器值;wr:上窗口值;prv:分频系数
  4. void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv)
  5. {
  6.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); //WWDG时钟使能

  7.     WWDG_SetCounter( tr );      //设置WWDG递减计数器值
  8.     WWDG_SetWindowValue( wr );  //设置WWDG上窗口值
  9.     WWDG_SetPrescaler( prv );   //设置WWDG预分频器值
  10.     WWDG_Enable(WWDG_CNT);      //设置计数器初始值并使能看门狗
  11.     WWDG_ClearFlag();           //清除提前唤醒中断标志
  12.     WWDG_NVIC_Config();         //初始化窗口看门狗NVIC
  13.     WWDG_EnableIT();            //开启窗口看门狗中断
  14. }

  15. //初始化看门狗NVIC,配置优先级
  16. void WWDG_NVIC_Config(void)
  17. {
  18.   NVIC_InitTypeDef NVIC_InitStructure;
  19.   NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;           //WWDG中断
  20.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级 0
  21.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //响应优先级 0
  22.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           //使能通道1中断
  23.   NVIC_Init(&NVIC_InitStructure);                           //NVIC初始化
  24. }

  25. //WWDG中断服务函数
  26. void WWDG_IRQHandler(void)
  27. {
  28.     WWDG_Feed();
  29.     WWDG_ClearFlag();           //清除提前唤醒中断标志位
  30.     printf("Execute interrupt function\r\n");
  31. }

  32. //喂狗
  33. void WWDG_Feed(void)
  34. {
  35.     WWDG_SetCounter( WWDG_CNT );//喂狗,刷新递减计数器的值,设置成最大WWDG_CNT=0X7F
  36. }
wwdg.c文件主要是WWDG相关配置,其具体配置流程如下:
1、进行WWDG配置,包括开启WWDG时钟、设置计数器值、窗口值和预分频器值等;
  1. //初始化窗口看门狗,tr:递减计数器值;wr:上窗口值;prv:分频系数
  2. void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv)
  3. {
  4.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); //WWDG时钟使能

  5.     WWDG_SetCounter( tr );      //设置WWDG递减计数器值
  6.     WWDG_SetWindowValue( wr );  //设置WWDG上窗口值
  7.     WWDG_SetPrescaler( prv );   //设置WWDG预分频器值
  8.     WWDG_Enable(WWDG_CNT);      //设置计数器初始值并使能看门狗
  9.     WWDG_ClearFlag();           //清除提前唤醒中断标志
  10.     WWDG_NVIC_Config();         //初始化窗口看门狗NVIC
  11.     WWDG_EnableIT();            //开启窗口看门狗中断
  12. }
2、WWDG NVIC初始化配置,设置优先级分组;
  1. //初始化看门狗NVIC,配置优先级
  2. void WWDG_NVIC_Config(void)
  3. {
  4.   NVIC_InitTypeDef NVIC_InitStructure;
  5.   NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;           //WWDG中断
  6.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级 0
  7.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //响应优先级 0
  8.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           //使能通道1中断
  9.   NVIC_Init(&NVIC_InitStructure);                           //NVIC初始化
  10. }
3、编写WWDG喂狗函数;
  1. //喂狗
  2. void WWDG_Feed(void)
  3. {
  4.     WWDG_SetCounter( WWDG_CNT );//喂狗,刷新递减计数器的值,设置成最大WWDG_CNT=0X7F
  5. }
4、编写中断服务函数
  1. //WWDG中断服务函数
  2. void WWDG_IRQHandler(void)
  3. {
  4.     WWDG_Feed();
  5.     WWDG_ClearFlag();           //清除提前唤醒中断标志位
  6.     printf("Execute interrupt function\r\n");
  7. }
wwdg.c文件主要进行窗口看门狗相关函数配置
main.c文件
  1. int main(void)
  2. {
  3.     u8 wwdg_tr,wwdg_wr;

  4.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  5.     Delay_Init();
  6.     USART_Printf_Init(115200);

  7.     printf("SystemClk:%d\r\n",SystemCoreClock);
  8.     printf("WWDG Test\r\n");

  9.     WWDG_Config(0x7f,0x5f,WWDG_Prescaler_8);      /* 36M/8/4096 */
  10.     wwdg_wr=WWDG->CFGR & 0x7F;
  11.     while(1)
  12.      {
  13.         Delay_Ms(70);
  14.         printf("The program runs normally\r\n");
  15.         wwdg_tr=WWDG->CTLR & 0x7F;
  16.         if(wwdg_tr<wwdg_wr)
  17.          {
  18.            WWDG_Feed();
  19.          }
  20.      }
  21. }
main.c文件主要进行相关函数初始化以及根据判断进行喂狗操作。其中,while循环中延时函数值不宜设置过大,其值根据计数器值、上窗口值和下窗口值进行设置。若设置过大,则会进入中断,本程序在中断中调用喂狗函数以保障程序正常运行,若无喂狗函数,则程序会不停复位。

4、下载验证
将编译好的程序下载到开发板并复位,打开串口调试助手,可看到串口调试助手一直在打印输出:The program runs normally,如图所示:
图片1.png
将main函数while循环中延时函数值增大大,函数将会进入中断通过中断服务函数进行喂狗,串口调试助手打印显示如下:
图片2.png




5、WWDG.rar

553.9 KB, 下载次数: 77

wgtwgtwgt 发表于 2022-3-27 10:20 | 显示全部楼层
喂狗时使用0x7f刷新递减计算器:
  1. //喂狗

  2. void WWDG_Feed(void)

  3. {

  4.     WWDG_SetCounter( WWDG_CNT );//喂狗,刷新递减计数器的值,设置成最大WWDG_CNT=0X7F

  5. }
但是根据手册:
82992623fc6f7127e1.png 10546623fc6e0ddce7.png

当前值T[6:0]>窗口值W[6:0]会引发RESET复位。
现在WWDG_Feed()函数中设置WWDG_SetCounter()的参数为WWDG_CNT,即0x7f,也就是设置当前值T[6:0]为0x7f,而在main()函数中有:
  1. WWDG_Config(0x7f,0x5f,WWDG_Prescaler_8);
即设置窗口值W[6:0]为0x5f。显然0x7f>0x5f,根据框图8-1会引发复位,所以用0x7f喂狗似乎不妥。
如果设置窗口值为0x5f,那么应该用0x5f与0x3f之间的值喂狗,即0x3f≤喂狗值≤0x5f。
不知上述理解是否正确,恳请指正。


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

本版积分规则

133

主题

296

帖子

45

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

133

主题

296

帖子

45

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