STM32工作笔记0060---窗口看门狗实验

技术交流QQ群【JAVA,C++,Python,.NET,BigData,AI】:170933152

这个独立看门狗和窗口看门狗的不一样的地方就是,

这个独立看门狗,前面说过,他就是从rlr倒数,倒数到0的时候,

就会触发复位,只要是,再倒数到0之前喂狗就不会复位.

这个窗口看门狗的概念,就是,喂狗的时间,要在这个规定的窗口之间来喂狗,

也就是,窗口看门狗有个窗口范围,要在这个窗口范围内喂狗才行,在窗口范围外喂狗的时候

都会触发复位.

比如:

rlr的值是100

那么窗口上沿是:80

窗口下沿是:30

那么,这个时候要喂狗就要在计数,计数到30到80之间的时候去喂狗,才是有效的喂狗

如果在90的时候喂狗,就会触发复位,再20的时候喂狗也会触发复位.

再来看一下,

可以看到实际上,这个跟图上说的一样,只有在圈1的范围内的时候,才能进行喂狗,

实际上就是在3Fh和W6:0这个范围内进行喂狗才行.

也就是在刷新窗口的那个范围才能开始喂狗,也必须在这个范围内喂狗,如果不在这个

范围内喂狗的话,就会触发复位,

要注意这里的0X3FH这个下窗口是固定的,而上窗口,是可以通过寄存器设置的.

这里的T6位是,超过上窗口喂狗的时候产生的复位信号,

这里的复位是,低于下窗口喂狗的时候产生的复位信号.

让MCU复位.

窗口看门狗的概述,也就是窗口看门狗的原理.

首先整个窗口看门狗的时钟,来至于PCLK1 实际上 还要除以 4096

然后这个时钟,经过除以4096,然后把这个时钟源给WDGTB这个看门狗预分频器,然后

给上面的6位递减计数器,CNT提供时钟来源,

然后这个时候,如果T6这个位,也就是写入的值,大于上窗口的时候,这个时候得到比较结果是1

然后,这个时候如果写了一个WWDG_CR,也就是一个rlr值的,话,那么图上,写入WWDG_CG这个重装载值

这个也是1

然后经过一个与操作,结果出来一个1.

然后T6可以看到写入的是个1,所以经过或以后还是1.

然后如果启动位这个时候也设置为1的话,那么这个电路整个的结果就是1,也就是会产生一个复位信号了.

另一个种会产生复位的情况,可以看到如果这里的T6也就是写入的值,

也就是T6这一位从1变成了0的时候,也就是写入的值是0X3F的时候,这个事实在输入值的位置,左侧连接T6的地方可以看到一个圈,这个是取反的意思,这个时候取反由0变成了1,然后再进行跟,上面的当T6:<W6的时候是0,1跟0进行或运算.

也就是,出来的值是1,然后这个时候启动位如果是1的话,也就是窗口看门狗启动的话,

这个时候,1和1,与运算,结果也是1.也就是说这个时候也会产生复位信号.

也就是说,不管是,大于上窗口的值,还是小于下窗口的值,都会产生复位信号

总结一下,产生复位的两种情况.

上面的1跟2.就是上面说的那两种情况

注意,这里,当计数器等于0x40的时候,会产生一个中断,这个时候,就是提醒一下,如果再不喂狗就会复位了.

所以,就可以在这个中断中进行喂狗操作.

twwdg是超时时间

Fpclk1:是时钟频率

WDGTB是预分频系数

T5是窗口看门狗的计数器低六位

计算的话,套入公式计算就可以了,跟前面的

这里,为什么要用窗口看门狗,一般的看门口,可以在倒计数到0的,任何一个时刻,去喂狗,这个时候

有个隐患,就是如果程序跑乱了,然后这个跑乱的程序,正好产生了一个喂狗的操作,就会导致,程序

不会复位了,这样程序就会继续乱下去,而窗口看门狗,就把喂狗的操作,限制在了,一个上下窗口

中,这样就大大降低了出错的几率,因为,程序跑乱了,并且,还恰好出现喂狗的错误,并且,还在

上下窗口的范围内喂狗,这样的错误几率会很小.

注意,上窗口是咱们自己设置的,但是自己设置的值要大于0x40才行,

窗口看门狗时钟来源是PCLK1.而一般的看门狗时钟来源于LSI..

控制器WWDG_CR,这个寄存器的作用是,它有7位,其中最高位WDGA,是1的时候,表示启动窗口看门狗,

然后,另外的T0到T6位,如果向这7个位中写入值的话,其实就是相当于去喂狗了

对于一般看门狗来说,喂狗是,把RLR寄存器的值,重新加载到KR寄存器中,而对于窗口看门狗就是

直接在CR寄存器中写入值了.

再看这个CFR寄存器,这里的W6到0位,设置的值是上窗口的值.

然后WDGTB8到7位,这2位,设置的是时基,也就是预分频系数

