完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
本帖最后由 正点原子运营官 于 2020-4-17 16:14 编辑
1)实验平台:ALIENTEK NANO STM32F411 V1开发板 2)摘自《正点原子STM32F4 开发指南(HAL 库版》关注官方微信号公众号,获取更多资料:正点原子 第十二章 窗口门狗(WWDG)实验 这一章,我们将向大家介绍如何使用 STM32F4 的另外一个看门狗,窗口看门狗(以下简 称 WWDG)。在本章中,我们将利用窗口看门狗的中断功能来喂狗,通过 DS0 和 DS1 提示程 序的运行状态。本章分为如下几个部分: 12.1 STM32F4 窗口看门狗简介 12.2 硬件设计 12.3 软件设计 12.4 下载验证 12.5 STM32CubeMX 配置 WWDG 12.1 STM32F4 窗口看门狗简介 窗口看门狗(WWDG)通常被用来监测由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。除非递减计数器的值在 T6 位(WWDG->CR 的第六位) 变成 0 前被刷新,看门狗电路在达到预置的时间周期时,会产生一个 MCU 复位。在递减计数器达到窗口配置寄存器(WWDG->CFR)数值之前,如果 7 位的递减计数器数值(在控制寄存器中) 被刷新, 那么也将产生一个 MCU 复位。这表明递减计数器需要在一个有限的时间窗口中被刷新。他们的关系可以用图 12.1.1 来说明: 图 12.1.1 窗口看门狗工作示意图 图 12.1.1 中,T[6:0]就是 WWDG_CR 的低七位,W[6:0]即是 WWDG->CFR 的低七位。T[6:0]就是窗口看门狗的计数器,而 W[6:0]则是窗口看门狗的上窗口,下窗口值是固定的(0X40)。 当窗口看门狗的计数器在上窗口值之外被刷新,或者低于下窗口值都会产生复位。 上窗口值(W[6:0])是由用户自己设定的,根据实际要求来设计窗口值,但是一定要确保窗口值大于 0X40,否则窗口就不存在了。 窗口看门狗的超时公式如下: Twwdg=(4096×2^WDGTB×(T[5:0]+1)) /Fpclk1; 其中: Twwdg:WWDG 超时时间(单位为 ms) Fpclk1:APB1 的时钟频率(单位为 Khz) WDGTB:WWDG 的预分频系数 T[5:0]:窗口看门狗的计数器低 6 位 根据上面的公式,假设 Fpclk1=30Mhz,那么可以得到最小-最大超时时间表如表 12.1.1 所示 表 12.1.1 30M 时钟下窗口看门狗的最小最大超时表接下来,我们介绍窗口看门狗的 3 个寄存器。首先介绍控制寄存器(WWDG_CR),该寄 存器的各位描述如图 12.1.2 所示:图 12.1.2 WWDG_CR 寄存器各位描述 可以看出,这里我们的 WWDG_CR 只有低八位有效,T[6:0]用来存储看门狗的计数器值, 随时更新的,每个窗口看门狗计数周期(4096×2^ WDGTB)减 1。当该计数器的值从 0X40 变 为 0X3F 的时候,将产生看门狗复位。 WDGA 位则是看门狗的激活位,该位由软件置 1,以启动看门狗,并且一定要注意的是该位一旦设置,就只能在硬件复位后才能清零了。 窗口看门狗的第二个寄存器是配置寄存器(WWDG_CFR),该寄存器的各位及其描述如 图 12.1.3 所示: 图 12.1.3 WWDG_ CFR 寄存器各位描述 该位中的 EWI 是提前唤醒中断,也就是在快要产生复位的前一段时间(T[6:0]=0X40)来 提醒我们,需要进行喂狗了,否则将复位!因此,我们一般用该位来设置中断,当窗口看门狗的计数器值减到 0X40 的时候,如果该位设置,并开启了中断,则会产生中断,我们可以在中 断里面向 WWDG_CR 重新写入计数器的值,来达到喂狗的目的。注意这里在进入中断后,必 须在不大于 1 个窗口看门狗计数周期的时间(在 PCLK1 频率为 48M 且 WDGTB 为 0 的条件下, 该时间为 95us)内重新写 WWDG_CR,否则,看门狗将产生复位! 最后我们要介绍的是状态寄存器(WWDG_SR),该寄存器用来记录当前是否有提前唤醒 的标志。该寄存器仅有位 0 有效,其他都是保留位。当计数器值达到 40h 时,此位由硬件置 1。它必须通过软件写 0 来清除。对此位写 1 无效。即使中断未被使能,在计数器的值达到 0X40 的时候,此位也会被置 1。 在介绍完了窗口看门狗的寄存器之后,我们介绍要如何启用 STM32F4 的窗口看门狗。这里我们介绍 HAL 库函数中用中断的方式来喂狗的方法,窗口看门狗 HAL 库函数相关源码和定 义分布在文件 stm32f4xx_hal_wwdg.c 文件和头文件 stm32f4xx_hal_wwdg.h 中。步骤如下: 1)使能 WWDG 时钟 WWDG 不同于 IWDG,IWDG 有自己独立的 32Khz 时钟,不存在使能问题。而 WWDG 使用的是 PCLK1 的时钟,需要先使能时钟。方法是: __HAL_RCC_WWDG_CLK_ENABLE(); //使能窗口看门狗时钟 2)设置窗口值和分频数和计数器初始值 在 HAL 库中,这三个值都是通过函数 HAL_WWDG_Init 来设置的。该函数声明如下: HAL_StatusTypeDef HAL_WWDG_Init(WWDG_HandleTypeDef *hwwdg); 该函数只有一个入口参数,就是 WWDG_HandleTypeDef 结构体类型指针变量。这里我们 来看看 WWDG_HandleTypeDef 结构体定义: typedef struct { WWDG_TypeDef *Instance; WWDG_InitTypeDef Init; }WWDG_HandleTypeDef; 该结构体和前面我们讲解 IWDG_HandleTypeDef 类似,这里我们就主要讲解成员变量 Init, 它是 WWDG_InitTypeDef 结构体类型,该结构体定义如下: typedef struct { uint32_t Prescaler; //预分频系数 uint32_t Window; //窗口值 uint32_t Counter; //计数器值 uint32_t EWIMode ; //中断使能/失能设置 }WWDG_InitTypeDef; 该结构体有 4 个成员变量,分别用来设置设置 WWDG 的预分频系数,窗口值、计数值, 以及中断使能设置。函数 HAL_WWDG_Init 的使用范例如下: WWDG_HandleTypeDef WWDG_Handler; //窗口看门狗句柄 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;//使能 EWI 模式 HAL_WWDG_Init(&WWDG_Handler); //初始化 WWDG HAL_WWDG_Init 除了配置参数和启动 WWDG 中断,还同时启动 WWDG。 3)使能中断通道并配置优先级(如果开启了 WWDG 中断) 这一步相信大家已经非常熟悉了,我们这里仅仅列出两行实现代码,如下: HAL_NVIC_SetPriority(WWDG_IRQn,2,3); //抢占优先级 2,子优先级为 3 HAL_NVIC_EnableIRQ(WWDG_IRQn); //使能窗口看门狗中断 这 里 大 家 要 注 意 , 跟 串 口 一 样 , HAL 库 同 样 为 看 门 狗 提 供 了 MSP 回 调 函 数 HAL_WWDG_MspInit,一般情况下,步骤 1 和步骤 3 的步骤,是与 MCU 相关的,我们均放在 该回调函数中。关于 MSP 回调函数的使用方法,前面多次讲解,这里我们就不累赘了。 4) 编写中断服务函数 在最后,还是要编写窗口看门狗的中断服务函数,通过该函数来喂狗,喂狗要快,否则当 窗口看门狗计数器值减到 0X3F 的时候,就会引起软复位了。在中断服务函数里面也要将状态 寄存器的 EWIF 位清空。 窗口看门狗中断服务函数为: void WWDG_IRQHandler(void); 在 HAL 库中,喂狗函数为: HAL_StatusTypeDef HAL_WWDG_Refresh(WWDG_HandleTypeDef *hwwdg); WWDG 的喂狗操作实际就是往 CR 寄存器重写计数器值,这里计数值就是我们 WWDG_Handler 窗口看门狗句柄的 WWDG_Handler.Init.Counter 的计数值。 5) 重写窗口看门狗唤醒中断处理回调函数 HAL_WWDG_EarlyWakeupCallback 跟串口和外部中断一样,首先,HAL 库定义一个中断处理共用函数 HAL_WWDG_IRQHandler,我们在 WWDG 中断服务函数中会调用该函数。同时该函数内 部会经过一系列判断,最后调用回调函数 HAL_WWDG_WakepCallback,所以提前唤醒中断逻 辑我们一般放在回调函数 HAL_WWDG_WakeupCallback 中。回调函数声明为: void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef* hwwdg); 完成了以上 5 个步骤之后,我们就可以使用 STM32 的窗口看门狗了。这一章的实验,我们将通过 DS0 来指示 STM32 是否被复位了,如果被复位了就会点亮 300ms。DS1 用来指示中断喂狗,每次中断喂狗翻转一次。 12.2 硬件设计 本实验用到的硬件资源有: 1) 指示灯 DS0 和 DS1 2) 窗口看门狗 其中指示灯前面介绍过了,窗口看门狗属于 STM32F4 的内部资源,只需要软件设置好即可正常工作。我们通过 DS0 和 DS1 来指示 STM32F4 的复位情况和窗口看门狗的喂狗情况。 12.3 软件设计 打开我们的窗口看门狗实验可以看到,相对于独立看门狗,我们只增加了窗口看门狗相关 的库函数支持文件 stm32f4xx_hal_wwdg.c 和 stm32f4xx_hal_wwdg.h,同时新建 wwdg.c 和对应 的头文件 wwdg.h 用来编写窗口看门狗相关的函数代码。 接下来我们看看 wwdg.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). 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;//使能 EWI 模式 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);//更新窗口看门狗值 (会调用 WWDG 初始化的计数值,0X7F) LED1=!LED1; } wwdg.c 文件一共包含四个函数。第一个函数 WWDG_Init()实现的是前面讲解的步骤 2,主 要作用是调用函数 HAL_WWDG_Init 设置 WWDG 的分频系数,窗口值、计数值并且设置中断, 开启了看门狗。包括看门狗计数器的值和看门狗比较值等。第二个函数 HAL_WWDG_MspInit 是 WWDG 的 MSP 回调函数,该函数主要作用是使能 WWDG 时钟,以及设置 NVIC,实现的 是前面讲解的步骤 1 和 3。第三个函数 WWDG_IRQHandler 也就是中断服务函数,该函数在前 面 步 骤 4 有 讲 解 , 一 般 情 况 下 , 在 该 函 数 内 部 会 调 用 中 断 共 用 处 理 函 数 HAL_WWDG_IRQHandler。第四个函数 HAL_WWDF_WakeupCallback 是提前唤醒中断回调函数,该函数内部我们主要编写了喂狗操作,以及 LED1 翻转。在后续的中断服务函数里面,就 又通过 HAL_WWDG_Refresh 函数把该数值放会到 WWDG_CR 上。 wwdg.h 文件内容比较简单,这里我们就不做过多讲解。 在完成了以上部分之后,我们就回到主函数,代码如下: int main(void) { HAL_Init(); //初始化 HAL 库 Stm32_Clock_Init(96,4,2,4); //设置时钟,96Mhz delay_init(96); //初始化延时函数 uart_init(115200); //初始化串口 115200 LED_Init(); //初始化 LED LED0=0; //点亮 LED0 delay_ms(300); //延时 300ms 再初始化看门狗,LED0 的变化"可见" WWDG_Init(0X7F,0X5F,WWDG_PRESCALER_8); //计数器值为 7F, 窗口寄存器为 5F,分频数为 8 while(1) { LED0=1; //熄灭 LED 灯 } } 该函数通过 LED0(DS0)来指示是否正在初始化。而 LED1(DS1)用来指示是否发生了中断。 我们先让 LED0 亮 300ms,然后关闭以用于判断是否有复位发生了。在初始化 WWDG 之后,我们回到死循环,关闭 LED1,并等待看门狗中断的触发/复位。 在编译完成之后,我们就可以下载这个程序到 NANO STM32F4 开发板上,看看结果是不是和我们设计的一样。 12.4 下载验证 将代码下载到 NANO STM32F4 后,可以看到 DS0 亮一下之后熄灭,紧接着 DS1 开始不停的闪烁。每秒钟闪烁 5 次左右,和我们预期的一致,说明我们的实验是成功的。 12.5 STM32CubeMX 配置 WWDG 上一讲我们讲解了使用 STM32CubeMX 配置 IWDG 步骤,而 WWDG 配置过程和 IWDG 配置过程基本是一模一样,这里我们就直接列出配置图,对配置过程不做过多讲解。首先进入 Pinout 选项界面,使能 WWDG,如下图 12.5.1: 图 12.5.1 使能 WWDG 接下来配置 WWDG 的四个参数,进入 Configuration->Parameter Setting 界面,如下图: 图 12.5.2 WWDG Configuration 配置界面 顾名思义,第一个参数是配置分频系数,这里我们配置为 8,第二个参数是配置窗口值, 第三个参数是配置计数器初始值,第四个参数是配置看门狗使能。配置完之后,因为我们开启 提前唤醒中断,所以这里我们要使能并配置 NVIC 中断优先级。进入 Configuration->NVIC 界面, 参考第十章配置方法配置 WWDG 中断即可。配置方法如下图 12.5.3 所示: 图 12.5.3 配置 WWDG 中断 配置完成之后直接生成工程源码。在 main.c 文件中生成的 MX_WWDG_Init 函数和本实验 的 WWDG_Init 函数实现功能类似。在 stm32f4xx_it.c 中生成的中断服务函数和我们实验一致。 在 srm32f4xx_hal_msp.c 文件中生成的 MSP 回调函数内容核实我们实验内容一致。 |
|
相关推荐
|
|
STM32进行DMA数据转运,为什么只有A组最后一位数据被转运到B组去?
1265 浏览 2 评论
1585 浏览 3 评论
1206 浏览 0 评论
嵌入式开发 Win11安装ST-Link 提示 设备描述符请求失败 怎么处理?
1339 浏览 0 评论
1632 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-8-18 06:35 , Processed in 0.465663 second(s), Total 65, Slave 48 queries .
Powered by 电子发烧友网
© 2015 www.ws-dc.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号