细说STM32F407单片机独立看门狗IWDG的原理及使用方法

news/2025/1/19 10:40:17/

目录

一、独立看门狗的工作原理

二、独立看门狗的HAL驱动程序

1、初始化函数HAL_IWDG_Init()

2、刷新看门狗的函数HAL_IWDG_Refresh()

3、宏函数

三、独立看门狗使用示例

1、项目动作说明

2、工程配置

(1)DEBUG、USART6、GPIO、CodeGenrator

(2) 时钟

(3) RTC

(4)IWDG

(5)NVIC

3、软件设计

(1)KEYLED

(2) main.c

4、运行与调试


        看门狗(Watchdog)就是MCU上的一种特殊的定时器,用于监视系统的运行,在发生错误(例如程序出现死循环)时,能自动使系统复位。STM32F407上有1个独立看门狗和1个窗口看门狗,这两个看门狗的作用不一样。

一、独立看门狗的工作原理

        独立看门狗(Independent Watchdog,IWDG)是由内部32kHz低速时钟LSI驱动的自由运行的12位递减计数器。LSI在时钟树上的位置如图所示。“独立看门狗”简称为“看门狗”。

 

        独立看门狗内部还可以对LSI时钟进行分频,分频后的时钟作为计数器的时钟信号。在预分频器寄存器IWDG_PR里,有PR[2:0]用于设置分频系数,分频系数从4、8、16到256。系统复位时,IWDG的12位递减计数器的值是4095。启动IWDG后,计数器就递减计数,当计数器值变为0的时候,就会使系统产生复位。

        独立看门狗有一个重载寄存器IWDG_RLR,可以设置一个12位的重载值,例如4000。在看门狗的递减计数器的值变为0之前,将IWDG_RLR里的值重新载入看门狗计数器,就可以避免产生复位。

        独立看门狗还有一个关键字寄存器IWDG_KR,其KEY[15:0]是一个只可以写的关键字。写入不同的关键字有不同的作用。

  • 写入0xAAAA时,重载寄存器IWDG_RLR中的12位值就会被写入计数器,从而使计数器从头开始递减计数,避免系统复位。此操作称为刷新看门狗。
  • 写入0x5555后,才可以修改预分频器寄存器IWDG_PR和重载寄存器IWDG_RLR的内容。
  • 写入0xCCCC时,启动独立看门狗。

        重载值为4095时独立看门狗的超时:

预分频系数超时/ms
/4512 
/81024 
/162048 
/324096 
/648192 
/12816384 
/25632768 

二、独立看门狗的HAL驱动程序

        独立看门狗的HAL驱动程序头文件是stm32f4xx_hal_iwdg.h,独立看门狗的驱动函数比较少,只有2个常规函数和几个宏函数。独立看门狗没有中断。

1、初始化函数HAL_IWDG_Init()

        函数HAL_IWDG_Init()用于初始化独立看门狗,其原型定义如下:

HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg);

        其中,参数hiwdg是IWDG_HandleTypeDef结构体指针,是看门狗对象指针。独立看门狗初始化后就自动启动了,且无法关闭。

        在CubeMX生成的外设初始化代码中,会定义一个独立看门狗外设对象变量,即

IWDG_HandleTypeDef hiwdg; //独立看门狗外设对象变量

        结构体IWDG_HandleTypeDef的定义如下,各成员变量的意义见注释:

typedef struct
{IWDG_TypeDef *Instance;    //IWDG寄存器基址IWDG_InitTypeDef Init;     //IWDG的参数
}IWDG_HandleTypeDef;

        其中的成员变量Init是结构体类型IWDG_InitTypeDef,它定义了IWDG的参数,这个结构体定义如下,各成员变量的意义见注释:

typedef struct
{uint32_t Prescaler; //IWDG预分频系数,也就是预分频寄存器工WDG_PR里的PR[2:0]uint32_t Reload;    //IWDG计数器重载值,也就是重载寄存器IWDG_RLR的值
}IWDG_InitTypeDef;

2、刷新看门狗的函数HAL_IWDG_Refresh()

        函数HAL_IWDG_Refresh()用于刷新看门狗,就是将重载寄存器IWDG_RLR的值重新载入看门狗计数器,避免产生系统复位。函数HAL_IWDG_Refresh()的原型定义如下,只需使用IWDG对象指针作为函数参数:

HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg);

3、宏函数

        文件stm32f4xx_hal_iwdg.h还有几个主要的宏函数,这些函数的输入参数__HANDLE__是独立看门狗对象指针。

  • __HAL_IWDG_START(__HANDLE__),启动独立看门狗,就是向关键字寄存器IWDG_KR写入0x0000CCCC。
  • __HAL_IWDG_RELOAD_COUNTER(__HANDLE__),重置看门狗计数器的值,就是向关键字寄存器IWDG_KR写入0x0000AAAA,这会导致重载寄存器IWDG_RLR中的值载入看门狗计数器。这个宏函数与函数HAL_IWDG_Refresh()的功能相同。
  • __IWDG_ENABLE_WRITE_ACCESS(__HANDLE__),使预分频寄存器IWDG_PR和重载寄存器IWDG_RLR变为可写的,其代码就是向关键字寄存器IWDG_KR写入0x00005555。
  • __IWDG_DISABLE_WRITE_ACCESS(__HANDLE__),使预分频寄存器IWDG_PR和重载寄存器IWDG_RLR变为不可写的,其代码就是向关键字寄存器IWDG_KR写入0x00000000。

