简介
RTC(Real-Time Clock,实时时钟)是单片机中用于提供精确时间计时的外设,广泛应用于需要时间记录、定时任务、日历功能等场景。STM32F407 系列芯片集成了一个独立的 RTC 模块,具有独立的 32.768kHz 低速振荡器(LSE),支持年、月、日、星期、时、分、秒的计时功能,并具有闹钟、周期性唤醒、时间戳等功能。本文从 RTC 的基本原理出发,详细讲解 STM32F407 RTC 的配置方法、代码实现、时间管理以及实际应用案例,帮助你快速掌握 RTC 的使用技巧。
一、RTC核心概念与分类
1.1 基本概念
RTC 是一个独立的 BCD 计数器,用于提供日历和时钟功能,其主要特点包括:
- 独立电源:RTC 具有独立的电源域(VBAT),在主电源断电时仍可正常工作
- 低功耗:RTC 在待机模式下仍可正常工作,功耗极低
- 高精度:支持外部 32.768kHz 晶振,计时精度高
- 多种功能:支持闹钟、周期性唤醒、时间戳、校准等功能
- BCD 码格式:时间数据以 BCD 码格式存储
关键参数:
- 时钟源:可选择 LSE(32.768kHz)、LSI(约32kHz)或 HSE 分频
- 预分频系数:用于将时钟源分频为 1Hz 的秒信号
- 时间格式:支持 12 小时制和 24 小时制
- 夏令时:支持夏令时调整
1.2 STM32F407 的 RTC 资源
STM32F407 系列芯片集成了 1 个 RTC 模块:
| 功能 | 特性 |
|---|---|
| 时钟源 | LSE(32.768kHz)、LSI(约32kHz)、HSE 分频 |
| 预分频 | 异步预分频(7位)+ 同步预分频(15位) |
| 时间格式 | 12 小时制或 24 小时制 |
| 闹钟 | 2 个可编程闹钟(闹钟A、闹钟B) |
| 周期性唤醒 | 可编程的周期性唤醒中断 |
| 时间戳 | 2 个时间戳(入侵时间戳、内部时间戳) |
| 校准 | 数字校准功能,可调整 RTC 频率 |
| 备份寄存器 | 32 个 32 位备份寄存器 |
关键特性:
- 支持 BCD 码格式的时间存储
- 支持闰年自动计算
- 支持夏令时调整
- 支持入侵检测
- 支持时间戳功能
- 支持数字校准
二、RTC工作原理
2.1 时钟源与预分频
RTC 的时钟源有三种选择:
LSE(Low Speed External,低速外部晶振):
- 频率:32.768kHz
- 精度:高,取决于外部晶振
- 适用场景:需要高精度计时的应用
LSI(Low Speed Internal,低速内部振荡器):
- 频率:约 32kHz
- 精度:较低,受温度和电压影响
- 适用场景:对精度要求不高的应用
HSE 分频:
- 频率:HSE 时钟分频后得到
- 精度:高,取决于外部晶振
- 适用场景:需要高精度计时的应用
预分频:
RTC 的预分频分为两级:
- 异步预分频:7 位,用于将时钟源分频为 1Hz 的秒信号
- 同步预分频:15 位,用于进一步分频
示例:使用 LSE(32.768kHz)作为时钟源
- 异步预分频系数:127(0x7F)
- 同步预分频系数:255(0xFF)
- 分频后频率:32768 / (127 + 1) / (255 + 1) = 1Hz
2.2 时间寄存器
RTC 的时间寄存器以 BCD 码格式存储时间信息:
RTC_TR(时间寄存器):
- 秒(SEC):6 位,BCD 码,范围 00-59
- 分(MIN):7 位,BCD 码,范围 00-59
- 时(HOUR):6 位,BCD 码,范围 00-23(24 小时制)或 01-12(12 小时制)
- AM/PM(PM):1 位,12 小时制时有效,0 为 AM,1 为 PM
RTC_DR(日期寄存器):
- 年(YR):7 位,BCD 码,范围 00-99
- 月(MTH):5 位,BCD 码,范围 01-12
- 日(DU):6 位,BCD 码,范围 01-31
- 星期(WDU):3 位,范围 1-7(1 为星期一)
2.3 闹钟功能
RTC 支持 2 个可编程闹钟(闹钟A、闹钟B):
闹钟配置:
- 闹钟时间:时、分、秒
- 闹钟日期:日、星期
- 闹钟掩码:可配置闹钟的匹配条件
闹钟触发:
- 当 RTC 时间与闹钟时间匹配时,触发闹钟中断
- 可配置闹钟中断为周期性触发或单次触发
三、RTC配置与代码实现
3.1 标准库配置步骤
使用标准库配置 RTC 的基本步骤:
- 使能 PWR 时钟和 RTC 时钟
- 使能访问备份寄存器
- 配置 RTC 时钟源
- 配置 RTC 预分频系数
- 配置 RTC 时间和日期
- 使能 RTC
- 配置中断(可选)
3.2 代码实现(RTC,LSE 时钟源)
#include"stm32f4xx.h"#include<stdio.h>/** * @brief 初始化RTC * @param 无 * @retval 成功返回0,失败返回1 */uint8_tRTC_Init(void){RTC_InitTypeDef RTC_InitStructure;RTC_TimeTypeDef RTC_TimeStructure;RTC_DateTypeDef RTC_DateStructure;// 1. 使能时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_RTC,ENABLE);// 2. 使能访问备份寄存器PWR_BackupAccessCmd(ENABLE);// 3. 检查RTC是否已经初始化if(RTC_ReadBackupRegister(RTC_BKP_DR0)!=0x5A5A){// 4. 复位RTCRCC_BackupResetCmd(ENABLE);RCC_BackupResetCmd(DISABLE);// 5. 使能LSERCC_LSEConfig(RCC_LSE_ON);while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET);// 6. 配置RTC时钟源为LSERCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);// 7. 使能RTC时钟RCC_RTCCLKCmd(ENABLE);// 8. 等待RTC同步RTC_WaitForSynchro();// 9. 配置RTC预分频系数RTC_InitStructure.RTC_HourFormat=RTC_HourFormat_24;RTC_InitStructure.RTC_AsynchPrediv=127;// 异步预分频系数RTC_InitStructure.RTC_SynchPrediv=255;// 同步预分频系数RTC_Init(&RTC_InitStructure);// 10. 配置RTC时间(默认时间:12:00:00)RTC_TimeStructure.RTC_Hours=12;RTC_TimeStructure.RTC_Minutes=0;RTC_TimeStructure.RTC_Seconds=0;RTC_TimeStructure.RTC_H12=RTC_H12_AM;RTC_SetTime(RTC_Format_BIN,&RTC_TimeStructure);// 11. 配置RTC日期(默认日期:2024-01-01,星期一)RTC_DateStructure.RTC_Year=