然后EWI,位9,为1的时候,这个时候当计数器的值到达0X40的时候,

就会产生中断.就可以在这个中断中进行喂狗.

SR寄存器,也就是当计数器的值到0x40的时候,这个位0就会变成1.

可以查询这个值来实现,对中断的判断.

然后看一下代码

打开代码看看

解释一下这几个代码

首先WWDG_DeInit(void),这个是把窗口看门狗进行复位

第二行:是设置预分频系数

WWDG_SetPrescaler(uint32_t WWDG_Prescaler)

设置预分频器

然后设置窗口的value值.实际上就是设置CFR寄存器的位6

然后这里的WWDG_EnableIT(void),这个实际上是使能的,提前唤醒中断.

也就是当计数器到0x40的时候,会产生中断.

然后,WWDG_SetCounter(uint8_t Counter)

这个是喂狗操作,

 可以看到WWDG_SetCounter(uint8_t Counter),这个是喂狗操作.

实际就是往T6到T0写入值.

然后就是去启动窗口看门狗

注意:

WWDG_Enable()

这个功能除了开始这个窗口看门狗以外,还可以同时设置初始值,因为这里的参数是个UINT8这个,除了设置第位7,还可以

设置为6到0

然后就是,获取,和清除窗口看门狗的标志位

前面说过,这里SR寄存器的位0.如果是1的话,就会产生中断,每当值到0x40的时候就会产生中断.

这里的这个1就是需要,用上面的这个函数去清除这个中断标志位.

上面又说了一遍,窗口看门狗的配置步骤,

首先使能看门狗时钟1,然后设置窗口看门狗的分频系数2

然后再去设置窗口看门狗的,上窗口值3,

然后开启中断唤醒4,因为开启了中断,所以这里要配置中断优先级,首先要设置中断分组.

然后5再使能看门狗WWDG_Enable(),使能看门狗以后,

然后再,编写中断函数7,然后在中断函数中进行喂狗6.

然后看看代码去:

这里

void WWDG_Init(u8 tr,u8 wr,u32 fprer);//初始化WWDG 初始化窗口看门狗
void WWDG_Set_Counter(u8 cnt);       //设置WWDG的计数器 喂狗操作
void WWDG_NVIC_Init(void);  //设置中断优先级

然后依次看一下这三个函数

这个函数WWDG_Init(tr,wr,fprer)

这三个参数,第一个是计数器的值,也就是,初始化的时候,窗口看门狗就按照这个值,去倒数,

然后第二个是窗口值,也就是上窗口值,下窗口值是固定的.

然后第3个参数是,分频系数,用来确定窗口看门狗的时钟频率

可以看到这里,WWDG_CNT这个变量,设置了一个0X7F,这个的作用,7f实际上是低7位,做一个与运算

实际上就是去获取计数器值的,低7位,作为有效的数据位.

//保存WWDG计数器的设置值,默认为最大. 
u8 WWDG_CNT=0x7f; 
//初始化窗口看门狗 	
//tr   :T[6:0],计数器值 
//wr   :W[6:0],窗口值 
//fprer:分频系数(WDGTB),仅最低2位有效 
//Fwwdg=PCLK1/(4096*2^fprer). 

void WWDG_Init(u8 tr,u8 wr,u32 fprer)
{ 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);  //   WWDG时钟使能

	WWDG_CNT=tr&WWDG_CNT;   //初始化WWDG_CNT. 这里实际上避免传过来的值过大,
    //这里只去获取低7位的值
	WWDG_SetPrescaler(fprer);设置IWDG预分频值

	WWDG_SetWindowValue(wr);//设置窗口值

    //这里除了使能,还可以进行设置,初始值,去定义的位置可以看的到
    //void WWDG_Enable(uint8_t Counter)
    //{
    ///* Check the parameters */
    //assert_param(IS_WWDG_COUNTER(Counter));
    //WWDG->CR = CR_WDGA_Set | Counter; //可以看到这里,实际上除了使能,还进行设置初始值了
    //}

	WWDG_Enable(WWDG_CNT);	 //使能看门狗 ,	设置 counter .                  

	WWDG_ClearFlag();//清除提前唤醒中断标志位 

	WWDG_NVIC_Init();//初始化窗口看门狗 NVIC

	WWDG_EnableIT(); //开启窗口看门狗中断
} 

然后,看看喂狗的函数

可以看到实际上他也是,用的这个使能的函数,只不过这个使能的函数同时也有喂狗的功能

看看中断服务函数,

这里 ,首先是喂狗,然后清除提前唤醒中断标志位.

然后LED灯翻转.

这里的main.c看一下

首先是一堆的初始化,然后,中断优先级分组是2

然后LED0是亮的,然后

开启窗口看门狗,这里的初始值也就上窗口的值是0X7F,然后喂狗值是0X5F,然后分频是8,分频

然后死循环,把LED0设置为设置为1,也就是如果

