【单片机】CH32V103C8T6 ——窗口看门狗
本章教程通过串口调试助手打印显示程序运行状态,具体现象如下:
- 若计数器值在上窗口值和下窗口值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应用手册。
本章教程通过调用窗口看门狗库函数中相关函数进行程序编写,关于库函数相关介绍如下:
void WWDG_DeInit(void); void WWDG_SetPrescaler(uint32_t WWDG_Prescaler); void WWDG_SetWindowValue(uint8_t WindowValue); void WWDG_EnableIT(void); void WWDG_SetCounter(uint8_t Counter); void WWDG_Enable(uint8_t Counter); FlagStatus WWDG_GetFlagStatus(void); 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文件
#ifndef __WWDG_H #define __WWDG_H #include "ch32v10x_conf.h" #define WWDG_CNT 0x7f void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv); void WWDG_NVIC_Config(void); void WWDG_IRQHandler(void); void WWDG_Feed(void); #endif
wwdg.h文件主要是相关定义及函数声明。
wwdg.c文件
#include "wwdg.h" void WWDG_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); //初始化窗口看门狗,tr:递减计数器值;wr:上窗口值;prv:分频系数 void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); //WWDG时钟使能 WWDG_SetCounter( tr ); //设置WWDG递减计数器值 WWDG_SetWindowValue( wr ); //设置WWDG上窗口值 WWDG_SetPrescaler( prv ); //设置WWDG预分频器值 WWDG_Enable(WWDG_CNT); //设置计数器初始值并使能看门狗 WWDG_ClearFlag(); //清除提前唤醒中断标志 WWDG_NVIC_Config(); //初始化窗口看门狗NVIC WWDG_EnableIT(); //开启窗口看门狗中断 } //初始化看门狗NVIC,配置优先级 void WWDG_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn; //WWDG中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级 0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应优先级 0 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能通道1中断 NVIC_Init(&NVIC_InitStructure); //NVIC初始化 } //WWDG中断服务函数 void WWDG_IRQHandler(void) { WWDG_Feed(); WWDG_ClearFlag(); //清除提前唤醒中断标志位 printf("Execute interrupt function\r\n"); } //喂狗 void WWDG_Feed(void) { WWDG_SetCounter( WWDG_CNT );//喂狗,刷新递减计数器的值,设置成最大WWDG_CNT=0X7F }
wwdg.c文件主要是WWDG相关配置,其具体配置流程如下:
1、进行WWDG配置,包括开启WWDG时钟、设置计数器值、窗口值和预分频器值等;
//初始化窗口看门狗,tr:递减计数器值;wr:上窗口值;prv:分频系数 void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); //WWDG时钟使能 WWDG_SetCounter( tr ); //设置WWDG递减计数器值 WWDG_SetWindowValue( wr ); //设置WWDG上窗口值 WWDG_SetPrescaler( prv ); //设置WWDG预分频器值 WWDG_Enable(WWDG_CNT); //设置计数器初始值并使能看门狗 WWDG_ClearFlag(); //清除提前唤醒中断标志 WWDG_NVIC_Config(); //初始化窗口看门狗NVIC WWDG_EnableIT(); //开启窗口看门狗中断 }
//初始化看门狗NVIC,配置优先级 void WWDG_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn; //WWDG中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级 0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应优先级 0 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能通道1中断 NVIC_Init(&NVIC_InitStructure); //NVIC初始化 }
//喂狗 void WWDG_Feed(void) { WWDG_SetCounter( WWDG_CNT );//喂狗,刷新递减计数器的值,设置成最大WWDG_CNT=0X7F } //WWDG中断服务函数 void WWDG_IRQHandler(void) { WWDG_Feed(); WWDG_ClearFlag(); //清除提前唤醒中断标志位 printf("Execute interrupt function\r\n"); }
wwdg.c文件主要进行窗口看门狗相关函数配置
main.c文件
int main(void) { u8 wwdg_tr,wwdg_wr; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); Delay_Init(); USART_Printf_Init(115200); printf("SystemClk:%d\r\n",SystemCoreClock); printf("WWDG Test\r\n"); WWDG_Config(0x7f,0x5f,WWDG_Prescaler_8); /* 36M/8/4096 */ wwdg_wr=WWDG->CFGR & 0x7F; while(1) { Delay_Ms(70); printf("The program runs normally\r\n"); wwdg_tr=WWDG->CTLR & 0x7F; if(wwdg_tr<wwdg_wr) { WWDG_Feed(); } } }