OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 30|回复: 0

《STM32H7R7开发指南 V1.1 》第十八章 窗口门狗(WWDG)实验

[复制链接]

1300

主题

1316

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
5567
金钱
5567
注册时间
2019-5-8
在线时间
1476 小时
发表于 4 小时前 | 显示全部楼层 |阅读模式
本帖最后由 正点原子运营 于 2026-4-9 09:28 编辑

第十八章 窗口门狗(WWDG)实验

1)实验平台:正点原子STM32H7R7开发板

2)章节摘自【正点原子】STM32H7R7开发指南 V1.1

3)购买链接: https://detail.tmall.com/item.htm?id=820823382459

4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/stm32/zdyz_stm32h7rx.html

5)正点原子官方B站:https://space.bilibili.com/394620890

6)正点原子STM32开发板技术交流群:756580169


2.jpg

3.png

本章我们学习如何使用STM32H7R7的另外一个看门狗,窗口看门狗(以下简称WWDG)。我们将使用窗口看门狗的中断功能来喂狗。
本章分为如下几个小节:
18.1 WWDG简介
18.2 硬件设计
18.3 程序设计
18.4 下载验证


18.1 WWDG简介
窗口看门狗(WWDG)通常被用来监测由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。窗口看门狗跟独立看门狗一样,也是一个递减计数器,不同的是它们的复位条件不一样。窗口看门狗产生复位信号有两个条件:
1)当递减计数器的数值从0x40减到0x3F时(T6位跳变到0)。
2)当喂狗的时候如果计数器的值大于W[6:0]时,此数值在WWDG_CFR寄存器定义。
上述的两个条件详细解释是,当计数器的值减到0X40时还不喂狗的话,到下一个计数就会产生复位,这个值称为窗口的下限值,是固定的值,不能改变。这个跟独立看门狗类似,不同的是窗口看门狗的计数器的值在减到某一个数之前喂狗的话也会产生复位,这个值叫窗口的上限,上限值W[6:0]由用户设置。窗口看门狗计数器的上限值和下限值就是窗口的含义,喂狗也必须在窗口之内,否则就会复位。


18.1.1 WWDG框图
下面先来学习WWDG框图,通过学习WWDG框图会有一个很好的整体掌握,同时对之后的编程也会有一个清晰的思路。

第十八章 窗口门狗593.png
图18.1.1.1 WWDG框图

从WWDG框图整体认知就是,WWDG有一个输入(时钟pclk),经过一个除4096的分频器,再经过一个分频系数可选(1、2、4、8…128)的可编程预分频器提供时钟给一个7位递减计数器,这里有两个输出信号。具体如下表:

1.png
表18.1.1.1 WWDG内部输入/输出信号

这里需要注意的就是pclk时钟是由PPRE1提供,由前面十一章的内容知道,我们的例程在系统时钟设置函数中把PPRE1的时钟频率设置为150Mhz。
结合寄存器分析窗口看门狗的上限值和下限值。W[6:0] 是WWDG_CFR寄存器的低7位,用于与递减计数器比较的窗口值,也就是我们说的上限值,由用户设置。0x40就是下限值,递减计数器达到这个值就会产生复位。T6位就是WWDG_CR寄存器的位6,即递减计数器T[6:0]的最高位。他们的关系可以用图18.1.1.2来说明:


第十八章 窗口门狗1090.png
图18.1.1.2 窗口看门狗工作示意图

图18.1.1.2可以看出,递减计数器的值递减过程中,当T[6:0]>W[6:0]是不允许刷新T[6:0]的值,即不允许喂狗,否则会产生复位。只有在W[6:0]<T[6:0]< 0x3F这个时间可以喂狗,这就是喂狗的窗口时间。当T[6:0]=0x3F,即T6位为0这一刻,也会产生复位。
上限值W[6:0]是由用户自己设置,但是一定要确保大于0X40,否则就不存在上图的窗口了,下限值0x40是固定的,不可修改。
知道了窗口看门狗的工作原理,下面学习如何计算窗口看门狗的超时公式:
Twwdg=(4096×2^WDGTB[2:0]×(T[5:0]+1)) /Fppre1
其中:
        Twwdg:WWDG超时时间(单位为ms)
        Fppre1:APB1的时钟频率(单位为Mhz)
        WDGTB[2:0]:WWDG的预分频系数,0~7
        T[5:0]:窗口看门狗的计数器低6位
