窗口门狗实验(WWDG)实验【学习】

使用 窗口看门狗的中断功能来喂狗, 通过 DS0和 DS1提示程序的运行状态。

11.1窗口看门狗简介

窗口看门狗(WWDG)通常被用来监测由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。除非递减计数器的值在T6位 WWDG-->CR的第六位)

变成 0前被刷新,看门狗电路在达到预置的时间周期时,会产生一个 MCU复位。

在递减计数器达到窗口 配置 寄存器 (WWDG-->CFR)数值之前,如果 7位的递减计数器数值 (在控制寄存器中 )被刷新, 那么也将产生一个 MCU复位。这表明递减计数器需要在一个有限的时间窗口中被刷新。

上窗口值 W[6:0】 是由用户自己设定的,根据实际要求来设计窗口值

窗口看门狗的超时公式如下:

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

其中

Twwdg: WWDG超时时间 (单位为 ms

Fpclk1 :APB1的时钟频率(单位为 Khz

WDGTB :WWDG的预分频系数

T[5:0]:窗口看门狗的计数器低 6位

最大超时值:因为是T[5:0],共六位,第六位变成0之前被刷新,即值为0x20,0x3f-0x20=0x1f

最小超时值:T{5:0}=0

介绍窗口看门狗的3个寄存器

1.控制寄存器 WWDG_CR

低八位有效, T[6 0]用来存储看门狗的计数器值,随时更新的,每个 窗口看门狗计数 周期( 4096 × 2^ WDGTB)减 1。当该计数器的值从 0X40变为 0X3F的时候,将产生看门狗复位。

WDGA位则是看门狗的激活位,该位由软件置 1,以启动看门狗,并且一定要注意的是该位一旦设置,就只能在硬件复位后才能清零了。

2.配置寄存器 WWDG_CFR

该位中的EWI是提前唤醒中断,也就是在快要产生复位的前一段时间 T[6:0]=0X40 来提醒我们,需要进行喂狗了,否则将复位!

因此,我们一般用该位来设置中断,当窗口看门狗的计数器值减到 0X40的时候,如果该位设置,并开启了中断,则会产生中断,我们可以在中断里面 向 WWDG_CR重新写入计数器的值,来达到喂狗的目的。

注意这里在进入中断后, 必须 在不大于 1个窗口看门狗计数周期 的时间( 在 PCLK1频率 为 36M且 WDGTB为 0的 条件下该时间为 113us)内重新写 WWDG_CR,否则,看门狗将产 生复位!

3.状态寄存器 WWDG_SR

该寄存器用来记录当前是否有提前唤醒的标志。该寄存器仅有位 0有效,其他都是保留位。当计数器值达到40h时,此位由硬件置 1。它必须通过软件写 0来清除。对此位写 1无效。 即使 中断未被使能, 在计数器的值达到 0X40,此位也会被置1

如何启用窗口看门狗

1.使能WWDG时钟(wwdg无独立时钟)

__HAL_RCC_WWDG_CLK_ENABLE(); //使能窗口看门狗时钟

2.设置窗口值,分频数和计数器初始值

函数 HAL_WWDG_Init来设置的。该函数声明如下:

HAL_StatusTypeDef HAL_WWDG_Init(WWDG_HandleTypeDef *hwwdg);
typedef struct

{

WWDG_TypeDef *Instance;

WWDG_InitTypeDef Init;

}

WWDG_HandleTypeDef;
typedef struct

{

uint32_t Prescaler; //预分频系数

uint32_t Window; //窗口值

uint32_t Counter; //计数器值

uint32_t EWIMode ; //是否启用 WWDG早期唤醒中断

}

WWDG_InitTypeDef;
函数 HAL_WWDG_Init的使用范例如下:

WWDG_HandleTypeDef WWDG_Handler; //窗口看门狗句柄

WWDG_Handler.Instance=WWDG; //窗口看门狗

WWDG_Handler.Init.Prescaler=WWDG_PRESCALER_8; //设置分频系数为 8 WWDG_Handler.Init.Window=0X5F; //设置窗口值 0X5F

WWDG_Handler.Init.Counter=0x7F; //设置计数器值 0x7F

HAL_WWDG_Init(&WWDG_Handler); //初始化 WWDG

3.使能中断通道并配置优先级(如果开启了 WWDG中断)

HAL_NVIC_SetPriority(WWDG_IRQn,2,3); //抢占优先级 2,子优先级为 3 HAL_NVIC_EnableIRQ(WWDG_IRQn); //使能窗口看门狗中断

4.编写中断服务函数

在最后,还是要编写窗口看门狗的中断服务函数,通过该函数来喂狗,喂狗要快,否则当

窗口看门狗计数器值减到 0X3F的时候,就会引起软复位了。在中断服务函数里面也要将状态

寄存器的 EWIF位清空。

窗口看门狗中断服务函数为:

void WWDG_IRQHandler(void);

在HAL库中,喂狗函数为:

HAL_StatusTypeDef HAL_WWDG_Refresh(WWDG_HandleTypeDef *hwwdg);

WWDG的喂狗操作实际就是往 CR寄存器重写计数器值。

5.重写窗口看门狗唤醒中断处理回调函数

跟串口和外部中断 一样, HAL库定义了一个中断处理共用函数HAL_WWDG_IRQHandler,我们在 WWDG中断服务函数中会调用该函数。同时该函数内部,会经过一系列判断,最后调用回调函数 HAL_WWDG_WakeupCallback,所以提前唤醒中断逻辑

我们一般些在回调函数 HAL_WWDG_WakeupCallback中。 回调函数声明为:

void HAL_WWDG_EarlyWakeupCallback (WWDG_HandleTypeDef* hwwdg);

完成了以上5个步骤之后,我们就可以使用 STM32F1的窗口看门狗了。这一 章 的实验,

我们将通过 DS0来指示 STM32F1是否被复位了,如果被复位了就会点亮 300ms。 DS1用来指

示中断喂狗,每次中断喂狗翻转一次。

11.2硬件设计

本实验用到的硬件资源有:

1) 指示灯 DS0和 DS1

2) 窗口看门狗

其中指示灯前面介绍过了,窗口看门狗属于STM32的内部资源,只需要软件设置好即可

正常工作。我们通过 DS0和 DS1来指示 STM32的复位情况和窗口看门狗的喂狗情况。

11.3软件设计

这里,我们在之前的IWDG看门狗实例内增添部分代码来实现

首先打开上次的工程,然后在 wdg.c加入如下代码(之前代码保留):

WWDG_HandleTypeDef WWDG_Handler; //窗口看门狗句柄

//保存 WWDG计数器的设置值,默认为最大

//u8 WWDG_CNT=0X7F; //初始化窗口看门狗

//tr :T[6:0],计数器值

//wr :W[6:0],窗口值

//fprer:分频系数( WDGTB)),仅最低 2位有效

//Fwwdg=PCLK1/(4096*2^fprer). 一般 PCLK1=42Mhz
void WWDG_Init(u8 tr,u8 wr,u32 fprer)

{

WWDG_Handler.Instance=WWDG;

WWDG_Handler.Init.Prescaler=fprer; //设置分频系数

WWDG_Handler.Init.Window=wr; //设置窗口值

WWDG_Handler.Init.Counter=tr; //设置计数器值

WWDG_Handler.Init.EWIMode=WWDG_EWI_ENABLE; //使能窗口看门狗提前唤醒中断

HAL_WWDG_Init(&WWDG_Handler); //初始化 WWDG

}
//WWDG底层驱动,时钟配置,中断配置

//此函数会被 HAL_WWDG_Init()调用

//hwwdg:窗口看门狗句柄

void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwwdg)

