【正点原子STM32连载】 第十九章 窗口门狗(WWDG)实验摘自【正点原子】STM32F103 战舰开发指南V1.2

news2024/11/17 21:49:51

1)实验平台:正点原子stm32f103战舰开发板V4
2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html

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

本章我们学习如何使用STM32F1的另外一个看门狗,窗口看门狗(以下简称WWDG)。我们将使用窗口看门狗的中断功能来喂狗,通过LED0和LED1提示程序的运行状态。
本章分为如下几个小节:
19.1 WWDG简介
19.2 硬件设计
19.3 程序设计
19.4 下载验证

19.1 WWDG简介

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

图19.1.1.1 WWDG逻辑框图
WWDG有一个来自RCC的PCLK1输入时钟,经过一个4096的分频器(4096分频在设计时已经设定死了,图中并没有给出来,但我们可以通过查看寄存器WWDG_CFR的WDGTB位的描述知道),再经过一个分频系数可选(1、2、4、8)的可编程预分频器提供时钟给一个7位递减计数器,这里有两个输出信号。
结合寄存器分析窗口看门狗的上限值和下限值。W[6:0] 是WWDG_CFR寄存器的低7位,用于与递减计数器T[6:0]比较的窗口值,也就是我们说的上限值,由用户设置。0x40就是下限值,递减计数器达到这个值就会产生复位。T6位就是WWDG_CR寄存器的位6,即递减计数器T[6:0]的最高位。他们的关系可以用图19.1.1.2来说明:
在这里插入图片描述

图19.1.1.2 窗口看门狗工作示意图
图19.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×(T[5:0] + 1))/ FPCLK1
其中:
TWWDG:WWDG超时时间(单位为ms)
FPCLK1: APB1的时钟频率(单位为 Khz)
2^WDGTB:是WWDG_CFR寄存器设置的预分频系数值
T[5:0]:窗口看门狗的计数器低6位的值
根据以上公式,假设 FPCLK1=36Mhz,那么可以得到最小-最大超时时间表如下表所示:
在这里插入图片描述

19.1.2 WWDG寄存器
WWDG只有3个寄存器,具体如下:
 控制寄存器(WWDG_CR)
窗口看门狗的控制寄存器描述如图19.1.2.1所示:
在这里插入图片描述

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

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

  1. 例程功能
    先点亮LED0延时300ms后,初始化窗口看门狗,进入死循环,关闭LED0。然后等待窗口看门狗中断的到来,在中断里面,喂狗,并执行LED1的翻转操作。我们将通过LED0来指示STM32F1是否被复位了,如果被复位了就会点亮300ms。LED1用来指示中断喂狗,每次中断喂狗翻转一次。
  2. 硬件资源
    1)LED灯
    LED0 – PB5
    LED1 – PE5
    2)窗口看门狗
  3. 原理图
    窗口看门狗属于STM32F103的内部资源,只需要软件设置好即可正常工作。我们通过LED0和LED1来指示STM32F103的复位情况和窗口看门狗的喂狗情况。
    19.3 程序设计
    19.3.1 WWDG的HAL库驱动
    WWDG在HAL库中的驱动代码在stm32f1xx_hal_wwdg.c文件(及其头文件)中。
  4. HAL_WWDG_Init函数
    IWDG的初始化函数,其声明如下:
    HAL_StatusTypeDef HAL_WWDG_Init(WWDG_HandleTypeDef *hwwdg);
    函数描述:
    用于初始化WWDG。
    函数形参:
    形参1是WWDG句柄,WWDG_HandleTypeDef结构体类型,其定义如下:
    typedef struct
    {
    WWDG_TypeDef Instance; / WWDG寄存器基地址 /
    WWDG_InitTypeDef Init; /
    WWDG初始化参数 */
    }WWDG_HandleTypeDef;
    1)Instance:指向WWDG寄存器基地址。
    2)Init:WWDG初始化结构体,用于配置计数器的相关参数。
    WWDG_InitTypeDef这个结构体类型定义如下:
typedef struct
{
  uint32_t Prescaler;	/* 预分频系数 */
  uint32_t Window;     	/* 窗口值 */
  uint32_t Counter;    	/* 计数器值 */
  uint32_t EWIMode;    	/* 提前唤醒中断使能 */
} WWDG_InitTypeDef;

