窗口门狗实验(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次左右,和我们预期的一致 ,说明我们的实验是成功的。

相关推荐
一只乔哇噻12 分钟前
java后端工程师进修ing(研一版 || day41)
java·开发语言·学习·算法
知识分享小能手25 分钟前
React学习教程,从入门到精通,React 使用属性(Props)创建组件语法知识点与案例详解(15)
前端·javascript·vue.js·学习·react.js·前端框架·vue
知识分享小能手7 小时前
React学习教程,从入门到精通, React 属性(Props)语法知识点与案例详解(14)
前端·javascript·vue.js·学习·react.js·vue·react
茯苓gao9 小时前
STM32G4 速度环开环,电流环闭环 IF模式建模
笔记·stm32·单片机·嵌入式硬件·学习
是誰萆微了承諾10 小时前
【golang学习笔记 gin 】1.2 redis 的使用
笔记·学习·golang
DKPT10 小时前
Java内存区域与内存溢出
java·开发语言·jvm·笔记·学习
aaaweiaaaaaa10 小时前
HTML和CSS学习
前端·css·学习·html
看海天一色听风起雨落11 小时前
Python学习之装饰器
开发语言·python·学习
speop12 小时前
llm的一点学习笔记
笔记·学习
非凡ghost13 小时前
FxSound:提升音频体验,让音乐更动听
前端·学习·音视频·生活·软件需求