{

__HAL_RCC_WWDG_CLK_ENABLE(); //使能窗口看门狗时钟

HAL_NVIC_SetPriority(WWDG_IRQn,2,3); //抢占优先级 2,子优先级为 3 HAL_NVIC_EnableIRQ(WWDG_IRQn); //使能窗口看门狗中断

}
//窗口看门狗中断服务函数

void WWDG_IRQHandler(void)

{

HAL_WWDG_IRQHandler(&WWDG_Handler);

//调用 WWDG共用中断处理函数

} //中断服务函数处理过程

//此函数会被 HAL_WWDG_IRQHandler()调用

void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef* hwwdg)

{

HAL_WWDG_Refresh(&WWDG_Handler);//更新窗口看门狗值

LED1=!LED1;

}

主函数

int main(void) {

HAL_Init(); //初始化 HAL库

......//此处省略部分初始化代码

LED0=0; //点亮 LED0

delay_ms(300); //延时 300ms再初始化看门狗 ,LED0的变化 "可见 " WWDG_Init(0X7F,0X5F,WWDG_PRESCALER_8);

//计数器值为 7F,窗口寄存器为 5F,分频数为 8

while(1)

{

LED0=1; //熄灭 LED灯

}

}

11.4 下载验证

将代码下载到MiniSTM32后,可以看到 DS0亮一下之后熄灭,紧接着 DS1开始不停的闪

烁。每秒钟闪烁 8次左右,和我们预期的一致 ,说明我们的实验是成功的。

相关推荐
楠了个难13 分钟前
以太网实战AD采集上传上位机——FPGA学习笔记27
笔记·学习·fpga开发
eyuhaobanga33 分钟前
Go入门学习笔记
笔记·学习·golang
东小黑1 小时前
java方法以及与C语言对比学习
java·c语言·学习
筑梦之路1 小时前
kafka学习笔记1 —— 筑梦之路
笔记·学习·kafka
筑梦之路1 小时前
kafka学习笔记5 PLAIN认证——筑梦之路
笔记·学习·kafka
筑梦之路1 小时前
kafka学习笔记2 —— 筑梦之路
笔记·学习·kafka
Xudde.2 小时前
100条Linux命令汇总
linux·运维·笔记·学习
eyuhaobanga2 小时前
高质量编程 & 性能优化学习笔记
笔记·学习·性能优化
可可鸭~4 小时前
鸿蒙学习构建视图的基本语法(二)
android·学习·harmonyos
Icoolkj4 小时前
微服务学习-Seata 解决分布式事务
分布式·学习·微服务