1)Prescaler:预分频系数,WWDG_PRESCALER_1\ WWDG_PRESCALER_2\
WWDG_PRESCALER_4\ WWDG_PRESCALER_8四个值,分别表示1\2\4\8分频。
2)Window:窗口值,即上限值。
3)Counter:计数器值,用于保存要设置计数器的值。
4)EWIMode:提前唤醒中断使能。
函数返回值:
HAL_StatusTypeDef枚举类型的值。
2. HAL_WWDG_Refresh函数
HAL_WWDG_Refresh函数是窗口看门狗的喂狗函数。其声明如下:
HAL_StatusTypeDef HAL_WWDG_Refresh(WWDG_HandleTypeDef *hwwdg);
函数描述:
该函数实际就是往CR寄存器重写Counte这个预先保存的计数器值。
函数形参:
形参1是WWDG_HandleTypeDef结构体指针类型的WWDG句柄。
函数返回值:
HAL_StatusTypeDef枚举类型的值。
窗口看门狗配置步骤
1) 使能WWDG时钟
WWDG不同于IWDG,IWDG有自己独立的40Khz时钟。而WWDG使用的是PCLK1的时钟,需要先使能时钟。方法是:
__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中。
19.3.2 程序流程图
本实验利用窗口看门狗的特性,配置一个合适的窗口时间,并开启了提前唤醒中断,如果程序未在合适的时间喂狗,则会触发窗口看门狗中断。我们在进入中断后需要第一时间喂狗,否则系统将会复位,并用LED1的翻转来表示一次未及时喂狗的事件。
下面的流程图表示了main函数必要的编程步骤。
在这里插入图片描述

图19.3.2.1 窗口看门狗实验程序流程图
19.3.3 程序解析

  1. WWDG驱动代码
    这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。窗口看门狗(WWDG)驱动源码包括两个文件:wdg.c和wdg.h。
    wdg.h头文件只有函数的声明,就不解释了。下面我们直接解析wdg.c的程序,先看WWDG的初始化函数,其定义如下:
/**
 * @brief       初始化窗口看门狗
 * @param       tr: T[6:0],计数器值
 * @param       tw: W[6:0],窗口值
 * @param       fprer: 分频系数(WDGTB),范围:WWDG_PRESCALER_1~WWDG_PRESCALER_8,
*                     表示2^WDGTB分频, Fwwdg=PCLK1/(4096*2^fprer). 一般PCLK1=36Mhz
* @retval      无
 */
void wwdg_init(uint8_t tr, uint8_t wr, uint32_t 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_Init是独立看门狗初始化函数,主要设置预分频数、窗口值和计数器的值,以及选择是否使能窗口看门狗提前唤醒中断。
因为用到中断,我们用HAL_WWDG_MspInit函数来编写窗口看门狗中断的初始化代码。当然大家也可以HAL_WWDG_MspInit函数的代码放到wwdg_init函数里面。这个初始化框架就是HAL库的特点。

void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwwdg)
{
    __HAL_RCC_WWDG1_CLK_ENABLE();            /* 使能窗口看门狗时钟 */
     
    HAL_NVIC_SetPriority(WWDG_IRQn, 2, 3);	/* 抢占优先级2,子优先级为3 */
    HAL_NVIC_EnableIRQ(WWDG_IRQn);           /* 使能窗口看门狗中断 */
}
HAL_WWDG_MspInit函数会被HAL_WWDG_Init函数调用。该函数使能窗口看门狗的时钟,并设置窗口看门狗中断的抢占优先级为2,响应优先级为3/**
 * @brief       窗口看门狗中断服务程序
 * @param       无
 * @retval      无
 */
void WWDG_IRQHandler(void)
{
    HAL_WWDG_IRQHandler(&g_wwdg_handle);
}

WWDG_IRQHandler函数是窗口看门狗中断服务函数,而这个函数实际上就是调用HAL库的中断处理函数HAL_WWDG_IRQHandler。逻辑程序在下面的这个回调函数中:

void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef* hwwdg)
{
    HAL_WWDG_Refresh(&g_wwdg_handle);/* 更新窗口看门狗值 */
    LED1_TOGGLE();  				      /* LED1闪烁 */
}

在回调函数内部调用HAL_WWDG_Refresh函数喂狗,并翻转LED1。
2. main.c代码
在main.c里面编写如下代码:

int main(void)
{
    HAL_Init();                          	/* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);	/* 设置时钟, 72Mhz */
    delay_init(72);                      	/* 延时初始化 */
    usart_init(115200);                 	/* 串口初始化为115200 */
    led_init();                            	/* 初始化LED */
    LED0(0);                                	/* 点亮LED0 红灯 */
    delay_ms(300);                    /* 延时300ms再初始化看门狗,LED0的变化"可见" */
/* 计数器值为7f,窗口寄存器为5f,分频数为8 */
    wwdg_init(0X7F, 0X5F, WWDG_PRESCALER_8);
    while (1)
    {
        LED0(1);                            	/* 关闭红灯 */
    }
}

