文章目录
- 一、WWDG 简介
- 二、WWDG 功能框图
- 窗口看门狗时钟
- 计数器时钟
- 计数器
- 窗口值
- 三、计算超时时间
- 四、STM32Cube MX配置
- 五、代码详解
- 附录
一、WWDG 简介
STM32 有两个看门狗,一个是独立看门狗,一个是窗口看门狗。
独立看门狗的工作原理就是一个递减计数器不断的往下递减计数,当减到0 之前如果没有喂狗的话,产生复位。
窗口看门狗和独立看门狗一样,也是一个递减计数器不断的往下递减计数,当减到一个固定值0X40时还不喂狗的话,产生复位,这个值叫窗口的下限,是固定的值,不能改变。
不同的地方是窗口看门狗的计数器的值在减到某一个数之前喂狗的话也会产生复位,这个值叫窗口的上限,上限值由用户独立设置。
窗口看门狗计数器的值必须在上窗口和下窗口之间才可以喂狗,这就是窗口看门狗中窗口两个字的含义.
WWDG 一般被用来监测,由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。比如一个程序段正常运行的时间是50ms,在运行完这个段程序之后紧接着进行喂狗,如果在规定的时间窗口内还没有喂狗,那就说明我们监控的程序出故障了,跑飞了,那么就会产生系统复位,让程序重新运行。
二、WWDG 功能框图
窗口看门狗时钟
窗口看门狗时钟来自PCLK1,PCLK1 最大是36M,由RCC 时钟控制器开启。
计数器时钟
计数器时钟由CK 计时器时钟经过预分频器分频得到,分频系数由配置寄存器CFR 的位8:7 WDGTB[1:0] 配置,可以是[0,1,2,3],其中CK 计时器时钟=PCLK1/4096,除以4096 是手册规定的。所以计数器的时钟CNT_CK=PCLK1/4096/(2^WDGTB),
这就可以算出计数器减一个数的时间T= 1/CNT_CK = Tpclk1 * 4096 * (2^WDGTB)。
计数器
窗口看门狗的计数器是一个递减计数器,共有7 位,其值存在控制寄存器CR 的位6:0,即T[6:0],当7 个位全部为1 时是0X7F,这个是最大值,当递减到T6 位变成0 时,即从0X40 变为0X3F 时候,会产生看门狗复位。
这个值0X40 是看门狗能够递减到的最小值,所以计数器的值只能是:0X40~0X7F (64 ~ 127)之间,实际上真正用来计数的是T[5:0]。
当递减计数器递减到0X40 的时候,还不会马上产生复位,如果使能了提前唤醒中断 :CFR 位9 EWI 置1,则产生提前唤醒中断,如果真进入了这个中断的话,就说明程序肯定是出问题了,那么在中断服务程序里面我们就需要做最重要的工作,比如保存重要数据,或者报警等,这个中断也叫死前中断。
窗口值
窗口看门狗必须在计数器的值在一个范围内才可以喂狗,其中下窗口的值是固定的0X40,上窗口的值可以改变,具体的由配置寄存器CFR 的位6:0 W[6:0] 设置。
其值必须大于0X40,如果小于或者等于0X40 就是失去了窗口的价值,而且也不能大于计数器的值,所以必须得小于0X7F。
如果我们要监控的程序段A 运行的时间为T1,当执行完这段程序之后就要进行喂狗,如果在窗口时间内没有喂狗的话,那程序就肯定是出问题了。
一般计数器的值TR 设置成最大0X7F,窗口值为WR,计数器减一个数的时间为T,那么时间:(TR-WR)*T 应该稍微大于T1 即可,这样就能做到刚执行完程序段A 之后喂狗,起到监控的作用,这样也就可以算出WR 的值是多少。
三、计算超时时间
同时在这里也介绍两种计算办法:
第一种计算方法
这个图来自数据手册,从图我们知道
看门狗超时时间:Twwdg = Tpclk1 x 4096 x 2^wdgtb x (T[5:0]+ 1) ms;
当PCLK1 = 36MHZ 时,WDGTB 取不同的值时有最小和最大的超时时间;
当WDGTB=0时,递减计数器有7 位T[6:0] ,当位6 变为0 的时候就会产生复位,实际上有效的计数位是T[5:0],而且T6 必须先设置为1。如果T[5:0]=0 时,递减计数器再减一次,就产生复位了,那这减一的时间就等于计数器的周期=1/CNT_CK = Tpclk1 * 4096 * (2 ^WDGTB) = 1/36 * 4096 *2^ 0 = 113.7us,这个就是最短的超时时间。
如果T[5:0] 全部装满为1,即63,当他减到0X40 变成0X3F 时,所需的时间就是最大的超时时间=113.72^5=113.764=7.2768ms。
第二种计算方法
看门狗超时时间:Twwdg = ( 4096 * 窗口值 ) / PCLK1,
当PCLK1 = 36MHZ 时,WDGTB 取不同的值时有最小和最大的超时时间;
计数器最大值取127,窗口下限值为63,
最小超时时间:窗口上限值为64,窗口值为1
最大超时时间:窗口上限值为127,窗口值为64
当WDGTB=0时,分频系数为1,(STM32Cube MX可以直接配置分频系数)
最小超时时间=1/CNT_CK = (( 4096 * 分频系数 ) / PCLK1) * 窗口值 = 1/36 * 40961 = 113.7us;
最大的超时时间=1/CNT_CK = (( 4096 * 分频系数 ) / PCLK1) * 窗口值= 1/36 * 409664 =113.7*64=7.2768ms。
四、STM32Cube MX配置
配置RCC ,配置为外部晶振模式
配置SYS,debug配置为Serial Wire
配置一个串口,异步通信模式,用于输出调试信息
配置WWDG:
配置分频系数为8,窗口上限值为90,窗口下限值为63,计数器的值为127,窗口值为27,PCLK1 = 36kHz,
窗口时间 = ((4096分频系数)/PCLK1) * 27 = ((4096 * 8) / 36kHz) * 27 = 24.576 ms
最早喂狗时间 = ((4096分频系数)/PCLK1) * (127 - 90) = ((4096 * 8) / 36kHz) * 37 = 33.678 ms
最迟喂狗时间 = ((4096*分频系数)/PCLK1) * (127 - 63) = ((4096 * 8) / 36kHz) * 64 = 58.254 ms
配置时钟树
配置项目生成
五、代码详解
HAL库独立窗口狗:
HAL_WWDG_Init(WWDG_HandleTypeDef *hwwdg); //看门狗初始化
HAL_WWDG_Refresh(WWDG_HandleTypeDef *hwwdg); //喂狗
HAL_WWDG_IRQHandler(WWDG_HandleTypeDef *hwwdg); //看门狗中断处理函数
//功能: 判断中断是否正常,并进入中断回调函数
__weak HAL_WWDG_EarlyWakeupCallback(hwwdg); //看门狗中断回调函数
看门狗中断运行完成之后,便会进入看门狗的中断回调函数
程序示例:
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
// 这部分应该写需要被WWDG 监控的程序,程序运行行的时间决定了窗口值设置成多大。
// 根据在STM32Cube MX里面设置 窗口最早喂狗时间为33ms 最迟喂狗时间为58ms
// 计时器值,初始化成最大0X7F,当开启WWDG 时候,这个值会不断减小
// 当计数器的值大于窗口值时喂狗的话,会复位,当计数器减少到0X40
// 还没有喂狗的话就非常非常危险了,计数器再减一次到了0X3F 时就复位
// 所以要当计数器的值在窗口值和0X40 之间的时候喂狗,其中0X40 是固定的
// 如果打开复位中断,可以在复位中断中发送紧急信息,报警
/* WWDG试验 如果在窗口时期前喂狗,程序执行20ms 就喂狗,不会输出执行信息2,会直接复位 */
// printf("start 1 \r\n"); //程序开始输出 执行信息1
// HAL_Delay(20); //延时20ms,未到喂狗时间
// HAL_WWDG_Refresh(&hwwdg); //提前喂狗
// printf("start 2 \r\n"); //程序 执行信息2
/* WWDG试验 如果程序窗口时期没有喂狗,程序执行60ms 还没有喂狗*/
/* 不会输出执行信息2,会进入死前中断,输出报警信息 */
// printf("start 1 \r\n"); //程序开始输出 执行信息1
// HAL_Delay(60); //延时60ms,超过喂狗时间
// HAL_WWDG_Refresh(&hwwdg); //没有窗口时期喂狗
// printf("start 2 \r\n"); //程序 执行信息2
/* 执行了一个40ms的程序,然后喂狗,在33ms -- 58ms的窗口时期内进行喂狗 */
printf("start 1 \r\n"); //程序开始输出 执行信息1
HAL_Delay(40); //执行了一个40ms的程序
HAL_WWDG_Refresh(&hwwdg); //喂狗
printf("start 2 \r\n"); //输出执行信息 2
HAL_Delay(40); //又执行了一个40ms的程序
printf("start 3 \r\n"); //输出执行信息 3
HAL_WWDG_Refresh(&hwwdg); //喂狗,防止进入死前中断
}
/* USER CODE BEGIN 4 */
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
{
UNUSED(hwwdg);
printf("overtime\r\n"); //输出报警信息,超时没有喂狗
/* 也可以在复位中断里面写喂狗,这样退出中断的时候程序就正常了 */
//HAL_WWDG_Refresh(hwwdg); //喂狗
}
/* USER CODE END 4 */