OpenEdv-开源电子网

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

《STM32H7R7开发指南 V1.1 》第十七章 独立看门狗(IWDG)实验

[复制链接]

1299

主题

1315

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
5563
金钱
5563
注册时间
2019-5-8
在线时间
1474 小时
发表于 6 小时前 | 显示全部楼层 |阅读模式
第十七章 独立看门狗(IWDG)实验

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 的独立看门狗(以下简称IWDG)。STM32H7R7内部自带了2个看门狗:独立看门狗(IWDG)和窗口看门狗(WWDG)。这一章我们只介绍独立看门狗,窗口看门狗将在下一章介绍。在本章中,我们将通过按键KEY_UP来喂狗,然后通过LED0提示复位状态。
本章分为如下几个小节:
17.1 IWDG简介
17.2 硬件设计
17.3 程序设计
17.4 下载验证


17.1 IWDG简介
独立看门狗本质上是一个定时器,这个定时器有一个输出端,可以输出复位信号。该定时器是一个12位的递减计数器,当计数器的值减到0的时候,就会产生一个复位信号。如果在计数没减到0之前,重置计数器的值的话,那么就不会产生复位信号,这个动作我们称为喂狗。看门狗功能由VDD电压域供电,在停止模式和待机模式下仍然可以工作。

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

第十七章 独立看门狗460.png
图17.1.1.1 IWDG框图

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

1.png
表17.1.1.1 IWDG内部输入/输出信号

STM32H7R7的独立看门狗由内部专门的32Khz低速时钟(lsi_ck)驱动,即使主时钟发生故障,它也仍然有效。这里需要注意独立看门狗的时钟是一个内部RC时钟,所以并不是准确的32Khz,而是在17~47Khz之间的一个可变化的时钟,只是我们在估算的时候,以32Khz的频率来计算,看门狗对时间的要求不是很精确,所以,时钟有些偏差,都是可以接受的。

17.1.2 IWDG寄存器
IWDG的框图很简单,用到的寄存器也不多。我们主要用到其中3个寄存器:
键寄存器(IWDG_KR)
键寄存器可以看作是独立看门狗的控制寄存器,其描述如图17.1.2.1所示:


第十七章 独立看门狗961.png
图17.1.2.1 IWDG_KR寄存器

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


第十七章 独立看门狗1305.png
图17.1.2.2 IWDG_ PR寄存器

该寄存器用来设置看门狗时钟(LSI)的分频系数,最低为4分频,最高位256分频,该寄存器是一个32位的寄存器,但是我们只用了最低4位,其他都是保留位。
重载寄存器(IWDG_ RLR)


第十七章 独立看门狗1422.png
图17.1.2.3 IWDG_ RLR寄存器

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

17.2 硬件设计

1. 例程功能
在配置看门狗后,LED0将常亮,如果KEY_UP按键按下,就喂狗,只要KEY_UP不停的按,看门狗就一直不会产生复位,保持LED0的常亮,一旦超过看门狗定溢出时间(Tout)还没按,那么将会导致程序重启,这将导致LED0熄灭一次。

2. 硬件资源
1)LED灯
       LED0:LED0 – PD14
2)独立按键
       WK_UP – PC13
3)独立看门狗

3. 原理图
独立看门狗实验的核心是在STM32H7R7内部进行,并不需要外部电路。喂狗我们采用板上的KEY_UP键来操作,通过LED0来指示。


17.3 程序设计

17.3.1 IWDG的HAL库驱动
IWDG在HAL库中的驱动代码在stm32h7rsxx_hal_iwdg.c文件(及其头文件)中。
1. HAL_IWDG_Init函数
IWDG的初始化函数,其声明如下:
HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg);
函数描述:
用于初始化IWDG。
函数形参:
形参1是IWDG句柄,IWDG_HandleTypeDef结构体类型,其定义如下:

  1. typedef struct
  2. {
  3.    IWDG_TypeDef                 *Instance;  /* IWDG寄存器基地址 */
  4.    IWDG_InitTypeDef             Init;       /* IWDG初始化参数 */
  5. }IWDG_HandleTypeDef;
  6. 1)Instance:指向IWDG寄存器基地址。
  7. 2)Init:IWDG初始化结构体,用于配置计数器的相关参数。
  8. IWDG_InitTypeDef这个结构体类型定义如下:
  9. typedef struct
  10. {
  11.   uint32_t Prescaler;          /* 预分频系数 */
  12.   uint32_t Reload;             /* 重装载值 */
  13.   uint32_t Window;             /* 窗口值 */
  14.   uint32_t EWI;             /* 唤醒中断 */
  15. } IWDG_InitTypeDef;
复制代码
1)Prescaler:预分频系数,IWDG_PRESCALER_4到IWDG_PRESCALER_256。
2)Reload:重装载值,范围:0到0x0FFF。
3)Window:窗口值。
4)EWI:使能唤醒中断。
函数返回值:
HAL_StatusTypeDef枚举类型的值。
2. HAL_IWDG_Refresh函数
HAL_IWDG_Refresh函数是独立看门狗的喂狗函数。其声明如下:

  1. 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) /32