根据以上公式,假设Fppre1=150Mhz,那么可以得到最小—最大超时时间表如下表所示:


2.png
表18.1.1.2 150M时钟下窗口看门狗的最小最大超时表

18.1.2 WWDG寄存器
WWDG只有3个寄存器,具体如下:
控制寄存器(WWDG_CR)
窗口看门狗的控制寄存器描述如图18.1.2.1所示:


第十八章 窗口门狗1822.png
图18.1.2.1 WWDG_CR寄存器

该寄存器只有低八位有效,其中T[6:0]用来存储看门狗的计数器的值,随时更新的,每隔(4096×2^ WDGTB[2:0])PCLK个周期减1。当该计数器的值从0X40变为0X3F的时候,将产生看门狗复位。
WDGA位则是看门狗的激活位,该位由软件置1,启动看门狗,并且一定要注意的是该位一旦设置,就只能在硬件复位后才能清零了。
配置寄存器(WWDG_CFR)
配置寄存器描述如图18.1.2.2所示:


第十八章 窗口门狗2047.png
图18.1.2.2 WWDG_CFR寄存器

该寄存器中的EWI位是提前唤醒中断,如果该位置1,当递减计数器等于0x40时产生提前唤醒中断,我们就可以及时喂狗以避免WWDG复位。因此,我们一般都会用该位来设置中断,当窗口看门狗的计数器值减到0X40的时候,如果该位设置,并开启了中断,则会产生中断,我们可以在中断里面向WWDG_CR重新写入计数器的值,来达到喂狗的目的。注意这里在进入中断后,必须在不大于1个窗口看门狗计数周期的时间(在ppre1频率为150M且WDGTB[2:0]为0的条件下,该时间为27.3us)内重新写WWDG_CR,否则,看门狗将产生复位!
状态寄存器(WWDG_SR)
该寄存器用来记录当前是否有提前唤醒的标志。该寄存器仅有位0有效,其他都是保留位。当计数器值达到0x40时,此位由硬件置1。它必须通过软件写0来清除。对此位写1无效。即使中断未被使能,在计数器的值达到0X40的时候,此位也会被置1。 状态寄存器描述如图18.1.2.3所示:


第十八章 窗口门狗2484.png
图18.1.2.3 WWDG_SR寄存器

18.2 硬件设计

1. 例程功能
LED1用来指示中断喂狗,每次中断喂狗翻转一次。

2. 硬件资源
1)LED灯
       LED1 – PD14
2)窗口看门狗

3. 原理图
窗口看门狗属于STM32H7R7的内部资源,只需要软件设置好即可正常工作。我们通过LED1来指示窗口看门狗的喂狗情况。


18.3 程序设计

18.3.1 WWDG的HAL库驱动
WWDG在HAL库中的驱动代码在stm32h7rsxx_hal_wwdg.c文件(及其头文件)中。
1. HAL_WWDG_Init函数
WWDG的初始化函数,其声明如下:
  1. HAL_StatusTypeDef HAL_WWDG_Init(WWDG_HandleTypeDef *hwwdg);
复制代码
函数描述:
用于初始化WWDG。
函数形参:
形参1是WWDG句柄,WWDG_HandleTypeDef结构体类型,其定义如下:

  1. typedef struct
  2. {
  3.   WWDG_TypeDef               *Instance; /* WWDG寄存器基地址 */
  4.   WWDG_InitTypeDef           Init;      /* WWDG初始化参数 */
  5. }WWDG_HandleTypeDef;
复制代码
1)Instance:指向WWDG寄存器基地址。
2)Init:WWDG初始化结构体,用于配置计数器的相关参数。
WWDG_InitTypeDef这个结构体类型定义如下:

  1. typedef struct
  2. {
  3.   uint32_t Prescaler;          /* 预分频系数 */
  4.   uint32_t Window;             /* 窗口值 */
  5.   uint32_t Counter;            /* 计数器值 */
  6.   uint32_t EWIMode;            /* 提前唤醒中断使能 */
  7. } WWDG_InitTypeDef;
