【正点原子STM32连载】 第十八章 独立看门狗(IWDG)实验 摘自【正点原子】STM32F103 战舰开发指南V1.2

news2024/11/18 7:49:26

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

第十八章 独立看门狗(IWDG)实验

本章我们学习如何使用STM32F1的独立看门狗(以下简称IWDG)。STM32F1内部自带了2个看门狗:独立看门狗(IWDG)和窗口看门狗(WWDG)。这一章我们只介绍独立看门狗,窗口看门狗将在下一章介绍。在本章中,我们将通过按键KEY_UP来喂狗,然后通过LED0提示复位状态。
本章分为如下几个小节:
18.1 IWDG简介
18.2 硬件设计
18.3 程序设计
18.4 下载验证

18.1 IWDG简介

独立看门狗本质上是一个定时器,这个定时器有一个输出端,可以输出复位信号。该定时器是一个12位的递减计数器,当计数器的值减到0的时候,就会产生一个复位信号。如果在计数没减到0之前,重置计数器的值的话,那么就不会产生复位信号,这个动作我们称为喂狗。看门狗功能由VDD电压域供电,在停止模式和待机模式下仍然可以工作。
18.1.1 IWDG框图
下面先来学习IWDG框图,通过学习IWDG框图会有一个很好的整体掌握,同时对之后的编程也会有一个清晰的思路。
在这里插入图片描述

图18.1.1.1 IWDG框图
从IWDG框图整体认知就是,IWDG有一个输入(时钟LSI),经过一个8位的可编程预分频器提供时钟给一个12位递减计数器,满足条件就会输出一个复位信号。IWDG内部输入/输出信号如下表:
在这里插入图片描述

表18.1.1.1 IWDG内部输入/输出信号
STM32F103的独立看门狗由内部专门的40Khz低速时钟(LSI)驱动,即使主时钟发生故障,它也仍然有效。这里需要注意独立看门狗的时钟是一个内部RC时钟,所以并不是准确的40Khz,而是在30~60Khz之间的一个可变化的时钟,只是我们在估算的时候,以40Khz的频率来计算,看门狗对时间的要求不是很精确,所以,时钟有些偏差,都是可以接受的。
18.1.2 IWDG寄存器
IWDG的框图很简单,用到的寄存器也不多。我们主要用到其中3个寄存器:
 键寄存器(IWDG_KR)
键寄存器可以看作是独立看门狗的控制寄存器,其描述如图18.1.2.1所示:
在这里插入图片描述

图18.1.2.1 WDG_KR寄存器
在键寄存器(IWDG_KR)中写入0xCCCC,开始启用独立看门狗;此时计数器开始从其复位值0xFFF递减计数。当计数器计数到末尾0x000时,会产生一个复位信号(IWDG_RESET)。无论何时,只要键寄存器IWDG_KR中被写入0xAAAA,IWDG_RLR中的值就会被重新加载到计数器中从而避免产生看门狗复位。
IWDG_PR和IWDG_RLR寄存器具有写保护功能。要修改这两个寄存器的值,必须先向IWDG_KR寄存器中写入0x5555。将其他值写入这个寄存器将会打乱操作顺序,寄存器将重新被保护。重装载操作(即写入0xAAAA)也会启动写保护功能。
 预分频寄存器(IWDG_PR)
预分频寄存器描述如图18.1.2.2所示:
在这里插入图片描述

图18.1.2.2 IWDG_PR寄存器
该寄存器用来设置看门狗时钟(LSI)的分频系数,最低为4,最高位256,该寄存器是一个32位的寄存器,但是我们只用了最低3位,其他都是保留位。
 重载寄存器(IWDG_RLR)
在这里插入图片描述

