STM32 HAL库RTC实时时钟超细详解

一、引言

在嵌入式系统的应用中,实时时钟(RTC)是一个非常重要的功能模块。它能够独立于主系统提供精确的时间和日期信息,即使在系统断电的情况下,也可以依靠备用电池继续运行。STM32F407 是一款性能强大的微控制器,其内置的 RTC 外设结合 HAL 库,为开发者提供了便捷、高效的实时时钟解决方案。本文将详细介绍基于 STM32F407 HAL 库的 RTC 实时时钟的开发过程,包括硬件连接、时钟配置、时间设置与读取等方面的内容。

二、STM32F407 RTC 硬件特性

2.1 RTC 基本结构

STM32F407 的 RTC 外设主要由以下几个部分组成:

  • 时钟源:RTC 可以使用三种不同的时钟源,分别是低速内部时钟(LSI,约 32kHz)、低速外部时钟(LSE,32.768kHz)和高速外部时钟(HSE)经过 128 分频后的时钟。其中,LSE 由于其高精度和稳定性,是 RTC 最常用的时钟源。
  • 预分频器:用于将时钟源的频率进行分频,以得到合适的 RTC 时钟频率。预分频器分为两个部分,一个是异步预分频器(PSC),另一个是同步预分频器(SYNCH_PREDIV)。
  • 计数器:RTC 包含两个 32 位的计数器,分别是秒计数器(RTC_SSR)和日历计数器(RTC_TR 和 RTC_DR)。秒计数器用于记录秒数,日历计数器用于记录时间和日期信息。
  • 闹钟寄存器:RTC 提供了两个闹钟寄存器(RTC_ALRMAR 和 RTC_ALRMBR),可以设置闹钟时间,当达到设定的闹钟时间时,会产生闹钟中断。

2.2 备用电源

为了保证 RTC 在系统断电的情况下仍然能够正常运行,需要为其提供备用电源。STM32F407 的 RTC 可以通过 VBAT 引脚连接备用电池,当主电源 VDD 断电时,备用电池会自动为 RTC 供电。

三、开发环境搭建

3.1 硬件准备

  • STM32F407 开发板:选择一款合适的 STM32F407 开发板,如正点原子的探索者开发板或野火的指南者开发板。
  • 调试工具:使用 ST-Link 或 J-Link 调试器,用于将程序下载到开发板上。
  • 备用电池:选择合适的纽扣电池,如 CR1220,连接到开发板的 VBAT 引脚。

3.2 软件准备

  • 开发工具:使用 Keil MDK-ARM 集成开发环境,该环境支持 STM32 系列微控制器的开发。
  • STM32CubeMX:用于快速配置 STM32 的外设和生成初始化代码。STM32CubeMX 是一款图形化的配置工具,它可以帮助开发者快速生成基于 HAL 库的初始化代码,大大提高开发效率。

四、基于 HAL 库的 RTC 编程

4.1 代码结构分析

使用 STM32CubeMX 生成的代码包含了 RTC 的初始化代码,主要在main.cstm32f4xx_hal_msp.c文件中。在main.c文件中,会调用MX_RTC_Init()函数来初始化 RTC 外设。

