目录
一 窗口看门狗简介
如图所示,T[6:0]是WWDG_CR的低七位,W[6:0]是WWDG->CFR的低七位。T[6:0]是窗口看门狗的计数器,W[6:0]是窗口看门狗的上窗口(自己设定的,但是必须大于0x40),下窗口是固定的0x40,窗口看门狗的计数器在上窗口值之外被刷新或者低于下窗口值都会产生复位。
超时公式:Twwdg=(4096×2^WDGTB×(T[5:0]+1)) /Fpclk1;
超时时间ms = (4096 * 2的预分频系数次方 * (计数器低6位+1))/ APB1的时钟频率
假设APB1时钟频率是36Mhz,那么最小-最大超时时间表如图所示:
然后还是介绍3个寄存器:
控制寄存器WWDG_CR
32位寄存器(只有低8位有效)T[6:0]用来存储看门狗的计数器值, 随时更新的,每个窗口看门狗计数周期(4096×2^ WDGTB)减 1。当该计数器的值从 0X40 变为 0X3F 的时候,将产生看门狗复位。
上面画圈的WGPA位是看门狗的激活位,由软件置1,用来启动看门狗,该位一旦设置,就只能在硬件复位后才能清零了。
配置寄存器WWDG_CFR
上面画圈的EWI是提前唤醒中断,在产生复位的前一段时间提醒我们要进行喂狗了,否则将复位,一般用这一位设置中断,当计数器值减到0x40的时候,产生中断,在中断里向WWDG_CR重新写入计数器的值(这里必须在不大于一个计数周期的时间内重新写入,在PLCK1频率为36M且WDGTB为0的条件下,该时间是113us),来达到喂狗的目的,否则将复位。
状态寄存器WWDG_SR
用来记录当前是否有提前唤醒的标志,这个寄存器只有位0有效,其他都是保留位,当计数值达到40h时,这位由硬件置1,然后软件置0来清除,软件置1无效,即使中断不使能,计数值达到0x40时,这位也会被置1。
1.使能WWDG时钟
上一节写的窗口看门狗IWDG有自己独立的40Khz时钟,不存在使能问题,而这个窗口看门狗用的是PLCK1的时钟,需要先使能时钟:
2.设置窗口值:void WWDG_SetWindowValue(uint8_t WindowValue);
设置分频数:void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);
3.开启WWDG中断并分组 WWDG_EnableIT(); //开启窗口看门狗中断
接下来是进行中断优先级配置,使用 NVIC_Init()函数即可。
4.设置计数器初始值并使能看门狗 void WWDG_Enable(uint8_t Counter);
该函数既设置了计数器初始值,同时使能了窗口看门狗。
5.编写中断服务函数
通过该函数来喂狗,喂狗要快,否则当窗口看门狗计数器值减到 0X3F 的时候,就会引起软复位了。在中断服务函数里面也要将状态寄存器的 EWIF位清空。
设计:通过 DS0 来指示 STM32 是否被复位,如果被复位了就会点亮 300ms。DS1 用来指示中断喂狗,每次中断喂狗翻转一次。
二 代码
wwdg.c
#include "wwdg.h"
#include "led.h"
u8 WWDG_CNT=0x7f;
void WWDG_Init(u8 tr,u8 wr,u32 fprer)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // WWDG 时钟使能
WWDG_SetPrescaler(fprer);设置 WWDG 预分频值
WWDG_SetWindowValue(wr);//设置窗口值
WWDG_Enable(tr); //使能看门狗 , 设置 counter .
WWDG_ClearFlag();
WWDG_NVIC_Init();//初始化窗口看门狗 NVIC
WWDG_EnableIT(); //开启窗口看门狗中断
}
void WWDG_Set_Counter(u8 cnt)//重设置 WWDG 计数器的值
{
WWDG_Enable(cnt);
}
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_Init(&NVIC_InitStructure);//NVIC 初始化
}
void WWDG_IRQHandler(void)
{
// Update WWDG counter
WWDG_SetCounter(0x7F); //当禁掉此句后,窗口看门狗将产生复位
// Clear EWI flag */
WWDG_ClearFlag(); //清除提前唤醒中断标志位
// Toggle GPIO_Led pin 7 */
LED1=!LED1;
}
main.c
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "wwdg.h"
int main(void)
{
delay_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
uart_init(9600);
LED_Init();
LED0=0;
delay_ms(300);
WWDG_Init(0X7F,0X5F,WWDG_Prescaler_8);
while(1)
{
LED0=1;
}
}
效果:可以看到 DS0 亮一下之后熄灭,紧接着 DS1 开始不停的闪烁,每秒钟闪烁 9 次左右。