复制代码
1)Prescaler:预分频系数,WWDG_PRESCALER_1到WWDG_PRESCALER_128。
2)Window:窗口值,即上限值。
3)Counter:计数器值,用于保存要设置计数器的值。
4)EWIMode:提前唤醒中断使能。
函数返回值:
HAL_StatusTypeDef枚举类型的值。
2. HAL_WWDG_Refresh函数
HAL_WWDG_Refresh函数是窗口看门狗的喂狗函数。其声明如下:

  1. HAL_StatusTypeDef HAL_WWDG_Refresh(WWDG_HandleTypeDef *hwwdg);
复制代码
函数描述:
该函数实际就是往CR寄存器重写Counter这个预先保存的计数器值。
函数形参:
形参1是WWDG_HandleTypeDef结构体指针类型的WWDG句柄。
函数返回值:
HAL_StatusTypeDef枚举类型的值。
窗口看门狗配置步骤
1)使能WWDG时钟
WWDG不同于IWDG,IWDG有自己独立的32Khz时钟。而WWDG使用的是PPRE1的时钟,需要先使能时钟。方法是:

  1. __HAL_RCC_WWDG_CLK_ENABLE();
复制代码
2)设置窗口值,分频数和计数器初始值
在HAL库中,这三个值都是通过函数HAL_WWDG_Init来设置的,详见本例程源码。
3)开启WWDG
通过设置WWDG_CR寄存器的WDGA(bit7)位为1来实现开启窗口看门狗,同样是在HAL_WWDG_Init函数里面实现。
4)使能中断通道并配置优先级(如果开启了WWDG中断)
WWDG的中断也是通过:HAL_NVIC_EnableIRQ函数使能,通过HAL_NVIC_SetPriority函数设置优先级。
HAL库同样为看门狗提供了MSP回调函数HAL_WWDG_MspInit,一般情况下,步骤1和步骤4的步骤,我们均放在该回调函数中。
5)编写中断服务函数
在最后,还是要编写窗口看门狗的中断服务函数,通过该函数来喂狗,喂狗要快,否则当窗口看门狗计数器值减到0X3F的时候,就会引起软复位了。在中断服务函数里面也要将状态寄存器的EWIF位清空。
窗口看门狗中断服务函数为:WWDG_IRQHandler,喂狗函数为:HAL_WWDG_Refresh。
6)重写窗口看门狗唤醒中断处理回调函数HAL_WWDG_EarlyWakeupCallback
HAL库定义了一个WWDG中断处理共用函数HAL_WWDG_IRQHandler,我们在WWDG中断服务函数中会调用该函数。同时该函数会调用回调函数HAL_WWDG_EarlyWakeupCallback,提前唤醒中断逻辑(喂狗、闪灯)我们写在回调函数HAL_WWDG_EarlyWakeupCallback中。


18.3.2 程序解析

1. WWDG驱动代码
这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。窗口看门狗(WWDG)驱动源码包括两个文件:wdg.c和wdg.h。
wdg.h头文件只有函数的声明,就不解释了。下面我们直接解析wdg.c的程序,先看WWDG的初始化函数,其定义如下:

  1. /**
  2. * @brief   初始化窗口看门狗
  3. * [url=home.php?mod=space&uid=271674]@param[/url]   counter: 计数器值
  4. * @param   window: 窗口值
  5. * @param   prescaler: 预分频器系数
  6. * @arg     WWDG_PRESCALER_1  : 1分频
  7. * @arg     WWDG_PRESCALER_2  : 2分频
  8. * @arg     WWDG_PRESCALER_4  : 4分频
  9. * @arg     WWDG_PRESCALER_8  : 8分频
  10. * @arg     WWDG_PRESCALER_16 : 16分频
  11. * @arg     WWDG_PRESCALER_32 : 32分频
  12. * @arg     WWDG_PRESCALER_64 : 64分频
  13. * @arg     WWDG_PRESCALER_128: 128分频
  14. * @retval  无
  15. */
  16. void wwdg_init(uint32_t counter, uint32_t window, uint32_t prescaler)
  17. {
  18.     g_wwdg_handler.Instance = WWDG;
  19.     g_wwdg_handler.Init.Prescaler = prescaler;
  20.     g_wwdg_handler.Init.Window = window;
  21.     g_wwdg_handler.Init.Counter = counter;
  22.     g_wwdg_handler.Init.EWIMode = WWDG_EWI_ENABLE;
  23.     HAL_WWDG_Init(&g_wwdg_handler);
  24. }