三、独立看门狗使用示例

1、项目动作说明

        本文作者旨在介绍如何IWDG及用法。继续使用旺宝红龙开发板STM32F407ZGT6 KIT V1.0。项目的目的:  

  • 配置独立看门狗的超时为8192ms。
  • 使用RTC周期唤醒功能,唤醒周期为1s,使用一个全局变量Seconds进行秒计时。
  • 按下任何一个按键时,刷新看门狗,使全局变量Seconds归零。
  • 超过8s无按键刷新看门狗,系统将复位。 
[S2]KeyUp    = IWDG_Refresh.           LED1 ON
[S3]KeyDown  = IWDG_Refresh.           LED1 ON
[S4]KeyLeft  = IWDG_RELOAD_COUNTER.    LED2 ON
[S4]KeyRight = IWDG_RELOAD_COUNTER.    LED2 ON

        示例仍然引用KEYLED文件夹中的文件。需要参考本文作者写的其他文章:

        参考文章1:细说STM32F407单片机中断方式CAN通信_stm32f407 103 can通信-CSDN博客  https://wenchm.blog.csdn.net/article/details/144913579 

        参考文章2: 细说STM32F407单片机以DMA方式读写外部SRAM的方法_stm32外部sram可用dma吗-CSDN博客  https://wenchm.blog.csdn.net/article/details/145013118

2、工程配置

(1)DEBUG、USART6、GPIO、CodeGenrator

         与参考文章1相同。

 

(2) 时钟

        HSE和LSE均使用外部晶振。 这里,设置HCLK=168MHz,PCLK1=42MHz,PCLK2=84MHz。

(3) RTC

        开启RTC的时钟源和日历,在时钟树上设置LSE为RTC的时钟源。开启RTC的周期唤醒功能,设置唤醒时钟为1Hz信号,唤醒周期为1s。开启RTC周期唤醒中断,设置RTC的周期唤醒中断抢占优先级为1。RTC设置结果如图20-2所示。

(4)IWDG

       LSI时钟频率是32kHz,看门狗最大重载值是4095(对应0xFFF),根据预分频系数可以计算出IWDG的最长超时(timeout)。

       MCU内部的LSI时钟频率不是非常准确,例如,STM32F407的LSI频率范围是17kHz~47kHz,所以在设置刷新独立看门狗的周期时,要留出一定的余量。

        对独立看门狗IWDG的设置界面如图所示。在模式设置部分只需激活IWDG即可,参数设置部分只有两个参数。

  • IWDG counter clock prescaler,独立看门狗计数器的预分频系数,可选值为4~256。这里设置为64,因为LSI是32kHz,所以看门狗计数器的时钟信号频率是500Hz。
  • IWDG down-counter reload value,递减计数器的重载值,可输入范围是0~4095,这里设置为4095。

(5)NVIC

         开启RTC周期唤醒中断,设置RTC的周期唤醒中断抢占优先级为1。

        经过这样的设置后,递减计数器的时钟信号周期是2ms,所以独立看门狗的超时是8192ms,也就是大约8s。如果超过8s不刷新独立看门狗,系统就会复位。

3、软件设计

(1)KEYLED

         本例的项目中要使用KEYLED,其中的keyled.c和keyled.h的使用方法与参考文章2相同。

(2) main.c