/* USER CODE BEGIN PFP */
/* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *//* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_RTC_Init();/* USER CODE BEGIN 2 *//* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

4.2 时间设置

在程序中,可以使用HAL_RTC_SetTime()HAL_RTC_SetDate()函数来设置 RTC 的时间和日期。以下是一个设置时间和日期的示例代码:

#include "main.h"
#include "rtc.h"
#include "stdio.h"RTC_HandleTypeDef hrtc;void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_RTC_Init(void);int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_RTC_Init();RTC_TimeTypeDef sTime = {0};RTC_DateTypeDef sDate = {0};// 设置时间为12:30:00sTime.Hours = 12;sTime.Minutes = 30;sTime.Seconds = 0;HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN);// 设置日期为2024年10月1日sDate.Year = 24;sDate.Month = RTC_MONTH_OCTOBER;sDate.Date = 1;HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN);while (1){// 主循环}
}

4.3 时间读取

使用HAL_RTC_GetTime()HAL_RTC_GetDate()函数可以读取 RTC 的当前时间和日期。以下是一个读取时间和日期并通过串口输出的示例代码:

#include "main.h"
#include "rtc.h"
#include "stdio.h"RTC_HandleTypeDef hrtc;
UART_HandleTypeDef huart1;void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_RTC_Init(void);
static void MX_USART1_UART_Init(void);int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_RTC_Init();MX_USART1_UART_Init();RTC_TimeTypeDef sTime = {0};RTC_DateTypeDef sDate = {0};char buffer[50];while (1){HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);sprintf(buffer, "Date: %02d/%02d/%02d Time: %02d:%02d:%02d\r\n",sDate.Date, sDate.Month, 2000 + sDate.Year,sTime.Hours, sTime.Minutes, sTime.Seconds);HAL_UART_Transmit(&huart1, (uint8_t *)buffer, strlen(buffer), HAL_MAX_DELAY);HAL_Delay(1000);}
}

4.4 闹钟设置与中断处理

RTC 可以设置闹钟功能,当达到设定的闹钟时间时,会产生闹钟中断。以下是一个设置闹钟并处理中断的示例代码:

#include "main.h"
#include "rtc.h"
#include "stdio.h"RTC_HandleTypeDef hrtc;
UART_HandleTypeDef huart1;void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_RTC_Init(void);
static void MX_USART1_UART_Init(void);void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{char buffer[] = "Alarm triggered!\r\n";HAL_UART_Transmit(&huart1, (uint8_t *)buffer, strlen(buffer), HAL_MAX_DELAY);
}int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_RTC_Init();MX_USART1_UART_Init();RTC_AlarmTypeDef sAlarm = {0};// 设置闹钟时间为12:31:00sAlarm.AlarmTime.Hours = 12;sAlarm.AlarmTime.Minutes = 31;sAlarm.AlarmTime.Seconds = 0;sAlarm.Alarm = RTC_ALARM_A;HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN);while (1){// 主循环}
}

五、RTC 校准

由于时钟源存在一定的误差,长时间运行后 RTC 的时间可能会出现偏差。为了提高 RTC 的时间精度,可以对其进行校准。STM32F407 的 RTC 提供了校准功能,可以通过设置校准寄存器(RTC_CALR)来调整时钟频率。

5.1 校准原理

RTC 的校准功能是通过在每 256 秒内插入或删除一个时钟脉冲来实现的。校准寄存器(RTC_CALR)的低 7 位(CAL [6:0])用于设置校准值,CAL [6] 为校准方向位,0 表示插入脉冲,1 表示删除脉冲。

5.2 校准代码示例

void RTC_Calibration(int calibration_value)
{// 检查校准值是否在有效范围内if (calibration_value >= -64 && calibration_value <= 63){uint32_t calr_value = 0;if (calibration_value < 0){calr_value |= (1 << 6); // 设置校准方向为删除脉冲calibration_value = -calibration_value;}calr_value |= (calibration_value & 0x3F);HAL_RTCEx_SetCalibrationValue(&hrtc, calr_value);}
}

六、RTC 低功耗模式

在一些对功耗要求较高的应用中,需要将 STM32F407 设置为低功耗模式,同时保证 RTC 正常运行。STM32F407 提供了多种低功耗模式,如睡眠模式、停止模式和待机模式。

6.1 停止模式

停止模式是一种低功耗模式,在该模式下,系统时钟停止运行,但 RTC、备份寄存器和待机电路仍然工作。以下是一个进入停止模式并在闹钟中断唤醒的示例代码:

#include "main.h"
#include "rtc.h"
#include "stdio.h"RTC_HandleTypeDef hrtc;
UART_HandleTypeDef huart1;void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_RTC_Init(void);
static void MX_USART1_UART_Init(void);void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{char buffer[] = "Wake up from Stop mode!\r\n";HAL_UART_Transmit(&huart1, (uint8_t *)buffer, strlen(buffer), HAL_MAX_DELAY);// 重新配置系统时钟SystemClock_Config();
}int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_RTC_Init();MX_USART1_UART_Init();RTC_AlarmTypeDef sAlarm = {0};// 设置闹钟时间为12:32:00sAlarm.AlarmTime.Hours = 12;sAlarm.AlarmTime.Minutes = 32;sAlarm.AlarmTime.Seconds = 0;sAlarm.Alarm = RTC_ALARM_A;HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN);while (1){// 进入停止模式HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);}
}

6.2 待机模式

待机模式是一种功耗最低的模式,在该模式下,所有的寄存器和 SRAM 内容都会被保留,但系统会完全停止运行。RTC 可以作为唤醒源,当闹钟时间到达时,系统会从待机模式中唤醒。以下是一个进入待机模式并在闹钟中断唤醒的示例代码:

#include "main.h"
#include "rtc.h"
#include "stdio.h"RTC_HandleTypeDef hrtc;
UART_HandleTypeDef huart1;void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_RTC_Init(void);
static void MX_USART1_UART_Init(void);void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{char buffer[] = "Wake up from Standby mode!\r\n";HAL_UART_Transmit(&huart1, (uint8_t *)buffer, strlen(buffer), HAL_MAX_DELAY);// 重新初始化所有外设HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_RTC_Init();MX_USART1_UART_Init();
}int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_RTC_Init();MX_USART1_UART_Init();RTC_AlarmTypeDef sAlarm = {0};// 设置闹钟时间为12:33:00sAlarm.AlarmTime.Hours = 12;sAlarm.AlarmTime.Minutes = 33;sAlarm.AlarmTime.Seconds = 0;sAlarm.Alarm = RTC_ALARM_A;HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN);while (1){// 进入待机模式HAL_PWR_EnterSTANDBYMode();}
}

七、常见问题与解决方案

7.1 RTC 时间不准确

  • 原因:时钟源不稳定、温度影响、校准值设置不当等。
  • 解决方案:选择稳定的时钟源(如 LSE),对 RTC 进行校准,尽量减少温度对时钟源的影响。

7.2 RTC 在断电后时间丢失

  • 原因:备用电池没电、VBAT 引脚连接不良等。
  • 解决方案:更换备用电池,检查 VBAT 引脚的连接是否正常。

7.3 闹钟中断不触发

  • 原因:闹钟时间设置错误、中断使能位未设置、中断优先级设置不当等。
  • 解决方案:检查闹钟时间设置是否正确,确保中断使能位已设置,调整中断优先级。

八、总结

本文详细介绍了基于 STM32F407 HAL 库的 RTC 实时时钟的开发过程,包括硬件特性、开发环境搭建、基于 HAL 库的编程、校准、低功耗模式以及常见问题与解决方案等方面的内容。通过本文的学习,读者可以全面掌握 STM32F407 RTC 的开发方法,为开发具有实时时钟功能的嵌入式系统打下坚实的基础。在实际应用中,开发者可以根据具体需求对 RTC 进行灵活配置和使用,以满足不同的应用场景。

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

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

相关文章

vdso概念及原理,vdso_fault缺页异常,vdso符号的获取

一、背景 vdso的全称是Virtual Dynamic Shared Object&#xff0c;它是一个特殊的共享库&#xff0c;是在编译内核时生成&#xff0c;并在内核镜像里某一段地址段作为该共享库的内容。vdso的前身是vsyscall&#xff0c;为了兼容一些旧的程序&#xff0c;x86上还是默认加载了vs…

Linux中的文件传输(附加详细实验案例)

一、实验环境的设置 ①该实验需要两台主机&#xff0c;虚拟机名称为 L2 和 L3 &#xff0c;在终端分别更改主机名为 node1 和 node2&#xff0c;在实验过程能够更好分辨。 然后再重新打开终端&#xff0c;主机名便都更改了相应的名称。 ②用 ip a 的命令分别查看两个主机的 …

【从0到1学Elasticsearch】Elasticsearch从入门到精通(上)

黑马商城作为一个电商项目&#xff0c;商品的搜索肯定是访问频率最高的页面之一。目前搜索功能是基于数据库的模糊搜索来实现的&#xff0c;存在很多问题。 首先&#xff0c;查询效率较低。 由于数据库模糊查询不走索引&#xff0c;在数据量较大的时候&#xff0c;查询性能很差…

图论基础理论

在我看来&#xff0c;想要掌握图的基础应用&#xff0c;仅需要三步走。 什么是图&#xff08;基本概念&#xff09;、图的构造&#xff08;打地基&#xff09;、图的遍历方式&#xff08;应用的基础&#xff09; 只要能OK的掌握这三步、就算图论入门了&#xff01;&#xff0…

详细解读react框架中的hooks

React Hooks 是 React 16.8 引入的一项革命性特性&#xff0c;它允许你在函数组件中使用状态(state)和其他 React 特性&#xff0c;而无需编写 class 组件。下面将详细解读 React Hooks 的核心概念、常用 Hooks 及其工作原理。 一、Hooks 的核心概念 1. 什么是 Hooks Hooks …

主机IP动态变化时如何通过固定host.docker.internal访问本机服务

场景需求——主机IP动态变化时&#xff0c;通过固定的 http://host.docker.internal:11555 访问本机服务&#xff0c;核心问题在于 host.docker.internal 的解析逻辑与动态IP的适配。以下是分步解决方案&#xff1a; 一、核心原理&#xff1a;host.docker.internal 的本质与局…

插值算法 - 最近邻插值实现

目录 1. 导入必要的库 2. nearest_neighbor_interpolation 3. 测试代码 数学原理 完整代码 本文实现了基于最近邻插值算法的图像缩放功能。 它使用 Python 编写,主要依赖于NumPy和PIL(Python Imaging Library)库。 NumPy用于高效的数值计算,而PIL仅用于图像的加载和…

windows中搭建Ubuntu子系统

windows中搭建虚拟环境 1.配置2.windows中搭建Ubuntu子系统2.1windows配置2.1.1 确认启用私有化2.1.2 将wsl2设置为默认版本2.1.3 确认开启相关配置2.1.4重启windows以加载更改配置 2.2 搭建Ubuntu子系统2.2.1 下载Ubuntu2.2.2 迁移位置 3.Ubuntu子系统搭建docker环境3.1安装do…

MySQL事务机制

目录 原子性 持久性 隔离性 隔离级别(并发事务之间的关系) 读未提交 读已提交 可重复读 串行化(最严格的隔离级别) 一致性 问题 不可重复读性(已经提交的数据) 什么是脏读问题(未提交的数据)? 幻读 保存点 自动提交机制--autocommit 会话隔离级别与全局隔离级…

Cadence学习笔记之---直插元件的封装制作

目录 01 | 引 言 02 | 环境描述 03 | 操作步骤 04 | 结 语 01 | 引 言 在之前发布的Cadence小记中&#xff0c;已经讲述了怎样制作热风焊盘&#xff0c;贴片(SMD)焊盘、通孔、过孔&#xff0c;以及贴片元件的封装。 本篇关于Cadence的小记主要讲如何制作直插元件的封装。 …

【第四十周】文献阅读:用于检索-增强大语言模型的查询与重写

目录 摘要Abstract用于检索-增强大语言模型的查询与重写研究背景方法论基于冻结LLM的重写方案基于可训练重写器的方案重写器预热训练&#xff08;Rewriter Warm-up&#xff09;强化学习&#xff08;Reinforcement Learning&#xff09; 创新性实验结果局限性总结 摘要 这篇论文…

java学习总结(if switch for)

一.基本结构 1.单分支if int num 10; if (num > 5) {System.out.println("num 大于 5"); } 2.双分支if-else int score 60; if (score > 60) {System.out.println("及格"); } else {System.out.println("不及格"); } 3.多分支 int…

yum的基本操作和vim指令

在我们的手机端或者Windows上下载软件&#xff0c;可以在相应的应用商店或者官网进行下载&#xff0c;这样对于用户来说十分的方便和便捷。而在Linux上&#xff0c;也有类似的安装方式&#xff0c;我们来一一了解一下。 Linux安装软件的3种方法 源代码安装 在Linux下安装软件…

C++ CUDA开发入门

CUDA开发笔记 文章目录 CUDA开发笔记[toc]1 概述2 环境3 命令行编译4 CMAKE引入CUDA5 vscode开发CUDA6 Qt中使用CUDA-CMake7 QMake配置CUDA8 核函数9 核函数调用9.1 核函数调用语法9.2 执行配置参数详解9.3 关键调用步骤9.4 重要注意事项9.5 调用示例分析9.6 最佳实践建议 10 线…

llm开发框架新秀

原文链接:https://i68.ltd/notes/posts/20250404-llm-framework3/ google开源ADK-Agent Development Kit 开源的、代码优先的 Python 工具包&#xff0c;用于构建、评估和部署具有灵活性和控制力的复杂智能体项目仓库:https://github.com/google/adk-python 2.6k项目文档:Age…

VM——相机拍照失败

1、问题&#xff1a;相机频闪触发&#xff0c;在MVS中正常出图&#xff0c;在VM中出现拍照失败 2、解决&#xff1a; 1、首先排查网络设置&#xff08;巨帧是否设置&#xff09; 2、电脑的所有防火墙是否关闭 3、在MVS中恢复相机的设置参数为默认参数&#xff0c;删除VM中的全…

【时频谱分析】小波分析

算法配置页面&#xff0c;也可以一键导出结果数据 报表自定义绘制 获取和下载【PHM学习软件PHM源码】的方式 获取方式&#xff1a;Docshttps://jcn362s9p4t8.feishu.cn/wiki/A0NXwPxY3ie1cGkOy08cru6vnvc

怎么免费下载GLTF/GLB格式模型文件,还可以在线编辑修改

​ 现在非常流行glb格式模型&#xff0c;和gltf格式文件&#xff0c;可是之类模型网站非常非常少 1&#xff0c;咱们先直接打开http://glbxz.com 官方glb下载网站 glbxz.com 2 可以搜索&#xff0c;自己想要的模型关键词 3&#xff0c;到自己想下载素材页面 4&#xff0c;…

【6】深入学习http模块(万字)-Nodejs开发入门

深入学习http模块 前言http一个Web服务器项目创建代码运行代码解析 Server属性&#xff1a;keepAlive属性&#xff1a;keepAliveTimeout属性&#xff1a;maxHeaderSize属性&#xff1a;requestTimeout属性&#xff1a;maxRequestsPerSocket方法&#xff1a;close()方法&#xf…

buuctf sql注入类练习

BUU SQL COURSE 1 1 实例无法访问 / Instance cant be reached at that time | BUUCTF但是这个地方很迷惑就是这个 一个 # 我们不抓包就不知道这个是sql注入类的判断是 get 类型的sql注入直接使用sqlmap我们放入到1.txt中 目的是 优先检测 ?id1>python3 sqlmap.py -r 1.t…