技术交流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;
}
}