图18.1.2.3 IWDG_RLR寄存器
该寄存器用来保存重装载到计数器中的值。该寄存器也是一个32位寄存器,只有低12位是有效的。
18.2 硬件设计

  1. 例程功能
    在配置看门狗后,LED0将常亮,如果KEY_UP按键按下,就喂狗,只要KEY_UP不停的按,看门狗就一直不会产生复位,保持LED0的常亮,一旦超过看门狗定溢出时间(Tout)还没按,那么将会导致程序重启,这将导致LED0熄灭一次。
  2. 硬件资源
    1)LED灯
    LED0 – PB5
    2)独立按键
    WK_UP - PA0。
    3)独立看门狗
  3. 原理图
    独立看门狗实验的核心是在STM32F103内部进行,并不需要外部电路。但是考虑到指示当前状态和喂狗等操作,我们需要2个IO口,一个用来触发喂狗信号,另外一个用来指示程序是否重启。喂狗我们采用板上的KEY_UP键来操作,而程序重启,则是通过LED0来指示的。
    18.3 程序设计
    18.3.1 IWDG的HAL库驱动
    IWDG在HAL库中的驱动代码在stm32f1xx_hal_iwdg.c文件(及其头文件)中。
  4. HAL_IWDG_Init函数
    IWDG的初始化函数,其声明如下:
    HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg);
    函数描述:
    用于初始化IWDG。
    函数形参:
    形参1是IWDG句柄,IWDG_HandleTypeDef结构体类型,其定义如下:
typedef struct
{
  IWDG_TypeDef                 *Instance;  /* IWDG寄存器基地址 */
  IWDG_InitTypeDef             Init;       /* IWDG初始化参数 */
} IWDG_HandleTypeDef;
1)Instance:指向IWDG寄存器基地址。
2)Init:IWDG初始化结构体,用于配置计数器的相关参数。
IWDG_InitTypeDef这个结构体类型定义如下:
typedef struct
{
  uint32_t Prescaler;  /* 预分频系数 */
  uint32_t Reload;      /* 重装载值 */
} IWDG_InitTypeDef;

1)Prescaler:预分频系数,IWDG_PRESCALER_4到IWDG_PRESCALER_256。
2)Reload:重装载值,范围:0到0x0FFF。
3)Window:窗口值。
函数返回值:
HAL_StatusTypeDef枚举类型的值。
2. HAL_IWDG_Refresh函数
HAL_IWDG_Refresh函数是独立看门狗的喂狗函数。其声明如下:
HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg);
函数描述:
用于把重装载寄存器的值重载到计数器中,喂狗,防止IWDG复位。
函数形参:
形参1是IWDG_HandleTypeDef结构体指针类型的IWDG句柄。
函数返回值:
HAL_StatusTypeDef枚举类型的值。
独立看门狗配置步骤
1) 取消寄存器写保护,设置看门狗预分频系数和重装载值
首先我们必须取消IWDG_PR和IWDG_RLR寄存器的写保护,这样才可以设置寄存器IWDG_PR和IWDG_RLR的值。取消写保护和设置预分频系数以及重装载值在HAL库中是通过函数HAL_IWDG_Init实现的。
通过该函数设置看门狗的分频系数,和重装载的值。看门狗的喂狗时间(也就是看门狗溢出时间)的计算方式为:
Tout=((4×2^prer) ×rlr) /40
其中Tout为看门狗溢出时间(单位为ms)。
prer为看门狗时钟预分频值(IWDG_PR值),范围为0~7。
rlr为看门狗的重装载值(IWDG_RLR的值)。
比如我们设定prer值为4(4代表的是64分频,HAL库中可以使用宏定义标识符IWDG_PRESCALER_64),定时值为Tout=1秒,那么就可以得到Tout=64×rlr/40Khz=1s,这样,得到看门狗的溢出时间要为1s需要设置rlr为625,只要你在一秒钟之内,有一次写入0XAAAA到IWDG_KR,就不会导致看门狗复位(当然写入多次也是可以的)。这里需要提醒大家的是,看门狗的时钟不是准确的40Khz,所以在喂狗的时候,最好不要太晚了,否则,有可能发生看门狗复位。
2) 重载计数值喂狗(向IWDG_KR写入0XAAAA)
在HAL中重载计数值的函数是HAL_IWDG_Refresh,该函数的作用是把值0xAAAA写入到IWDG_KR寄存器,从而触发计数器重载,即实现独立看门狗的喂狗操作。
3) 启动看门狗(向IWDG_KR写入0XCCCC)
HAL库函数里面启动独立看门狗是通过宏定义标识符来实现的:
#define __HAL_IWDG_START(HANDLE)
WRITE_REG((HANDLE)->Instance->KR, IWDG_KEY_ENABLE);
我们只需要调用宏定义标识符__HAL_IWDG_START即可实现看门狗使能。实际上,当我们调用了看门狗初始化函数HAL_IWDG_Init之后,在内部已经调用了该宏启动看门狗。
18.3.2 程序流程图
下面看看本实验的程序流程图:
在这里插入图片描述

