一、时钟树:时钟源、锁相环
(1)时钟源
(2)锁相环:
将低频时钟源(如HSE/HSI)倍频至更高频率,生成系统主时钟(SYSCLK)
RCC_PLLConfig(RCC_PLLSource_HSE, RCC_PLLMul_9); // HSE=8MHz ×9 → SYSCLK=72MHz
(3)时钟树配置关键点:
优先级:HSE > HSI(HSE故障时自动切换至HSI)。
外设时钟分配:
-
APB1(低速总线):最大36 MHz(如定时器TIM2-TIM7)。
-
APB2(高速总线):最大72 MHz(如GPIO、SPI1)。
二、RTC实时时钟
(1)RTC的时钟源选择(LSE/LSI):任选一个接到RTCCLK
LSE(推荐):
精度高(月误差约±1秒),需外接32.768 kHz晶振。
典型应用:需要精准计时的场景(如电子表、数据记录),如计时、日志记录等。
LSI(备用):
精度低(误差可达±5%),无需外部元件,40kHz。
适用场景:成本敏感且对时间精度要求不高的设备,简单的定时器、看门狗定时。
HSE时钟除以128:
通常为8MHz/128
(2)RTC掉电时间保持机制
-
BKP寄存器(Backup Registers):
-
特殊寄存器,由后备电源(VBAT)供电,主电源断开后数据不丢失。
-
功能:保存RTC配置和计数器值。
-
-
RTC掉电时间保持机制
-
BKP寄存器(Backup Registers):
特殊寄存器,由后备电源(VBAT)供电,主电源断开后数据不丢失。
功能:保存RTC配置和计数器值
-
后备电源(VBAT):
-
连接纽扣电池(如CR2032)至VBAT引脚,确保RTC和BKP寄存器在断电时持续供电。
-
-
(3)RTC操作事项
-
执行以下操作将使能对BKP和RTO的访问:
设置RCC_APB1ENR的PWREN和BKPEN,使能PWR和BKP时钟
设置PWR_CR的DBP使能对BKP和RTC的访问
-
若在读取RTC寄存器时,RTC的APB1接口曾经处于禁止状态,则软件首先必须等待RTC_CRL寄存器中的RSF位(寄存器同步标志)被硬件置1
-
必须设置RTC_CRL寄存器中的CNP位,使RTC进入配置模式后,才能写入RTC_PRL、RTC_CNT、RTC_ALR寄存器
-
对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。可以查询RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。仅当RTOFF状态位是1时,才可以写入RTC寄存器
三.Unix时间戳
从1970年1月1日00:00:00 UTC至今的秒数
-
时间戳存储在一个秒计数器中,秒计数器位32位/64位的整型变量(32位整数,2038年溢出)
-
世界上所有时区秒计数器相同,不同时区通过添加偏移来得到当地时间
-
Unix时间戳基于UTC,需根据本地时区调整(如东八区:
unix_time += 8*3600
) -
Unix时间戳与RTC时间的转换(闰年、时区处理)
// RTC时间(年月日时分秒)转Unix时间戳
uint32_t rtc_to_unix(RTC_DateTypeDef date, RTC_TimeTypeDef time) {
struct tm t;
t.tm_year = date.Year + 100; // tm_year=实际年份-1900(RTC Year从2000开始)
t.tm_mon = date.Month - 1; // tm_mon=0~11
t.tm_mday = date.Date;
t.tm_hour = time.Hours;
t.tm_min = time.Minutes;
t.tm_sec = time.Seconds;
return mktime(&t) - timezone * 3600; // 校正时区
}
// Unix时间戳转RTC时间
void unix_to_rtc(uint32_t unix_time, RTC_DateTypeDef *date, RTC_TimeTypeDef *time) {
struct tm *t = gmtime(&unix_time); // 使用UTC时间
date->Year = t->tm_year - 100; // RTC Year从2000开始
date->Month = t->tm_mon + 1;
date->Date = t->tm_mday;
time->Hours = t->tm_hour;
time->Minutes = t->tm_min;
time->Seconds = t->tm_sec;
}
四、常见问题
1.RTC如何实现掉电时间保持(BKP寄存器的作用)?
-
BKP寄存器:存储RTC计数器值和配置,由VBAT供电,主电源断开后数据保留。
-
后备电源(VBAT):连接纽扣电池至VBAT引脚,确保RTC和BKP持续工作。
-
在系统初始化时,会对 RTC 进行配置并启动计时。RTC 的计时数据(如年、月、日、时、分、秒)会不断更新,同时可以将这些数据存储到 BKP 寄存器中。当主电源掉电时,备份域的电源继续为 RTC 和 BKP 寄存器供电,RTC 继续计时,BKP 寄存器中的数据也得以保存。当主电源恢复后,系统可以从 BKP 寄存器中读取之前保存的时间数据,继续进行时间的显示和处理。
// 初始化RTC并启用BKP HAL_PWR_EnableBkUpAccess(); __HAL_RCC_BKP_CLK_ENABLE();
2.Unix时间戳溢出问题(2038年问题)如何解决?
-
升级到64位时间戳:64位整数可表示时间至约2920亿年后。
-
使用无符号32位整数:延后溢出时间至2106年,但需系统支持。
-
采用新的时间标准:可以考虑采用新的时间标准来替代 Unix 时间戳,例如 ISO 8601 标准,它使用字符串来表示日期和时间,不存在溢出问题,并且具有更好的可读性和跨平台兼容性。