STM32 HAL 之 RTC

本文详细介绍了使用STM32CubeIDE和HAL库函数操作STM32的RTC实时时钟模块,包括如何设置时间、日期以及配置定时闹钟中断,为开发者提供了一个全面的STM32 RTC应用指南。

https://blog.youkuaiyun.com/as480133937/article/details/105741893
【STM32】HAL库 STM32CubeMX教程十三—RTC时钟
在这里插入图片描述
STM32CubeIDE HAL库函数操作RTC实时时钟 及 定时闹钟中断
https://blog.youkuaiyun.com/u010779035/article/details/104161684?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
在这里插入图片描述

<think>我们正在分析STM32 HAL库中的RTC代码。根据用户提供的引用,我们可以知道: 1. 引用[1]提到了在没有使用STM32CubeMX的情况下如何手动添加RTC模块相关的HAL库文件,并启用宏定义。 2. 引用[2]介绍了STM32F407 HAL库的RTC开发过程,包括硬件特性、编程、校准等。 3. 引用[3]提到了一个具体函数`HAL_RTC_GetTime`,该函数用于获取RTC时间。 用户的需求是:对stm32 hal库中的RTC代码进行详细分析。 因此,我们需要围绕HAL库中RTC模块的代码进行分析,包括初始化、时间设置与获取、日期设置与获取、闹钟设置、低功耗处理等。 由于HAL库的RTC代码较长,我们不可能逐行分析,但我们可以分析其主要结构和关键函数。 ### STM32 HALRTC模块代码分析 #### 1. RTC初始化 RTC初始化主要包括以下步骤: - 配置RTC时钟源(通常使用LSE或LSI)。 - 设置RTC预分频器以得到1Hz的时钟。 - 初始化RTC外设。 在HAL库中,主要函数为`HAL_RTC_Init`。该函数会调用`HAL_RTC_MspInit`(用户需要实现此函数以配置底层硬件,如时钟和NVIC)和`RTC_Init`(配置RTC预分频器和时钟格式)。 ```c HAL_StatusTypeDef HAL_RTC_Init(RTC_HandleTypeDef *hrtc) { // ... 检查参数 if (hrtc->State == HAL_RTC_STATE_RESET) { hrtc->Lock = HAL_UNLOCKED; HAL_RTC_MspInit(hrtc); } // 进入初始化模式 if (RTC_EnterInitMode(hrtc) != HAL_OK) { return HAL_ERROR; } // 设置预分频器 MODIFY_REG(hrtc->Instance->PRER, RTC_PRER_PREDIV_A, hrtc->Init.AsynchPrediv); MODIFY_REG(hrtc->Instance->PRER, (RTC_PRER_PREDIV_S | RTC_PRER_PREDIV_A), (hrtc->Init.SynchPrediv | hrtc->Init.AsynchPrediv)); // 设置时间格式(12小时/24小时) MODIFY_REG(hrtc->Instance->CR, RTC_CR_FMT, hrtc->Init.HourFormat); // 退出初始化模式 RTC_ExitInitMode(hrtc); // 其他配置... return HAL_OK; } ``` 用户需要实现的`HAL_RTC_MspInit`函数示例: ```c void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; // 配置LSE为RTC时钟源 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE; RCC_OscInitStruct.LSEState = RCC_LSE_ON; HAL_RCC_OscConfig(&RCC_OscInitStruct); PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC; PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); // 使能RTC时钟 __HAL_RCC_RTC_ENABLE(); // 设置RTC中断优先级并使能中断 HAL_NVIC_SetPriority(RTC_IRQn, 0, 0); HAL_NVIC_EnableIRQ(RTC_IRQn); } ``` #### 2. 设置和获取时间与日期 设置时间和日期的函数分别为`HAL_RTC_SetTime`和`HAL_RTC_SetDate`,获取时间和日期的函数分别为`HAL_RTC_GetTime`和`HAL_RTC_GetDate`。 注意:为了确保读取的时间/日期的一致性,通常需要连续读取两次时间(或日期)并比较,直到连续两次读取的值相同。这是因为在读取过程中,RTC寄存器可能正在更新(秒进位)。 以`HAL_RTC_GetTime`为例: ```c HAL_StatusTypeDef HAL_RTC_GetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format) { uint32_t tmp; // 读取时间寄存器 tmp = (uint32_t)(hrtc->Instance->TR & RTC_TR_RESERVED_MASK); sTime->Hours = (uint8_t)((tmp & (RTC_TR_HT | RTC_TR_HU)) >> 16); sTime->Minutes = (uint8_t)((tmp & (RTC_TR_MNT | RTC_TR_MNU)) >> 8); sTime->Seconds = (uint8_t)(tmp & (RTC_TR_ST | RTC_TR_SU)); sTime->TimeFormat = (uint8_t)((tmp & (RTC_TR_PM)) >> 16); // 如果是12小时制,需要转换 if (Format == RTC_FORMAT_BIN) { sTime->Hours = (uint8_t)RTC_Bcd2ToByte(sTime->Hours); sTime->Minutes = (uint8_t)RTC_Bcd2ToByte(sTime->Minutes); sTime->Seconds = (uint8_t)RTC_Bcd2ToByte(sTime->Seconds); } return HAL_OK; } ``` 实际使用中,为了确保读取正确,通常需要连续读取两次直到相同: ```c RTC_DateTypeDef date1, date2; RTC_TimeTypeDef time1, time2; do { HAL_RTC_GetTime(&hrtc, &time1, RTC_FORMAT_BIN); HAL_RTC_GetDate(&hrtc, &date1, RTC_FORMAT_BIN); HAL_RTC_GetTime(&hrtc, &time2, RTC_FORMAT_BIN); HAL_RTC_GetDate(&hrtc, &date2, RTC_FORMAT_BIN); } while (time1.Seconds != time2.Seconds || date1.Date != date2.Date); ``` #### 3. RTC闹钟 设置闹钟的函数为`HAL_RTC_SetAlarm`。闹钟可以设置成按秒、分、时、日、星期等匹配时触发中断。 #### 4. RTC校准 RTC的校准可以通过配置校准寄存器(如RTC_CALR)来实现,HAL库提供了`HAL_RTC_SetSmoothCalib`函数用于平滑校准。 #### 5. 低功耗模式 RTC在低功耗模式下(如Stop或Standby模式)仍然可以运行。在进入低功耗模式前,需要配置RTC唤醒源(如闹钟或周期性唤醒)。HAL库中,唤醒后需要重新初始化RTC时钟(因为时钟可能从停止模式恢复)。 #### 6. 常见问题 - 时间/日期读取不一致:如上所述,需要连续读取两次。 - RTC初始化失败:检查时钟源是否正常(LSE起振较慢,可能需要等待)。 - 备份域写保护:在修改RTC配置或备份寄存器前,需要先关闭写保护(`__HAL_RTC_WRITEPROTECTION_DISABLE`),修改后再使能写保护。 ### 总结 对STM32 HAL库中RTC代码的分析主要围绕初始化、时间日期操作、闹钟、校准和低功耗处理等。用户需要关注的是: - 正确配置RTC时钟源(通过CubeMX或手动配置)。 - 理解并正确使用HAL库提供的函数,特别是时间日期的读取需要连续两次以确保一致性。 - 注意备份域写保护的处理。 [^1]: Stm32HalRTC模块学习笔记 [^2]: STM32 HALRTC实时时钟超细详解 [^3]: STM32 HALRTC CubeMX生成不丢日期问题更新 §§相关问题§§ 1. STM32 HAL库中RTC的时钟源如何选择和配置? 2. 如何解决STM32 HALRTC读取时间日期不一致的问题? 3. STM32 RTC的闹钟功能如何使用? 4. STM32 RTC在低功耗模式下的使用注意事项有哪些? </think>### STM32 HALRTC模块代码详细分析 #### 1. **RTC初始化流程** 在HAL库中,RTC初始化主要通过`HAL_RTC_Init()`函数实现: ```c HAL_StatusTypeDef HAL_RTC_Init(RTC_HandleTypeDef *hrtc) { // 1. 检查时钟源配置(LSE/LSI) if (hrtc->Instance == RTC) { if (__HAL_RCC_GET_RTC_SOURCE() == RCC_RTCCLKSOURCE_NO_CLK) { return HAL_ERROR; // 时钟源未配置 } } // 2. 进入初始化模式 if (RTC_EnterInitMode(hrtc) != HAL_OK) { return HAL_ERROR; } // 3. 配置预分频器 hrtc->Instance->PRER = (uint32_t)(hrtc->Init.SynchPrediv); hrtc->Instance->PRER |= (uint32_t)(hrtc->Init.AsynchPrediv << 16); // 4. 设置时间格式(12/24小时制) MODIFY_REG(hrtc->Instance->CR, RTC_CR_FMT, hrtc->Init.HourFormat); // 5. 退出初始化模式 RTC_ExitInitMode(hrtc); return HAL_OK; } ``` **关键点**: - 需手动配置`RCC`时钟源(通过`__HAL_RCC_RTC_ENABLE()`) - 预分频器决定计时精度:$f_{\text{RTC}} = \frac{f_{\text{source}}}{(AsynchPrediv+1) \times (SynchPrediv+1)}$ - 需在`stm32f1xx_hal_conf.h`中启用宏`HAL_RTC_MODULE_ENABLED`[^1] --- #### 2. **时间读写机制** 时间读取通过`HAL_RTC_GetTime()`实现: ```c HAL_StatusTypeDef HAL_RTC_GetTime( RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format ) { uint32_t tmpreg = hrtc->Instance->TR; // 读取时间寄存器 // 解析时分秒(BCD格式) sTime->Hours = (uint8_t)((tmpreg & (RTC_TR_HT | RTC_TR_HU)) >> 16); sTime->Minutes = (uint8_t)((tmpreg & (RTC_TR_MNT | RTC_TR_MNU)) >> 8); sTime->Seconds = (uint8_t)(tmpreg & (RTC_TR_ST | RTC_TR_SU)); // 格式转换 if (Format == RTC_FORMAT_BIN) { sTime->Hours = RTC_Bcd2ToByte(sTime->Hours); sTime->Minutes = RTC_Bcd2ToByte(sTime->Minutes); sTime->Seconds = RTC_Bcd2ToByte(sTime->Seconds); } return HAL_OK; } ``` **重要特性**: - 采用BCD编码存储时间(节约寄存器空间) - 读取时需连续调用两次以避免"秒进位"导致的数据不一致[^3] - 写操作需先进入初始化模式(`RTC_EnterInitMode()`) --- #### 3. **后备域处理** ```c // 解除写保护 HAL_PWR_EnableBkUpAccess(); __HAL_RCC_BACKUPRESET_FORCE(); __HAL_RCC_BACKUPRESET_RELEASE(); // 启用后备寄存器 __HAL_RCC_PWR_CLK_ENABLE(); PWR->CR |= PWR_CR_DBP; ``` **注意事项**: - VBAT引脚需接备用电池(维持RTC计数) - 复位后需重新启用后备域访问权限 - 后备寄存器(`RTC_BKPxR`)可用于存储用户数据 --- #### 4. **校准与低功耗** - **校准机制**: 通过`RTC_CALR`寄存器补偿晶振误差,公式: $$ \Delta t = \frac{CALP \times 32768 + CALM}{131072} \text{ (秒/分钟)} $$ - **低功耗模式**: ```c // 配置唤醒时钟 HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 0x1000, RTC_WAKEUPCLOCK_RTCCLK_DIV16); // 进入Stop模式 HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); ``` --- #### 5. **常见问题解决** 1. **时间丢失问题**: - 检查VBAT电池电压(需>2.0V) - 验证后备域是否成功初始化 ```c if (__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST)) { // 发生掉电复位,需重新初始化RTC } ``` 2. **CubeMX生成代码优化**: - 在`rtc.c`中启用`RTC_ASYNCH_PREDIV`和`RTC_SYNCH_PREDIV`预分频 - 添加时间连续读取逻辑[^3] [^1]: Stm32HalRTC模块学习笔记 [^2]: STM32 HALRTC实时时钟超细详解 [^3]: STM32 HALRTC CubeMX生成不丢日期问题更新
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值