一、引言
STM32 微控制器的实时时钟(RTC)功能在许多应用中都非常重要,它允许设备保持精确的时间和日期信息,即使在系统断电或复位后,只要有备用电源(如锂电池)为 RTC 供电,就能继续运行。这对于需要时间戳、定时任务、日历功能以及其他需要精确时间信息的应用程序来说是必不可少的,例如数据记录系统、定时控制、事件调度等。
二、STM32 RTC 概述
STM32 的 RTC 模块通常由一组时钟源、预分频器、计数器和闹钟寄存器组成。时钟源可以来自外部的 32.768kHz 晶体振荡器(LSE),内部低速时钟(LSI)或高速时钟(HSE)经过分频得到。为了保证时间的精确性,通常使用外部的 32.768kHz 晶体振荡器作为 RTC 的时钟源,因为其频率可以方便地产生精确的 1 秒计时信号。
RTC 模块可以工作在日历模式和闹钟模式下。在日历模式下,它可以提供年、月、日、时、分、秒等时间信息;在闹钟模式下,当达到设定的闹钟时间时,可以触发中断,用于唤醒系统或执行特定的任务。
三、硬件连接
对于使用外部 32.768kHz 晶体振荡器的情况,需要将晶体连接到 STM32 的 RTC 专用引脚。通常,这涉及到连接一个 32.768kHz 的晶振和两个匹配电容到相应的 OSC32_IN 和 OSC32_OUT 引脚。确保电容的容值选择合适,以保证晶体能够稳定起振。
四、STM32 软件实现
以下是一个使用 STM32 的 HAL 库实现 RTC 功能的代码示例:
#include "stm32f4xx_hal.h"
// 定义 RTC 句柄
RTC_HandleTypeDef hrtc;
// RTC 初始化函数
void MX_RTC_Init(void)
{
// 使能电源接口时钟
__HAL_RCC_PWR_CLK_ENABLE();
// 使能后备寄存器访问
HAL_PWR_EnableBatteryBackUpAccess();
// 配置 RTC 时钟源为 LSE
hrtc.Instance = RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 127;
hrtc.Init.SynchPrediv = 255;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
if (HAL_RTC_Init(&hrtc)!= HAL_OK)
{
Error_Handler();
}
}
// 错误处理函数
void Error_Handler(void)
{
while(1);
}
// 设置 RTC 时间
void RTC_SetTime(uint8_t hours, uint8_t minutes, uint8_t seconds)
{
RTC_TimeTypeDef sTime = {0};
sTime.Hours = hours;
sTime.Minutes = minutes;
sTime.Seconds = seconds;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN)!= HAL_OK)
{
Error_Handler();
}
}
// 获取 RTC 时间
void RTC_GetTime(RTC_TimeTypeDef *sTime)
{
if (HAL_RTC_GetTime(&hrtc, sTime, RTC_FORMAT_BIN)!= HAL_OK)
{
Error_Handler();
}
}
// 设置 RTC 日期
void RTC_SetDate(uint8_t year, uint8_t month, uint8_t date)
{
RTC_DateTypeDef sDate = {0};
sDate.Year = year;
sDate.Month = month;
sDate.Date = date;
sDate.WeekDay = RTC_WEEKDAY_MONDAY;
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN)!= HAL_OK)
{
Error_Handler();
}
}
// 获取 RTC 日期
void RTC_GetDate(RTC_DateTypeDef *sDate)
{
if (HAL_RTC_GetDate(&hrtc, sDate, RTC_FORMAT_BIN)!= HAL_OK)
{
Error_Handler();
}
}
int main(void)
{
HAL_Init();
// 配置系统时钟
SystemClock_Config();
// 初始化 RTC
MX_RTC_Init();
// 设置初始时间
RTC_SetTime(12, 0, 0);
RTC_SetDate(21, 1, 16);
while (1)
{
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
// 获取当前时间和日期
RTC_GetTime(&sTime);
RTC_GetDate(&sDate);
// 在这里可以对获取的时间和日期进行处理,例如通过串口输出或显示在 LCD 上
// 示例:
// printf("Current Time: %02d:%02d:%02d\n", sTime.Hours, sTime.Minutes, sTime.Seconds);
// printf("Current Date: %02d/%02d/%02d\n", sDate.Date, sDate.Month, sDate.Year);
// 延时一段时间,避免频繁读取
HAL_Delay(1000);
}
}
代码解释:
stm32f4xx_hal.h
是 STM32 的 HAL 库头文件,提供了初始化和操作 STM32 各种硬件的函数和定义。RTC_HandleTypeDef hrtc;
用于管理和操作 RTC 模块。MX_RTC_Init()
函数首先使能电源接口时钟,以便访问后备寄存器,因为 RTC 属于后备域。然后,它配置 RTC 的参数,包括 24 小时格式、异步和同步预分频器的值。最后,使用 HAL_RTC_Init()
函数完成初始化。Error_Handler()
函数在出现错误时进入无限循环,方便调试和故障排查。RTC_SetTime()
和 RTC_SetDate()
函数分别用于设置 RTC 的时间和日期。它们接收相应的时间和日期参数,填充 RTC_TimeTypeDef
和 RTC_DateTypeDef
结构体,然后使用 HAL_RTC_SetTime()
和 HAL_RTC_SetDate()
函数将其写入 RTC 寄存器。RTC_GetTime()
和 RTC_GetDate()
函数分别用于从 RTC 读取时间和日期信息,将结果存储在相应的结构体中。main()
函数中,首先初始化 HAL 库和系统时钟,然后初始化 RTC 并设置初始时间和日期。接着进入一个无限循环,在循环中不断读取 RTC 的时间和日期信息,并可以将这些信息进行处理,如通过串口输出或显示在 LCD 上。这里使用 HAL_Delay(1000)
实现每秒读取一次时间,避免过于频繁的读取操作。五、RTC 闹钟功能
除了基本的时间和日期功能,RTC 还可以设置闹钟。以下是一个简单的闹钟设置示例:
// 设置 RTC 闹钟
void RTC_SetAlarm(uint8_t hours, uint8_t minutes, uint8_t seconds)
{
RTC_AlarmTypeDef sAlarm = {0};
sAlarm.AlarmTime.Hours = hours;
sAlarm.AlarmTime.Minutes = minutes;
sAlarm.AlarmTime.Seconds = seconds;
sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY;
sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
sAlarm.Alarm = RTC_ALARM_A;
if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN)!= HAL_OK)
{
Error_Handler();
}
}
// RTC 闹钟中断处理函数
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
// 在此处处理闹钟触发事件,例如唤醒系统或执行特定任务
// 可以通过清除相应的闹钟标志位来避免重复触发
__HAL_RTC_ALARM_CLEAR_FLAG(hrtc, RTC_FLAG_ALRAF);
}
代码解释:
RTC_SetAlarm()
函数用于设置闹钟时间,通过填充 RTC_AlarmTypeDef
结构体,并使用 HAL_RTC_SetAlarm_IT()
函数设置闹钟并启用中断。HAL_RTC_AlarmAEventCallback()
函数是闹钟 A 的中断处理函数,当闹钟触发时,会调用该函数。在该函数中可以执行所需的操作,如唤醒系统或执行特定任务,并清除相应的闹钟标志位,避免重复触发。六、注意事项
RTC_FORMAT_BIN
表示使用二进制格式存储和读取数据,避免混淆。七、总结
STM32 的 RTC 功能为我们提供了一个可靠且精确的时间和日期管理工具。通过合理的硬件连接和正确的软件编程,我们可以方便地实现时间的读取、设置以及闹钟功能。在不同的 STM32 型号中,RTC 的具体实现细节可能会有细微差别,但基本的操作流程和原理是相似的。在开发过程中,需要仔细阅读芯片手册,根据具体的芯片资源和需求来调整代码和配置,以满足不同应用的时间管理需求。
上述代码只是一个基础示例,在实际应用中,可以根据具体的项目需求进行扩展和优化,例如添加更多的时间处理功能、处理不同的中断源、实现更复杂的定时任务等。
✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进
❤欢迎关注我的知乎:对error视而不见
代码获取、问题探讨及文章转载可私信。
☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。
获取更多嵌入式资料可点击链接进群领取,谢谢支持!
点击领取更多详细资料