其中Tout为看门狗溢出时间(单位为ms)。
prer为看门狗时钟预分频值(IWDG_PR值),范围为0~7。
rlr为看门狗的重装载值(IWDG_RLR的值)。
比如我们设定prer值为IWDG_PRESCALER_32,rlr值为1000,那么就可以得到Tout=32×1000/32=1000ms,这样,看门狗的溢出时间就是1s,只要你在一秒钟之内,有一次写入0XAAAA到IWDG_KR,就不会导致看门狗复位(当然写入多次也是可以的)。这里需要提醒大家的是,看门狗的时钟不是准确的32Khz,所以在喂狗的时候,最好不要太晚了,否则,有可能发生看门狗复位。
2)重载计数值喂狗(向IWDG_KR写入0XAAAA)
在HAL中重载计数值的函数是HAL_IWDG_Refresh,该函数的作用是把值0xAAAA写入到IWDG_KR寄存器,从而触发计数器重载,即实现独立看门狗的喂狗操作。
3) 启动看门狗(向IWDG_KR写入0XCCCC)
HAL库函数里面启动独立看门狗是通过宏定义标识符来实现的:

  1. #define __HAL_IWDG_START(__HANDLE__)        
  2.          WRITE_REG((__HANDLE__)->Instance->KR, IWDG_KEY_ENABLE);
复制代码
我们只需要调用宏定义标识符__HAL_IWDG_START即可实现看门狗使能。实际上,当我们调用了看门狗初始化函数HAL_IWDG_Init之后,在内部已经调用了该宏启动看门狗。

17.3.2 程序解析

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

  1. /**
  2. * @brief   初始化独立看门狗
  3. * [url=home.php?mod=space&uid=271674]@param[/url]   prescaler: 预分频器系数
  4. * @arg     IWDG_PRESCALER_4  : 4分频
  5. * @arg     IWDG_PRESCALER_8  : 8分频
  6. * @arg     IWDG_PRESCALER_16 : 16分频
  7. * @arg     IWDG_PRESCALER_32 : 32分频
  8. * @arg     IWDG_PRESCALER_64 : 64分频
  9. * @arg     IWDG_PRESCALER_128: 128分频
  10. * @arg     IWDG_PRESCALER_256: 256分频
  11. * @param   reload: 自动重装载值(0~0xFFF)
  12. * @retval  无
  13. */
  14. void iwdg_init(uint32_t prescaler, uint32_t reload)
  15. {
  16.     g_iwdg_handler.Instance = IWDG;
  17.     g_iwdg_handler.Init.Prescaler = prescaler;
  18.     g_iwdg_handler.Init.Reload = reload;
  19. g_iwdg_handler.Init.Window = IWDG_WINDOW_DISABLE;
  20. g_iwdg_handler.Init.EWI = IWDG_EWI_DISABLE;
  21.     HAL_IWDG_Init(&g_iwdg_handler);
  22. }
复制代码
iwdg_init是独立看门狗初始化函数,主要设置预分频数和重装载寄存器的值。通过这两个寄存器,就可以大概知道看门狗复位的时间周期为多少了。
  1. /**
  2. * @brief       喂独立看门狗
  3. * @param       无
  4. * @retval      无
  5. */
  6. void iwdg_feed(void)
  7. {
  8.     HAL_IWDG_Refresh(&g_iwdg_handler);    /* 喂狗 */
  9. }
复制代码
iwdg_feed函数用来喂狗,在该函数内部只需调用HAL库函数HAL_IWDG_Refresh。

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.     key_init();                         /* 初始化按键 */
  13.     iwdg_init(IWDG_PRESCALER_32, 1000); /* 初始化IWDG,溢出时间约1秒 */
  14.     delay_ms(100);
  15.     LED0(0);
  16.    
  17.     while (1)
  18.     {
  19.         key = key_scan(0);
  20.         if (key == WKUP_PRES)   /* WKUP按键被按下 */
  21.         {
  22.             iwdg_feed();        /* 喂狗IWDG */
  23.         }
  24.         delay_ms(10);
  25.     }
  26. }
复制代码
在main函数里,先初始化系统和用户的外设代码,然后先点亮LED0,在无限循环里开始获取按键的键值,并判断是不是按键WK_UP按下,是的话就喂狗,不是则延时10ms,继续上述操作。当1秒钟后都没测到按键WK_UP按下,IWDG就会产生一次复位信号,系统复位,可以看到LED0因系统复位熄灭一次,再亮。反之,当按下按键WK_UP后,1秒内再按下按键WK_UP,就会及时喂狗,结果就是系统不会复位,LED0也就不会闪烁。
iwdg_init(IWDG_PRESCALER_32, 1000);这个语句有必要跟大家说明一下,这里的第一个形参直接使用HAL库自定义的IWDG_PRESCALER_32,即预分频系数为32,重装载值是1000,所以可由公式得到Tout=32×1000/32=1000ms,即溢出时间就是1s。只要你在一秒钟之内,有一次写0XAAAA到IWDG_KR,就不会导致看门狗复位(当然写入多次也是可以的)。这里需要提醒大家的是,看门狗的时钟不是准确的32Khz,所以在喂狗的时候,最好不要太晚了,否则,有可能发生看门狗复位。


17.4 下载验证
下载代码后,可以看到LED0不停的闪烁,证明系统在不停的复位,否则LED0常亮。这时我们试试不停的按KEY_UP按键,可以看到LED0就常亮了,不会再闪烁。说明我们的实验是成功的。
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

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

GMT+8, 2026-4-8 15:50

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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