完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1)实验平台:alientek 阿波罗 STM32F767 开发板
2)摘自《STM32F7 开发指南(HAL 库版)》关注官方微信号公众号,获取更多资料:正点原子 第十二章 窗口门狗(WWDG)实验 这一章,我们将向大家介绍如何使用 STM32F4 的另外一个看门狗,窗口看门狗(以下简 称 WWDG)。在本章中,我们将使用窗口看门狗的中断功能来喂狗,通过 DS0 和 DS1 提示程 序的运行状态。本章分为如下几个部分: 12.1 STM32F4 窗口看门狗简介 12.2 硬件设计 12.3 软件设计 12.4 下载验证 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=42Mhz,那么可以得到最小-最大超时时间表如表 12.1.1 所 示: 表 12.1.1 42M 时钟下窗口看门狗的最小最大超时表 接下来,我们介绍窗口看门狗的 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 频率为 42M 且 WDGTB 为 0 的条件下, 该时间为 97.52us)内重新写 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; HAL_LockTypeDef Lock; __IO HAL_WWDG_StateTypeDef State; }WWDG_HandleTypeDef;该结构体和前面我们讲解的 WWDG_HandleTypeDef 类似,这里我们就主要讲解成员变量 Init,它是 WWDG_InitTypeDef 结构体类型,该结构体定义如下: typedef struct { uint32_t Prescaler; //预分频系数 uint32_t Window; //窗口值 uint32_t Counter; //计数器值 }WWDG_InitTypeDef;该结构体有 3 三个成员变量,分别用来设置 WWDG 的预分频系数,窗口之以及计数器值。 函数 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); //初始化 WWDG3)开启 WWDG HAL 库中开启 WWDG 的函数有两个: HAL_StatusTypeDef HAL_WWDG_Start(WWDG_HandleTypeDef *hwwdg); HAL_StatusTypeDef HAL_WWDG_Start_IT(WWDG_HandleTypeDef *hwwdg); 函数 HAL_WWDG_Start 仅仅只是用来开启 WWDG,而函数 HAL_WWDG_Start_IT 除了 启动 WWDG,还同时启动 WWDG 中断。 4)使能中断通道并配置优先级(如果开启了 WWDG 中断) 这一步相信大家已经非常熟悉了,我们这里仅仅列出两行实现代码,如下: HAL_NVIC_SetPriority(WWDG_IRQn,2,3); //抢占优先级 2,子优先级为 3 HAL_NVIC_EnableIRQ(WWDG_IRQn); //使能窗口看门狗中断这里大家要注意, 跟串口一样, HAL 库 同 样 为 看 门 狗 提 供 了 MSP 回调函数 HAL_WWDG_MspInit,一般情况下,步骤 1 和步骤 4 的步骤,是与 MCU 相关的,我们均放在 该回调函数中。关于 MSP 回调函数的使用方法,前面多次讲解,这里我们就不累赘了。 5)编写中断服务函数 在最后,还是要编写窗口看门狗的中断服务函数,通过该函数来喂狗,喂狗要快,否则当 窗口看门狗计数器值减到 0X3F 的时候,就会引起软复位了。在中断服务函数里面也要将状态 寄存器的 EWIF 位清空。 窗口看门狗中断服务函数为: void WWDG_IRQHandler(void); 在 HAL 库中,喂狗函数为: HAL_StatusTypeDef HAL_WWDG_Refresh(WWDG_HandleTypeDef *hwwdg, uint32_t cnt);WWDG 的喂狗操作实际就是往 CR 寄存器重写计数器值,这里的第二个入口函数就是重写 的计数器的值。 6) 重写窗口看门狗唤醒中断处理回调函数 HAL_WWDG_WakeupCallback 跟串口和外部中断一样,首先,HAL 库定义了一个中断处理共用函数 HAL_WWDG_IRQHandler,我们在 WWDG 中断服务函数中会调用该函数。同时该函数内部, 会经过一系列判断,最后调用回调函数 HAL_WWDG_WakeupCallback,所以提前唤醒中断逻辑 我们一般些在回调函数 HAL_WWDG_WakeupCallback 中。 回调函数声明为: void HAL_WWDG_WakeupCallback(WWDG_HandleTypeDef* hwwdg);完成了以上 6 个步骤之后,我们就可以使用 STM32F4 的窗口看门狗了。这一章的实验, 我们将通过 DS0 来指示 STM32F4 是否被复位了,如果被复位了就会点亮 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; //窗口看门狗句柄 //初始化窗口看门狗 //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; }wwdg.c 文件一共包含四个函数。第一个函数 WWDG_Init()实现的是前面讲解的步骤 1 和 步骤 3,主要作用是调用函数 HAL_WWDG_Init 设置 WWDG 的分频系数,窗口值和计数器初 始值,同时还调用 HAL_WWDG_Start_IT 函数开启看门狗和使能看门狗中断。包括看门狗计数 器的值和看门狗比较值等。第二个函数 HAL_WWDG_MspInit 是 WWDG 的 MSP 回调函数,该 函数主要作用是使能 WWDG 时钟,以及设置 NVIC,实现的是前面讲解的步骤 2 和 4。第三个函数 WWDG_IRQHandler 也就是中断服务函数,该函数在前面步骤 5 有讲解,一般情况下,在 该函数内部会调用中断共用处理函数 HAL_WWDG_IRQHandler 。 第 四 个 函 数 HAL_WWDG_WakeupCallback 是提前唤醒中断回调函数,该函数内部我们主要编写了喂狗操作, 以及LED1翻转。注意到这里有个全局变量WWDG_CNT,该变量用来保存最初设置WWDG_CR 计数器的值。在后续的中断服务函数里面,就又通过 HAL_WWDG_Refresh 函数把该数值放回 到 WWDG_CR 上。 wwdg.h 头文件内容比较简单,这里我们就不做过多讲解。 在完成了以上部分之后,我们就回到主函数,代码如下: 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 灯 } }该函数通过 LED0(DS0)来指示是否正在初始化。而 LED1(DS1)用来指示是否发生了中断。 我们先让 LED0 亮 300ms,然后关闭以用于判断是否有复位发生了。在初始化 WWDG 之后, 我们回到死循环,关闭 LED1,并等待看门狗中断的触发/复位。 在编译完成之后,我们就可以下载这个程序到阿波罗 STM32F4 开发板上,看看结果是不 是和我们设计的一样。 12.4 下载验证 将代码下载到探索者 STM32F4 后,可以看到 DS0 亮一下之后熄灭,紧接着 DS1 开始不停 的闪烁。每秒钟闪烁 20 次左右,和我们预期的一致,说明我们的实验是成功的。 |
|
相关推荐
|
|
1276 浏览 1 评论
AD7686芯片不传输数据给STM32,但是手按住就会有数据。
1209 浏览 3 评论
2288 浏览 0 评论
如何解决MPU-9250与STM32通讯时,出现HAL_ERROR = 0x01U
1372 浏览 1 评论
hal库中i2c卡死在HAL_I2C_Master_Transmit
1799 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-29 13:13 , Processed in 0.585026 second(s), Total 64, Slave 46 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号