在main函数里,先初始化系统和用户的外设代码,然后先点亮LED0,延时300ms后,初始化窗口看门狗,进入死循环,关闭LED0。
调用wwdg_init(0X7F,0X5F,WWDG_PRESCALER_8)这个语句,就设置计数器值为7f,窗口寄存器为5f,分频数为8,然后可由前面的公式得到窗口上限时间Twwdg=4096×8×(0x7F-0x5F)/36MHz=29.12ms,窗口下限时间Twwdg=4096×8×(0x7F-0x3F)/36MHz=58.25ms,即喂狗的窗口区间为29.12~58.25ms。我们在程序的其它地方没有喂狗,所以程序会在58.25ms左右进入死前中断,我们在中断中喂狗一次,并翻转LED1。
19.4 下载验证
下载代码后,可以看到LED0亮了一下就熄灭,紧接着LED1开始不停的闪烁。可以接入示波器测试得每秒钟闪烁17次左右,说明程序在中断不停的喂狗,和我们预期的一致。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/563546.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unreal Niagara粒子入门2

本次学习一下如何将Niagara参数暴露给蓝图、材质编辑器。 1.暴露参数给蓝图 首先在左侧Parmeters参数面板的User Exposed处创建参数&#xff1a; 然后将参数拖入到想要绑定的粒子字段上&#xff0c;例如这里绑定给粒子发射数&#xff1a; 在调用粒子时&#xff0c;可通过Se…

【Java EE 初阶】网络编程套接字UDP

目录 1.为什么需要网络编程&#xff1f; 2.什么是网络编程&#xff1f; 3.发送端和接收端 4.请求和响应 5.客户端和服务端 6.如何进行网络编程&#xff08;Socket套接字&#xff09; 1.如何进行网络编程 2.TCP与UDP的区别 1.流套接字&#xff1a;使用传输层TCP协议 2.…

5月跳槽会有风险,不跳也会有?

今天讲讲跳槽。 说实话跳槽是为了寻求更好的发展&#xff0c;但在跳槽前我们也不能确定下家就是更好的归宿&#xff0c;这就更加需要我们审慎地去对待&#xff0c;不能盲目跳槽。 其次&#xff0c;我们离职和跳槽&#xff0c;其中的原因很大一部分是目前薪资不符合预期。 那…

Kyligence 客户案例招商银行批发业务分析平台获评金融数字化最佳实践案例

近日&#xff0c;“2023 爱分析金融数字化最佳实践案例”评选结果正式揭晓。Kyligence 携手招商银行申报的“招商银行‘火眼’批发业务分析平台”项目经过领先性、案例创新性、应用成熟度、价值创造等维度综合评选&#xff0c;最终获评“金融数字化最佳实践案例”。 招商银行“…

阿里 P9 推荐的 Spring 领域巅峰之作,直接颠覆了我对 Spring 的认知

写在前面 你第一次接触 spring 框架是在什么时候&#xff1f;相信很多人和我一样&#xff0c;第一次了解 spring 都不是做项目的时候用到&#xff0c;而是在网上看到或者是听到过一个叫做 spring 的框架&#xff0c;这个框架号称完爆之前的 structs 和 structs2&#xff0c;吸…

Jupyter设置指定的python环境

Jupyter设置指定的python环境 Jupyter在虚拟环境中启动 按理说在命令行执行如下命令 conda activate 环境名称激活一个conda环境&#xff0c;再打开jupyter&#xff0c;输入如下命令 jupyter notebook默认的python环境应该是刚刚激活的那个&#xff0c;但是我发现在window上…

git代码回滚是使用reset还是revert

时光不能回退&#xff0c;Git却允许我们改变历史。 想要让Git回退历史&#xff0c;有以下步骤&#xff1a; 使用git log命令&#xff0c;查看分支提交历史&#xff0c;确认需要回退的版本 使用git reset --hard commit_id命令&#xff0c;进行版本回退 使用git push origin命…

不需要策略模式也能避免满屏if/else

