zl程序教程

您现在的位置是:首页 >  Java

当前栏目

(十六)STM32——尝试把窗口看门狗当成游戏中的困难模式来理解

2023-02-18 15:49:57 时间

目录

学习目标

内容

需求

简介

工作过程

配置

时间配置 

寄存器

配置步骤

代码

运行结果

总结 


        本文基于正点原子的教程,算是自己的一种理解吧!为了让大家更能理解,就省略了一些配置过程以及寄存器的详细介绍,如果有一些类比不准确之处,还请各位见谅,感兴趣的同学可以去看开发手册或者教学视频。谢谢大家了! 

学习目标

        本节我们还在上一篇文章上的基础来用一个虚构的游戏来讲解窗口看门狗的知识点,在此先给出上篇文章的链接:尝试把独立看门狗当成一款游戏来理解 个人浅显的理解,窗口看门狗相当于我们独立看门狗的加强版,也就相当于我们游戏的困难模式。于是我们现在就来讲讲这个困难模式!

内容

需求

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

        用通俗的话来解释就是:之前的游戏难度太小了,因为你可以一直喂狗,甚至有可能把狗吸引到身边,一边偷东西一边喂狗,或者直接偷狗,所以我们就直接加难度。

简介

        窗口看门狗通常被用来监测,由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。除非递减计数器的值在 T6 位变成 0 前被刷新,看门狗电路在达到预置的时间周期时,会产生一个 MCU 复位。如果在递减计数器达到窗口寄存器值之前刷新控制寄存器中的 7 位递减计数器值,也会产生 MCU 复位。这意味着必须在限定的时间窗口内刷新计数器。之所以称为窗口就是因为其喂狗时间是一个有上下限的范围内(窗口),可以通过设定相关寄存器,设定其上限时间(下限固定)。喂狗的时间不能过早也不能过晚。

        用通俗的话来说就是现在这条狗特别精明,太饱了的话,你再喂他吃东西,他就觉得不对劲,于是便会叫,吸引他人的注意,游戏失败!所以应该卡在一个合适的时间去喂狗,加大了我们的难度。

工作过程

这个就是窗口看门狗的工作过程,窗口的上限由我们自己设置,而下限就是0x3F 的时候,也就是第六位由1变0。而且有一个好玩的地方:如果启动了看门狗并且允许中断,当递减计数器等于0x40时产生早期唤醒中断(EWI),它可以用于喂狗以避免WWDG复位。相当于开了一个喂狗外挂,当它到0x40的时候,就会帮我们去喂狗,岂不妙哉!

        这个就是内部的框图,当超过窗口上限喂狗的话,就会触发复位,而当低于下限值时,同样也会触发复位。

配置

时间配置 

Twwdg=(4096×2^WDGTB×(T[5:0]+1)) /Fpclk1;

  • Twwdg:WWDG 超时时间(单位为 ms)
  • Fpclk1:APB1 的时钟频率(单位为 Khz)
  • WDGTB:WWDG 的预分频系数
  • T[5:0]:窗口看门狗的计数器低 6 位

        这个和我们之前的独立看门狗是类似的,只不过加了一个上限值,还有一个APB1时钟,这个我们马上来介绍,目前可以简单理解为,这个困难模式如此困难,所以我们需要一个精准的手表来控制时间,而APB1就是这个精准的手表。

寄存器

        还是同之前一样,寄存器部分我们不做详细介绍,感兴趣的同学可以去看手册,比较好理解,我们重点介绍一下流程。

配置步骤

  1. 使能 WWDG 时钟,这一步相当于我们买装备了,购买一个高精度的手表,帮助我们通关
  2. 设置窗口值和分频数,就是设置投喂窗口和时间范围
  3. 开启 WWDG 中断并分组,这个就相当于开外挂了,配置一个中断来帮我们喂狗
  4. 设置计数器初始值并使能看门狗,相当于准备开始游戏了
  5. 编写中断服务函数,在中断函数写上喂狗的操作,整个外挂就完成了

代码

#include "wwdg.h"
#include "led.h"
//保存WWDG计数器的设置值,默认为最大. 
u8 WWDG_CNT=0X7F;
//初始化窗口看门狗 	
void WWDG_Init(u8 tr,u8 wr,u32 fprer)
{
 
	NVIC_InitTypeDef NVIC_InitStructure;
 
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); //使能窗口看门狗时钟
	
	WWDG_CNT=tr&WWDG_CNT;   //初始化WWDG_CNT. 获取低七位,tr  :T[6:0],计数器值 
	
	WWDG_SetWindowValue(wr); //设置窗口值,wr   :W[6:0],窗口值 
	WWDG_SetPrescaler(fprer); //设置分频值,fprer:分频系数(WDGTB),仅最低2位有效 
	
	NVIC_InitStructure.NVIC_IRQChannel=WWDG_IRQn;  //窗口看门狗中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02;  //抢占优先级为2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03;					//子优先级为3
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;  //使能窗口看门狗
	NVIC_Init(&NVIC_InitStructure);
	

	WWDG_EnableIT();//开启提前唤醒中断
	WWDG_Enable(WWDG_CNT);  //开启看门狗,第一次喂狗
	
	WWDG_ClearFlag();//清除提前唤醒中断标志位

}

//窗口看门狗中断服务程序 
void WWDG_IRQHandler(void)
{
	WWDG_SetCounter(WWDG_CNT); //重设窗口看门狗值
	WWDG_ClearFlag();//清除提前唤醒中断标志位
	LED0=!LED0;
}

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "beep.h"
#include "wwdg.h"


int main(void)
{ 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	delay_init(168);  //初始化延时函数
	LED_Init();				//初始化LED端口
	BEEP_Init();
	LED1=0;				   //点亮LED0

	delay_ms(10);
	WWDG_Init(0x7F,0X5F,WWDG_Prescaler_8); 	//计数器值为7f,窗口寄存器为5f,分频数为8	   
	// 程序会一直卡在这喂狗,进不了循环(doge)
	while(1)
	{
		LED1=1;  //熄灭LED灯,不会灭
		BEEP =! BEEP ;//不会响
	}
}

运行结果

        仔细看,红灯在一闪一闪,就是说明进入了中断。

https://player.bilibili.com/player.html?aid=386912114

窗口看门狗

总结 

        这是博主第一次使用这种类比游戏的思路来写文章,如果大家觉得好玩或者有收获的话,还希望可以帮我点一个免费的赞,激励博主继续更文,好了,谢谢大家的阅读!