复制代码
wwdg_init是独立看门狗初始化函数,主要设置预分频数、窗口值和计数器的值,以及选择是否使能窗口看门狗提前唤醒中断。
因为用到中断,我们用HAL_WWDG_MspInit函数来编写窗口看门狗中断的初始化代码。当然大家也可以HAL_WWDG_MspInit函数的代码放到wwdg_init函数里面。这个初始化框架就是HAL库的特点。

  1. /**
  2. * @brief       WWDG底层驱动,时钟配置,中断配置
  3.                 此函数会被HAL_WWDG_Init()调用
  4. * @param       hwwdg:窗口看门狗句柄
  5. * @retval      无
  6. */
  7. void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwwdg)
  8. {
  9.     /* 使能窗口看门狗时钟 */
  10.     __HAL_RCC_WWDG_CLK_ENABLE();
  11.    
  12.     /* 配置中断优先级并使能中断 */
  13.     HAL_NVIC_SetPriority(WWDG_IRQn, 0, 0);
  14.     HAL_NVIC_EnableIRQ(WWDG_IRQn);
  15. }
复制代码
HAL_WWDG_MspInit函数会被HAL_WWDG_Init函数调用。该函数使能窗口看门狗的时钟,并设置窗口看门狗中断的抢占优先级为0,响应优先级为0。
  1. /**
  2. * @brief       窗口看门狗中断服务程序
  3. * @param       无
  4. * @retval      无
  5. */
  6. void WWDG_IRQHandler(void)
  7. {
  8.     HAL_WWDG_IRQHandler(&g_wwdg_handler);
  9. }
复制代码
WWDG_IRQHandler函数是窗口看门狗中断服务函数,而这个函数实际上就是调用HAL库的中断处理函数HAL_WWDG_IRQHandler。逻辑程序在下面的这个回调函数中:
  1. /**
  2. * @brief       窗口看门狗喂狗提醒中断服务回调函数
  3. * @param       wwdg句柄
  4. * [url=home.php?mod=space&uid=60778]@note[/url]        此函数会被HAL_WWDG_IRQHandler()调用
  5. * @retval      无
  6. */
  7. void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef* hwwdg)
  8. {
  9.     HAL_WWDG_Refresh(&g_wwdg_handler); /* 更新窗口看门狗值 */
  10.     LED1_TOGGLE();                     /* LED1闪烁 */
  11. }
复制代码
在回调函数内部调用HAL_WWDG_Refresh函数喂狗,并翻转LED1。

2. main.c代码
在main.c里面编写如下代码:

  1. int main(void)
  2. {
  3.     uint8_t key;
  4.    
  5.     sys_mpu_config();                           /* 配置MPU */
  6.     sys_cache_enable();                         /* 使能Cache */
  7.     HAL_Init();                                 /* 初始化HAL库 */
  8.     sys_stm32_clock_init(300, 6, 2);            /* 配置时钟,600MHz */
  9.     delay_init(600);                            /* 初始化延时 */
  10.     usart_init(115200);                         /* 初始化串口 */
  11.     led_init();                                 /* 初始化LED */
  12.     wwdg_init(0x7F, 0x5F, WWDG_PRESCALER_16);   /* 初始化WWDG */
  13.    
  14.     while (1)
  15.     {
  16.         
  17.     }
  18. }
复制代码
在main函数里,先初始化系统和用户的外设代码,调用wwdg_init(0X7F, 0X5F, WWDG_PRESCALER_16)这个语句,就设置计数器值为7f,窗口寄存器为5f,分频数为16,然后可由前面的公式得到Twwdg=4096×16×64/150000=27.96ms,即超时时间就是27.96ms。27.96ms进中断喂狗一次,并翻转LED1。

18.4 下载验证
下载代码后,可以看到LED1开始不停的闪烁。每秒钟闪烁28次左右,说明程序在中断不停的喂狗,和我们预期的一致。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

如发现本坛存在违规或侵权内容, 请点击这里发送邮件举报 (或致电020-38271790)。请提供侵权说明和联系方式。我们将及时审核依法处理,感谢配合。

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2026-4-9 13:46

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表