1.WWDG介绍
1.1 WWDG简介
上一章我们已经介绍了IWDG,知道它的工作原理就是一个12位递减计数器不断递减计数,当减到0之前还未进行喂狗的话,产生一个MCU复位。
窗口看门狗WWDG其实和独立看门狗类似,它是一个7位递减计数器不断的往下递减计数,当减到一个固定值 0X40 时还不喂狗的话,产生一个MCU复位,这个值叫窗口的下限,是固定的值,不能改变,这个和独立看门狗是类似的。只不过独立看门狗是减0之前要复位,这里要在0X40之前要复位。
不同的是,窗口看门狗的计数器的值在减到某一个数之前喂狗的话也会产生复位,这个值叫窗口的上限,上限值由用户独立设置。窗口看门狗计数器的值必须在上窗口和下窗口之间可以刷新(喂狗),才不会产生复位。这也是窗口看门狗中“窗口”两个字的含义。
这很容易理解,7位计数器的最大值是127, 窗口下限 0X40是64,这是固定的。假定我将窗口上限值设为100,那么,当窗口看门狗启动后,它就从127开始递减,在它减到100之前,不能去刷新也就是重新装载100,否则会产生复位。只有在其递减到100以下,64之前,才可以重载100。如果掉到64以下(64来还不会复位,63就复位)还没有重载(喂狗)100,那么也会产生复位。
1.2 WWDG结构框图
要更好的理解窗口看门狗,就需要了解它内部的结构。
(1)标号1:WWDG时钟(在APB1总线上,因此需要将APB1总线时钟打开.APB1总线时钟通常为36MHZ。)
(2)标号2:WDG预分频器器
分频后的计数器时钟为:CK_CNT= PCLK1/4096/(2^WDGTB)。
除以4096是中文参考手册内公式规定,没有为什么。WDGTB叫做分频因子,取值可以是0,1,2,3四种情况。
假定取值为0,那么2的0次方为1.CK_CNT= PCLK1/4096/1=36MHZ/4086=8.78KHZ。
(3)标号3:7位递减计数器
窗口看门狗的超时时间计算公式如下:
Twwdg=(4096×2^WDGTB×(T[5:0]+1)) /PCLK1;
Twwdg为窗口看门狗的超时时间,单位为ms。
PCLK1为APB1的时钟频率,最大36MHz。
WDGTB为窗口看门狗的预分频系数。
T[5:0]为窗口看门狗的计数器低6位。
通常不使用这个公式来计算溢出时间,因为当计数由最大值0X7F(或者用户指定某个超过0X40的值)递减到0X40(0011 1111)时,如果我们打开了提前唤醒中断功能,那么这时就会产生一个中断提醒我们应该喂狗了,于是重置初值,重新开始计数。因为计到0X40时可以产生中断,所以不需要计算溢出时间以决定在多长时间内必须喂狗。当然,计算一下,心里了解多长时间必须喂狗也是可以的。
当递减到0X40并且产生中断喂狗时,必须在一个计数周期内完成喂狗,否则0X40再减1,就会启动MCU复位,程序就会重启。
(4)标号4:看门狗配置寄存器
这个就是喂狗时设置上窗口值,其值范围就是0X7F到0X40之间
(5)标号5:系统复位信号
2.WWDG配置步骤
接下来我们介绍下如何使用库函数对WWDG进行配置。这个也是在编写程序中必须要了解的。具体步骤如下:(WWDG相关库函数在stm32f10x_wwdg.c和stm32f10x_wwdg.h文件中)。
(1)使能WWDG时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);
(2)设置WWDG窗口值和分频数
void WWDG_SetWindowValue(uint8_t WindowValue);
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);
分频系数可以为WWDG_Prescaler_1、WWDG_Prescaler_2、WWDG_Prescaler_4、W
WDG_Prescaler_8。
(3)开启WWDG中断并分组
NVIC_Init();
WWDG_EnableIT();
(4)设置计数器初始值并使能WWDG
void WWDG_Enable(uint8_t Counter);
void WWDG_SetCounter(uint8_t Counter);
(5)编写WWDG中断服务函数
WWDG_IRQHandler
WWDG_ClearFlag();
3.硬件电路
由于WWDG是STM32内部资源,因此本硬件电路非常简单,只有D1、D2指示灯连接,D1指示灯用来提示系统是否被复位,D2指示灯用来作为喂狗提示,每进入中断喂狗D2指示灯状态翻转一次。
4.编写窗口看门狗控制程序
本实验所要实现的功能是:
用D1指示灯的先亮后灭,表示系统重启了,系统每次重启时D1指示灯点亮500ms时间,然后熄灭。
用D2指示灯不断翻转闪烁来表示正在喂狗。
程序框架如下:
(1)初始化WWDG(使能WWDG时钟,设置窗口及分频值,使能中断等)
(2)编写窗口看门狗中断函数
(3)编写主函数
main.c
#include "system.h"
#include "led.h"
#include "SysTick.h"
#include "wwdg.h"
int main()
{
SysTick_Init(72);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组
LED_Init();
led1=0;
delay_ms(500);//LED1 如果没有及时喂狗,LED就会熄灭500ms,提示系统重启了
WWDG_Init();
while(1)
{
led1=1;
}
}
wwdg.c
#include "wwdg.h"
#include "led.h"
#include "SysTick.h"
void WWDG_Init()
{
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);
WWDG_SetPrescaler(WWDG_Prescaler_8);
WWDG_SetWindowValue(0x5f);//只有在0x5F到0x40之间喂狗,系统才不会复位,不会重启
//设置中断优先级,使能定时器中断通道
NVIC_InitStructure.NVIC_IRQChannel= WWDG_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
WWDG_Enable(0x7f);//设定计数器的初值,这里设的是最大值0x7f
WWDG_ClearFlag();
WWDG_EnableIT();
}
void WWDG_IRQHandler(void)
{
//delay_ms(1);//用来检查不喂狗时的情况
WWDG_SetCounter(0x7f);
WWDG_ClearFlag();
led2=!led2;
}
程序烧写到开发板上运行后是正常的,实验成功!