图18.3.2.1 独立看门狗实验程序流程图
18.3.3 程序解析

  1. IWDG驱动代码
    这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。独立看门狗(IWDG)驱动源码包括两个文件:wdg.c和wdg.h。
    wdg.h头文件只有函数的声明,就不解释了。下面我们直接解析wdg.c的程序,先看IWDG的初始化函数,其定义如下:
/**
 * @brief       初始化独立看门狗 
 * @param       prer: IWDG_PRESCALER_4~IWDG_PRESCALER_256,对应4~256分频
 * @arg         分频因子 = 4 * 2^prer. 但最大值只能是256!
 * @param       rlr: 自动重装载值,0~0XFFF. 
 * @note        时间计算(大概):Tout=((4 * 2^prer) * rlr) / 40 (ms). 
 * @retval      无
 */
void iwdg_init(uint8_t prer, uint16_t rlr)
{
    g_iwdg_handle.Instance = IWDG1;
    g_iwdg_handle.Init.Prescaler = prer;                 /* 设置IWDG分频系数 */
    g_iwdg_handle.Init.Reload = rlr;                      /* 重装载值 */
    g_iwdg_handle.Init.Window = IWDG_WINDOW_DISABLE;   /* 关闭窗口功能 */
    HAL_IWDG_Init(&g_iwdg_handle);    
}

IWDG_Init是独立看门狗初始化函数,主要设置预分频数和重装载寄存器的值。通过这两个寄存器,就可以大概知道看门狗复位的时间周期为多少了。

/**
 * @brief       喂独立看门狗
 * @param       无
 * @retval      无
 */
void iwdg_feed(void)
{   
    HAL_IWDG_Refresh(&g_iwdg_handle); /* 重装载计数器 */
}

iwdg_feed函数用来喂狗,在该函数内部只需调用HLA库函数HAL_IWDG_Refresh。
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 */
    key_init();                             	/* 初始化按键 */
delay_ms(100);                    	/* 延时100ms再初始化看门狗,LED0的变化"可见" */
iwdg_init(IWDG_PRESCALER_64,625);	/* 预分频数64,重载值为625,溢出时间约为1s */
    LED0(0);                                	/* 点亮LED0(红灯) */

    while (1)
    {
        if (key_scan(1) == WKUP_PRES)	/* 如果WK_UP按下,则喂狗 */
        {
            iwdg_feed();                  	/* 喂狗 */
        }
        delay_ms(10);
    }
}