没有喂狗,程序就不会不停的产生复位,这里的没有喂狗就是指,注释掉第一句喂狗的语句,然后

不停的复位,就会导致LED0会不停的闪烁,这个时候闪烁的是红灯.

注意喂狗的时候,喂完狗要把这个提前唤醒中断标志位置0,因为这个位是由硬件自动

置1的,每当计数器到0x40的时候,就会自动被硬件置1,所以这里要清除.

先看一下,这里注释掉喂狗语句的效果

没有喂狗,不停产生复位,LED0就是红灯就会不停的翻转.

如果喂狗的话,就不会产生复位,那么喂狗中的那个LED1就会翻转,这样就会是LED1闪烁,也就是绿灯闪烁.

完整的代码看一下:

wdg.h

#ifndef __WDG_H
#define __WDG_H
#include "sys.h"
//	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//Mini STM32开发板
//看门狗 驱动代码		   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2010/5/30
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 正点原子 2009-2019
//All rights reserved
// 	  


void IWDG_Init(u8 prer,u16 rlr);
void IWDG_Feed(void);

void WWDG_Init(u8 tr,u8 wr,u32 fprer);//初始化WWDG
void WWDG_Set_Counter(u8 cnt);       //设置WWDG的计数器
void WWDG_NVIC_Init(void);
#endif

wdg.c

#include "wdg.h"
#include "led.h"
//	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK精英STM32开发板
//看门狗 驱动代码	   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/9/3
//版本:V1.1
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved
//********************************************************************************
//V1.1 20120903
//增加了窗口看门狗相关函数。									  
// 

void IWDG_Init(u8 prer,u16 rlr) 
{	
 	IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);  //使能对寄存器IWDG_PR和IWDG_RLR的写操作
	
	IWDG_SetPrescaler(prer);  //设置IWDG预分频值:设置IWDG预分频值为64
	
	IWDG_SetReload(rlr);  //设置IWDG重装载值
	
	IWDG_ReloadCounter();  //按照IWDG重装载寄存器的值重装载IWDG计数器
	
	IWDG_Enable();  //使能IWDG
}
//喂独立看门狗
void IWDG_Feed(void)
{   
 	IWDG_ReloadCounter();	//重载计数值									   
}


//保存WWDG计数器的设置值,默认为最大. 
u8 WWDG_CNT=0x7f; 
//初始化窗口看门狗 	
//tr   :T[6:0],计数器值 
//wr   :W[6:0],窗口值 
//fprer:分频系数(WDGTB),仅最低2位有效 
//Fwwdg=PCLK1/(4096*2^fprer). 

void WWDG_Init(u8 tr,u8 wr,u32 fprer)
{ 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);  //   WWDG时钟使能

	WWDG_CNT=tr&WWDG_CNT;   //初始化WWDG_CNT.   
	WWDG_SetPrescaler(fprer);设置IWDG预分频值

	WWDG_SetWindowValue(wr);//设置窗口值

	WWDG_Enable(WWDG_CNT);	 //使能看门狗 ,	设置 counter .                  

	WWDG_ClearFlag();//清除提前唤醒中断标志位 

	WWDG_NVIC_Init();//初始化窗口看门狗 NVIC

	WWDG_EnableIT(); //开启窗口看门狗中断
} 
//重设置WWDG计数器的值
void WWDG_Set_Counter(u8 cnt)
{
    WWDG_Enable(cnt);//使能看门狗 ,	设置 counter .	 
}
//窗口看门狗中断服务程序
void WWDG_NVIC_Init()
{
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;    //WWDG中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;   //抢占2,子优先级3,组2	
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;	 //抢占2,子优先级3,组2	
  NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; 
	NVIC_Init(&NVIC_InitStructure);//NVIC初始化
}

void WWDG_IRQHandler(void)
	{

	WWDG_SetCounter(WWDG_CNT);	  //当禁掉此句后,窗口看门狗将产生复位

	WWDG_ClearFlag();	  //清除提前唤醒中断标志位

	LED1=!LED1;		 //LED状态翻转
	}

main.c

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "wdg.h"

 
/************************************************
 ALIENTEK精英STM32开发板实验7
 窗口看门狗实验 
 技术支持:www.openedv.com
 淘宝店铺:http://eboard.taobao.com 
 关注微信公众平台微信号:"正点原子",免费获取STM32资料。
 广州市星翼电子科技有限公司  
 作者:正点原子 @ALIENTEK
************************************************/

 int main(void)
 {		
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 //串口初始化为115200
 	LED_Init();
	KEY_Init();          //按键初始化	 
	LED0=0;
	delay_ms(300);	  
	WWDG_Init(0X7F,0X5F,WWDG_Prescaler_8);//计数器值为7f,窗口寄存器为5f,分频数为8	   
 	while(1)
	{
		LED0=1;			  	   
	}   
}
  

猜你喜欢

转载自blog.csdn.net/lidew521/article/details/108247849