/* USER CODE BEGIN Includes */
#include "keyled.h"
#include <stdio.h>
/* USER CODE END Includes */
/* USER CODE BEGIN PD */
uint8_t Seconds=0;		//秒计数器
/* USER CODE END PD */
/* USER CODE BEGIN 2 *///IWDG初始化后就已经自动启动,且无法停止printf("Demo20_IWDG: Independent Watchdog\r\n");printf("IWDG should be refreshed in 8s.\r\n");printf("Press any key to refresh IWDG.\r\n");//显示菜单printf("[S2]KeyUp    = IWDG_Refresh.\r\n");printf("[S3]KeyDown  = IWDG_Refresh.\r\n");printf("[S4]KeyLeft  = IWDG_RELOAD_COUNTER.\r\n");printf("[S4]KeyRight = IWDG_RELOAD_COUNTER.\r\n\r\n");// MCU output low level LED light is onLED1_OFF();LED2_OFF();LED3_OFF();/* USER CODE END 2 */
/* USER CODE BEGIN 3 */KEYS curKey = ScanPressedKey(KEY_WAIT_ALWAYS);switch(curKey){case KEY_DOWN:case KEY_UP:{HAL_IWDG_Refresh(&hiwdg);			//刷新IWDGprintf("IWDG is refreshed:\r\n");LED1_ON();LED2_OFF();LED3_OFF();break;}case KEY_LEFT:case KEY_RIGHT:{__HAL_IWDG_RELOAD_COUNTER(&hiwdg);	//刷新IWDGprintf("IWDG is refreshed:\r\n");LED1_OFF();LED2_ON();LED3_OFF();}default:{LED1_OFF();LED2_OFF();LED3_OFF();printf("IWDG is not refreshed:\r\n");}}Seconds = 0;		//秒计数清零HAL_Delay(500);		//消除按键抖动影响}/* USER CODE END 3 */
/* USER CODE BEGIN 4 */
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{Seconds++;	//秒计数值printf("Stopwatch counting: %d\r\n",Seconds);
}int __io_putchar(int ch)
{HAL_UART_Transmit(&huart6,(uint8_t*)&ch,1,0xFFFF);return ch;
}
/* USER CODE END 4 */

        在main()函数的while循环中检测按键输入,4个按键中有任何一个按下时,就会调用函数HAL_IWDG_Refresh()或宏函数_HAL_IWDG_RELOAD_COUNTER()刷新看门狗,并且使全局变量Seconds清零。这两个函数的功能是完全一样的

        文件main.c还实现了RTC周期唤醒中断的回调函数HAL_RTCEx_WakeUpTimerEventCallback(),在这个回调函数里将全局变量Seconds加1,并且在串口助手上显示。

4、运行与调试

        运行时,串口助手上会显示秒计数值,如果计数值超过4还未按下任何键,系统就会复位。如果在计数值达到4之前按任何键就会刷新看门狗,并且重新开始秒计数。

 


http://www.ppmy.cn/news/1564385.html

相关文章

【springboot】Spring 官方抛弃了 Java 8!新idea如何创建java8项目

解决idea至少创建jdk17项目 问题 idea现在只能创建最少jdk17&#xff0c;不能创建java8了吗?解决 问题 idea现在只能创建最少jdk17&#xff0c;不能创建java8了吗 我本来以为是 IDEA 版本更新导致的 Bug&#xff0c;开始还没在意。 直到我今天自己初始化项目时才发现&am…

BGP边界网关协议(Border Gateway Protocol)概念、邻居建立

一、定义 主要用于交换AS之间的可达路由信息&#xff0c;构建AS域间的传播路径&#xff0c;防止路由环路的产生&#xff0c;并在AS级别应用一些路由策略。当前使用的版本是BGP-4。 二、环境 底层以OSPF进行igp互联互通&#xff0c;上层使用BGP协议。 三、基本原理 1、BGP是一…

MySql操作指南5--事务与并发控制

数据库事务是保障数据一致性和可靠性的重要手段&#xff0c;并发控制则在多用户环境下确保数据的正确性。风云今天详细探讨数据库事务的管理、并发访问的最佳实践&#xff0c;乐观锁与悲观锁的应用&#xff0c;以及Golang 中的事务实现、并发访问的最佳实践&#xff0c;通过合理…

学英语学技术:Elasticsearch 线程池

单词 汉语意思 音标 allocate 分配 /ˈləˌkeɪt/ coordination 协调 /koʊˌɔːrdɪˈneɪʃn/ deprecated 废弃的 /ˈdɛprəˌkeɪtɪd/ elasticsearch 弹性搜索&#xff08;专有名词&#xff09; /ˌɛlɪkˈsɜːrtʃ/ execute 执行 /ˈɛksɪˌkjuːt…

C 语言的void*到底是什么?

一、void* 的类型任意性 void* 是一种通用指针类型。它可以指向任意类型的数据。例如&#xff0c;它可以指向一个整数&#xff08;int&#xff09;、一个浮点数&#xff08;float&#xff09;、一个字符&#xff08;char&#xff09;或者一个结构体等。在C语言中&#xff0c;当…

电脑换固态硬盘

参考&#xff1a; https://baijiahao.baidu.com/s?id1724377623311611247 一、根据尺寸和缺口可以分为以下几种&#xff1a; 1、M.2 NVME协议的固态 大部分笔记本是22x42MM和22x80MM nvme固态。 在京东直接搜&#xff1a; M.2 2242 M.2 2280 2、msata接口固态 3、NGFF M.…

Word中如何格式化与网页和 HTML 内容相关的元素

在 Microsoft Word 中&#xff0c;HTML变量、HTML打字机、HTML地址、HTML定义、HTML键盘、HTML缩写、HTML样本、HTML引文 等样式是针对在文档中处理与 HTML 相关内容时&#xff0c;方便格式化特定类型的文本元素。以下是每个样式的详细说明及其使用场景&#xff1a; 1. HTML 变…

“提升大语言模型推理与规划能力的策略:思维链提示与由少至多提示”

思维链提示&#xff08;Chain-of-Thought Prompting&#xff09;和由少至多提示&#xff08;Least-to-Most Prompting&#xff09;是两种提升大语言模型在推理和规划任务上表现的有效方法。下面详细介绍这两种方法的原理和应用&#xff1a; 思维链提示&#xff08;Chain-of-Th…