在main函数里,先初始化系统和用户的外设代码,然后先点亮LED0,在无限循环里开始获取按键的键值,并判断是不是按键WK_UP按下,是的话就喂狗,不是则延时10ms,继续上述操作。当1秒钟后都没测到按键WK_UP按下,IWDG就会产生一次复位信号,系统复位,可以看到LED0因系统复位熄灭一次,再亮。反之,当按下按键WK_UP后,1秒内再按下按键WK_UP,就会及时喂狗,结果就是系统不会复位,LED0也就不会闪烁。
iwdg_init(IWDG_PRESCALER_64, 625);这个语句有必要跟大家说明一下,这里的第一个形参直接使用HAL库自定义的IWDG_PRESCALER_64,即预分频系数为64,重装载值是625,所以可由公式得到Tout=64×625/40=1000ms,即溢出时间就是1s。只要你在一秒钟之内,有一次写0XAAAA到IWDG_KR,就不会导致看门狗复位(当然写入多次也是可以的)。这里需要提醒大家的是,看门狗的时钟不是准确的40Khz,所以在喂狗的时候,最好不要太晚了,否则,有可能发生看门狗复位。
18.4 下载验证
下载代码后,可以看到LED0不停的闪烁,证明系统在不停的复位,否则LED0常亮。这时我们试试不停的按KEY_UP按键,可以看到LED0就常亮了,不会再闪烁。说明我们的实验设计成功了。

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

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

相关文章

【Netty】Netty 架构设计(二)

文章目录 前言一、Selector 模型1.1 SelectableChannel1.2 Channel 注册到 Selector1.3 SelectionKey1.4 遍历 SelectionKey 二、事件驱动2.1 Channel2.2 回调2.3 Future2.4 事件及处理器 三、责任链模式3.1 责任链模式的优缺点3.2 ChannelPipeline3.3 将事件传递给下一个处理器…

从事软件测试2年跳槽4次,不给你涨薪真不怪老板……

前几天和朋友们聚餐,发现了一个有意思的现象。 所谓的聚餐其实就是大家对于工作生活的一个大型倒苦水现场。 最近工作太TM烦心了,越来越觉得没有意思了,感觉没啥前途,也不给人涨薪。 我也是,不仅工作压力大&#xff0…

华为云网站备案操作流程

目录 一、官方指引二、操作步骤1.操作场景2.前提条件3.操作步骤(1)下载华为云 APP(2)登录华为云 APP,在 “控制台” 中单击 “网站备案”,进入 APP 备案操作入口(3)验证备案类型&…

HarmonyOS低代码开发-在已有工程中添加Visual

使用低代码开发应用或服务有以下两种开发方式:创建一个支持低代码开发的新工程,开发应用或服务的UI界面。在已有工程中,创建Visual文件来开发应用或服务的UI界面。ArkTS工程和JS工程使用低代码的步骤相同,接下来以JS工程为例分别讲…

【LCD应用编程】练习一 —— 绘制点、线、矩形框

之前获取LCD屏幕参数信息时了解到,LCD屏是 FrameBuffer 设备,操作 FrameBuffer 设备 其实就是在读写 /dev/fb0 文件。除此之外,LCD屏上包含多个像素点,绘制点、线、矩形框本质是在修改这些像素点的颜色。 目录 1、定义 lcd_color…

Vulkan Tutorial 4

11 framebuffer 我们已经将渲染传递设置为期望一个与交换链图像格式相同的单一帧缓冲,但我们还没有实际创建任何图像。 在渲染过程创建期间指定的附件通过将它们包装到一个VkFramebuffer对象中来绑定。帧缓冲区对象引用 VkImageView代表附件的所有对象。 std::ve…

SSH和SFTP是否相同

SSH和SFTP是否相同?SSH和SFTP是经典的对。在确保通信安全方面,它们交织在一起,尽管它们具有类似的功能,但它们并不是一回事。那么,它们之间有什么区别?请仔细阅读,找出答案。 什么是SSH&#x…

Java使用xlsx-streamer和EasyExcel解决读取超大excel数据时OutOfMemoryError的问题

解决读取超大excel数据时OutOfMemoryError的问题 前言关于Excel相关技术场景复现与问题定位问题代码读取50MB40万行数据读取84MB100万行数据 解决方案一:xlsx-streamer引入依赖:示例代码:加载数据效果耗费资源对比 解决方案二:Eas…

静态时序分析-时序检查