满屏if/else java 复制代码 public static void main(String[] args) { int a 1; if(a 1){ System.out.println("执行a1的逻辑"); }else if (a 2){ System.out.println("执行a2的逻辑"); }else if (a 3){ System.out.println("执行a3的逻辑&quo…

基于apache paimon实时数仓全增量一体实时入湖

用例简介 Apache Paimon&#xff08;以下简称 Paimon&#xff09;作为支持实时更新的高性能湖存储&#xff0c;本用例展示了在千万数据规模下使用全量 增量一体化同步 MySQL 订单表到 Paimon明细表、下游计算聚合及持续消费更新的能力。整体流程如下图所示&#xff0c;其中 …

R语言实践——rWCVP:世界维管植物名录的R包

rWCVP&#xff1a;世界维管植物名录的R包 介绍1. 参照github安装与简单例子1.1 安装rWCVP1.2 安装rWCVPdata1.3 github的例子 2. rWCVP原始文献阅读2.1 前言&#xff08;背景&#xff09;2.2 功能概要2.2.1 名称匹配&#xff08;wcvp_match_names(), wcvp_match_exact(), wcvp …

ChatGPT:你真的了解网络安全吗?浅谈攻击防御进行时之网络安全新定义

ChatGPT&#xff1a;你真的了解网络安全吗&#xff1f;浅谈网络安全攻击防御进行时 网络安全新定义总结 ChatGPT&#xff08;全名&#xff1a;Chat Generative Pre-trained Transformer&#xff09;&#xff0c;美国OpenAI 研发的聊天机器人程序&#xff0c;是人工智能技术驱动…

在字节跳动做了6年测试,5月无情被辞,想给划水的兄弟提个醒

先简单交代一下背景吧&#xff0c;某不知名 985 的本硕&#xff0c;17 年毕业加入字节&#xff0c;以“人员优化”的名义无情被裁员&#xff0c;之后跳槽到了有赞&#xff0c;一直从事软件测试的工作。之前没有实习经历&#xff0c;算是6年的工作经验吧。 这6年之间完成了一次…

API接口测试—详情版(拼多多根据ID取商品详情)

一、为什么要做接口测试 做接口测试的原因主要有以下几个方面&#xff1a; 1. 确保接口功能正确性&#xff1a;接口是不同软件系统或者不同模块之间的数据传输和交互的通道&#xff0c;通过接口测试能够确保不同系统或者模块之间传递的信息准确无误&#xff0c;从而保证了整个…

微信小程序点击icon实现分享功能

1.小程序分享功能实现方式 小程序分享功能有两种方式&#xff0c;监听用户点击页面内转发按钮&#xff08; 组件 open-type“share”&#xff09;或右上角菜单“转发”按钮的行为&#xff0c;并自定义转发内容。 使用微信小程序的分享功能需要定义onShareAppMessage(Object obj…

Java基础 变量与数据类型

变量 为什么需要变量 一花一世界&#xff0c;如果把一个程序看做一个世界或一个社会的话&#xff0c;那么变量就是程 序世界的花花草草、万事万物。即&#xff0c;变量是程序中不可或缺的组成单位&#xff0c;最基 本的存储单元。 初识变量 变量的概念 内存中的一个存储区域…

工作几年,涨薪4K遭拒,后一天我就裸辞走了···

19年7月大学毕业&#xff0c;当时学的计算机科学专业。因为考研之后&#xff0c;秋招结束了。也没什么更多的岗位选择&#xff0c;就想着找个工作先干着&#xff0c;刚好有个亲戚在一家大厂公司上班说要招测试&#xff0c;所以就来做测试了。 虽然都是属于计算机大类&#xff0…

chatgpt赋能Python-python_nor

了解Python NOR 在Python编程语言中&#xff0c;NOR运算是一种逻辑运算符&#xff0c;用于反转两个变量的逻辑值。它是布尔运算中的一种&#xff0c;通常用于检查两个条件是否都不成立。 NOR运算有两个输入和一个输出&#xff0c;当输入为空或两个输入都为False时&#xff0c…

nuxt视频播放(踩坑)

展示效果&#xff1a; nuxt样例视频 1.安装vue-video-player插件 ①执行命令 npm i vue-video-player 或者 npm i vue-video-player5.0.2 后者直接安装对应版本号的插件 ②安装完之后 执行npm i ③安装不对应的版本会报错 ④注意安装版本 不是vue3.0的 请安装&#xff08;“v…

【nginx】同一接口有时返回500(client_body_temp)

问题描述&#xff1a; 同一个接口&#xff0c;有能正常访问并返回的&#xff0c;有的访问未到服务器直接返回500。 查看nginx日志&#xff08;error.log&#xff09;&#xff0c;发现open() "/nginx/client_body_temp/0000476534" failed (13: Permission denied)报…

java的URL类

文章目录 1. 简介2. 创建URL3. 从URL获取数据4. 分解URL5. 相等性和比较 1. 简介 java.net.URL类是对统一资源定位符的抽象。它扩展了Object类&#xff0c;是一个final类&#xff0c;不能对其派生子类。它不依赖于继承来配置不同的URL实例&#xff0c;而使用了策略设计模式&am…