时序检查 一旦在触发器的时钟引脚上定义了时钟,便会自动推断出该触发器的建立时间和保持时间检查。时序检查通常会在多个条件下执行,通常,最差情况的慢速条件对于建立时间检查很关键,而最佳情况的快速条件对于保持时间检查很关键。 1.建立时间检查 在时钟的有效沿到达触…

9:02面试,9:08就出来了,这问的我毫无还手之力····

就离谱了,现在面试都这么难的了嘛 从外包出来,没想到算法死在另一家厂子 自从加入这家公司,每天都在加班,钱倒是给的不少,所以也就忍了。没想到8月一纸通知,所有人不许加班,薪资直降30%&#x…

C语言代码封装MQTT协议报文,了解MQTT协议通信过程

【1】MQTT协议介绍 MQTT是一种轻量级的通信协议,适用于物联网(IoT)和低带宽网络环境。它基于一种“发布/订阅”模式,其中设备发送数据(也称为 “发布”)到经纪人(称为MQTT代理)&…

实现一个域名对应多个IP地址和DNS优缺点

DNS定义 DNS(Domain Name System)是因特网的一项服务,它作为域名和IP地址相互映射的一个分布式数据库,能够使人更方便的访问互联网。 DNS作用 解析域名 人们在通过浏览器访问网站时只需要记住网站的域名即可,而不需…

清晰易懂IoC

1.IoC的目的在于让服务端的代码不需要改动 这段代码的问题在于,如果想要调用不同的dao层,就需要在服务端的代码Service层中进行改动 比如要调用dao1,Service层代码就是Dao dao1new Dao1() 比如要调用dao2,Service层代码就是Dao …

【JavaScript 递归】判断两个对象的键值是否完全一致,支持深层次查询,教你玩转JavaScript脚本语言

博主:東方幻想郷 Or _LJaXi 专栏分类:JavaScript | 脚本语言 JavaScript 递归 - 判断两个对象的键值 🌕 起因🌓 代码流程⭐ 第一步 判断两个对象的长度是否一致⭐ 第二步 循环 obj 进行判断两个对象⭐ 第三步 递归条件判断两个对象…

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

ChatGPT:你真的了解网络安全吗?浅谈网络安全攻击防御进行时 网络攻击新威胁1) 人工智能的应用2) 5G和物联网的崛起3) 云安全4) 社交工程的威胁 总结 ChatGPT(全名:Chat Generative Pre-trained Transformer)&#xff0…

大龄、零基础,想转行做网络安全。怎样比较可行?这届粉丝可真难带

昨晚上真的给我气孕了。 对于一直以来对网络安全兴趣很大,想以此作为以后的职业方向的人群。 不用担心,你可以选择兼顾工作和学习,以步步为营的方式尝试转行到网络安全领域。 那么,网络安全到底要学些什么呢? &…

getline()与cin.getline()

文章目录 1.getline2.cin.getline3.区别 1.getline 读取一行内容。定义为: istream& getline (istream& is, string& str, char delim);参数一:istream &is 表示一个输入流,譬如cin; 参数二:string…

Tensorflow2基础代码实战系列之双层RNN文本分类任务

深度学习框架Tensorflow2系列 注:大家觉得博客好的话,别忘了点赞收藏呀,本人每周都会更新关于人工智能和大数据相关的内容,内容多为原创,Python Java Scala SQL 代码,CV NLP 推荐系统等,Spark …

自动化测试工具selenium的使用方法

一、前言 由于requests模块是一个不完全模拟浏览器行为的模块,只能爬取到网页的HTML文档信息,无法解析和执行CSS、JavaScript代码,因此需要我们做人为判断; selenium模块本质是通过驱动浏览器,完全模拟浏览器的操作&…

Python爬虫入门案例6:scrapy的基本语法+使用scrapy进行网站数据爬取

几天前在本地终端使用pip下载scrapy遇到了很多麻烦,总是报错,花了很长时间都没有解决,最后发现pycharm里面自带终端!(狂喜),于是直接在pycharm终端里面写scrapy了 这样的好处就是每次不用切换路…