嵌入式-RTC实时时钟-知识卡片

发布时间:2026/7/19 9:33:21
嵌入式-RTC实时时钟-知识卡片 RTC 实时时钟 —— STM32 知识卡片⏰ 一句话RTC 是一个独立于 CPU 的定时器通过 32 位秒计数器实现 Unix 时间戳计时。系统复位不清零VDD 断电后由 VBAT 备用电池继续走时。可配置闹钟触发中断或唤醒待机模式。核心要点后备区域Backup DomainRTC BKP 在后备区域VDD 断电时由 VBAT 供电继续工作32 位秒计数器RTC_CNT Unix 时间戳秒计数器计到2106-02-07 06:28:15才溢出20 位预分频器PRL重装值 DIV余数计数器 LSE 32.768KHz ÷ 32768 1Hz闹钟寄存器RTC_ALRCNT 与 ALR 相等时触发闹钟信号可唤醒待机模式三个中断秒中断Second、溢出中断Overflow、闹钟中断AlarmLSE 32.768KHz 是首选经 15 位分频自然溢出得 1Hz断电走时必须用 LSERTC 框图时钟源对比时钟源频率VBAT 供电PRL 填写值推荐场景HSE / 128~62.5KHz❌62500-1备选LSE ★32.768KHz✅32768-1首选断电走时必须用LSI40KHz❌40000-1LSE 失效时备选 为什么是 32767LSE32768HzPRL32767DIV 从 32767 递减到 0正好 32768 个时钟周期 1 秒。这是最简单的 1Hz 方案。RTC 初始化步骤❗ 必须按顺序执行开时钟RCC_APB1ENR→PWREN1, BKPEN1使能访问PWR_BackupAccessCmd(ENABLE)判断是否第一次读BKP_DR1≠ 0xA5A5 → 第一次配置 0xA5A5 → 已配置过跳过配置开 LSE开启 LSE 振荡器并等待RCC_FLAG_LSERDY1选时钟源RCC_RTCCLKConfig(LSE) RCC_RTCCLKCmd(ENABLE)等同步 等写完RTC_WaitForSynchro()RTC_WaitForLastTask()设预分频RTC_SetPrescaler(32768-1)RTC_WaitForLastTask()设初始时间MyRTC_SetTime() 写标志BKP_DR1 0xA5A5MyRTC_Init() 实操代码#includestm32f10x.h#includetime.huint16_tMyRTC_Time[]{2023,1,1,23,59,55};// 年、月、日、时、分、秒voidMyRTC_Init(void){/* 1. 开启 PWR BKP 时钟 */RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);/* 2. 使能后备区域访问 */PWR_BackupAccessCmd(ENABLE);// 允许访问 RTC/BKP 寄存器/* 3. 判断是否第一次配置通过 BKP_DR1 标志位 */if(BKP_ReadBackupRegister(BKP_DR1)!0xA5A5){/* 4. 开启 LSE 并等待就绪 */RCC_LSEConfig(RCC_LSE_ON);while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)!SET);/* 5. 选择 RTCCLK 来源并使能 */RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);// RTCCLK LSERCC_RTCCLKCmd(ENABLE);/* 6. 等待同步 等待上一次写操作完成 */RTC_WaitForSynchro();// 等待 RSF1RTC_WaitForLastTask();// 等待 RTOFF1/* 7. 设置预分频器32768-1 → 输出 1Hz */RTC_SetPrescaler(32768-1);RTC_WaitForLastTask();/* 8. 设置初始时间 */MyRTC_SetTime();/* 写入标志位下次不再重新配置 */BKP_WriteBackupRegister(BKP_DR1,0xA5A5);}else{/* RTC 已配置过只需重新同步 */RTC_WaitForSynchro();RTC_WaitForLastTask();}}时间读写函数 核心原理RTC 内部存的是UTC 秒计数写日期时间 → mktime →-8h去掉东八区→ 写入 RTC_CNT读读 RTC_CNT →8h加上东八区→ localtime → 日期时间MyRTC_SetTime() — 把数组时间写入 RTCvoidMyRTC_SetTime(void){time_ttime_cnt;// 秒计数器32位整数structtmtime_date;// 日期时间结构体/* 把数组时间赋值给 tm 结构体注意月实际值-1年实际值-1900*/time_date.tm_yearMyRTC_Time[0]-1900;time_date.tm_monMyRTC_Time[1]-1;time_date.tm_mdayMyRTC_Time[2];time_date.tm_hourMyRTC_Time[3];time_date.tm_minMyRTC_Time[4];time_date.tm_secMyRTC_Time[5];/* mktime日期时间 → UTC秒计数再 -8h 转UTC去掉东八区*/time_cntmktime(time_date)-8*60*60;/* 写入 RTC_CNT */RTC_SetCounter(time_cnt);RTC_WaitForLastTask();}MyRTC_ReadTime() — 把 RTC 时间读到数组voidMyRTC_ReadTime(void){time_ttime_cnt;// 秒计数器structtmtime_date;// 日期时间结构体/* 读取 RTC_CNT再 8h 转东八区 */time_cntRTC_GetCounter()8*60*60;/* localtimeUTC秒计数 → 本地日期时间结构体 */time_date*localtime(time_cnt);/* 结构体值写回数组注意月1年1900*/MyRTC_Time[0]time_date.tm_year1900;MyRTC_Time[1]time_date.tm_mon1;MyRTC_Time[2]time_date.tm_mday;MyRTC_Time[3]time_date.tm_hour;MyRTC_Time[4]time_date.tm_min;MyRTC_Time[5]time_date.tm_sec;}主函数示例OLED 显示#includestm32f10x.h#includeDelay.h#includeOLED.h#includeMyRTC.hintmain(void){OLED_Init();// OLED 初始化MyRTC_Init();// RTC 初始化首次配置或同步OLED_ShowString(1,1,Date:XXXX-XX-XX);OLED_ShowString(2,1,Time:XX:XX:XX);OLED_ShowString(3,1,CNT :);OLED_ShowString(4,1,DIV :);while(1){MyRTC_ReadTime();// 读 RTC 硬件到数组/* 第1行年-月-日 */OLED_ShowNum(1,6,MyRTC_Time[0],4);// 年OLED_ShowNum(1,11,MyRTC_Time[1],2);// 月OLED_ShowNum(1,14,MyRTC_Time[2],2);// 日/* 第2行时:分:秒 */OLED_ShowNum(2,6,MyRTC_Time[3],2);// 时OLED_ShowNum(2,9,MyRTC_Time[4],2);// 分OLED_ShowNum(2,12,MyRTC_Time[5],2);// 秒/* 第3行RTC_CNTUnix时间戳第4行DIV余数寄存器*/OLED_ShowNum(3,6,RTC_GetCounter(),10);// 32位秒计数器OLED_ShowNum(4,6,RTC_GetDivider(),10);// 余数寄存器}}闹钟 待机模式唤醒⚠️ 闹钟不一定要中断待机模式下闹钟触发后程序从头重新运行相当于复位不需要 NVIC 中断向量。闹钟中断RTC_IT_ALR RTC_IRQn只在程序持续运行时需要。方案 A待机模式唤醒代码实操intmain(void){OLED_Init();MyRTC_Init();/* 开启 PWR 时钟待机/停止模式必须*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);OLED_ShowString(1,1,CNT :);OLED_ShowString(2,1,ALR :);OLED_ShowString(3,1,ALRF:);/* 使能 WKUP 引脚PA0上升沿可唤醒待机 */PWR_WakeUpPinCmd(ENABLE);/* 设定闹钟当前 CNT 10秒 */uint32_tAlarmRTC_GetCounter()10;RTC_SetAlarm(Alarm);// 写入 RTC_ALROLED_ShowNum(2,6,Alarm,10);while(1){OLED_ShowNum(1,6,RTC_GetCounter(),10);OLED_ShowNum(3,6,RTC_GetFlagStatus(RTC_FLAG_ALR),1);/* Running STANDBY 闪烁指示 */OLED_ShowString(4,1,Running);Delay_ms(100);OLED_ShowString(4,1, );Delay_ms(100);OLED_ShowString(4,9,STANDBY);Delay_ms(1000);OLED_ShowString(4,9, );Delay_ms(100);OLED_Clear();// 清屏关闭 OLED 省电PWR_EnterSTANDBYMode();// 进入待机等待 WKUP/闹钟 唤醒/* 唤醒后程序从头重新运行 */}}方案 B闹钟中断非待机模式/* 在 MyRTC_Init 之后调用 */RTC_ITConfig(RTC_IT_ALR,ENABLE);// 使能闹钟中断NVIC_EnableIRQ(RTC_IRQn);// 使能 RTC 中断通道/* stm32f10x_it.c 中 */voidRTC_IRQHandler(void){if(RTC_GetITStatus(RTC_IT_ALR)SET)// 闹钟标志{/* 闹钟触发处理代码 */RTC_ClearITPendingBit(RTC_IT_ALR);// 清除闹钟中断标志}}LSE 失效时的备选LSI⚠️ LSI 不适合断电走时LSI 由 VDD 供电备用电池 VBAT 无法维持。仅作为 LSE 起振失败时的临时替代。voidMyRTC_Init_LSI(void){RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);PWR_BackupAccessCmd(ENABLE);if(BKP_ReadBackupRegister(BKP_DR1)!0xA5A5){RCC_LSICmd(ENABLE);while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)!SET);RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);// 用 LSIRCC_RTCCLKCmd(ENABLE);RTC_WaitForSynchro();RTC_WaitForLastTask();RTC_SetPrescaler(40000-1);// LSI40KHz, PRL39999 → 1HzRTC_WaitForLastTask();MyRTC_SetTime();BKP_WriteBackupRegister(BKP_DR1,0xA5A5);}else{/* 已配置过也需要重新开启 LSI */RCC_LSICmd(ENABLE);while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)!SET);RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);RCC_RTCCLKCmd(ENABLE);RTC_WaitForSynchro();RTC_WaitForLastTask();}}操作注意事项⚠️ 高频考点使能访问用 RTC 前必须先开PWREN BKPENDBP1等待同步APB1 曾被禁止后读 RTC 寄存器前必须RTC_WaitForSynchro()等RSF1等待写完每次写 RTC 寄存器前必须等RTOFF1配置模式写PRL / CNT / ALR前需设CNF1库函数自动处理LSE 断电不工作断电走时必须选 LSE选 HSE/LSI 则 VDD 断电 RTC 停走LSI VBAT 不可用LSI 由 VDD 供电不是 VBAT待机模式进入待机后所有寄存器复位程序从头重新运行VBAT 域RTC BKP数据保持 RSF 标志的作用APB1 频率36MHz远大于 RTCCLK32.768KHzAPB1 开启后需等 RTCCLK 上升沿把 RTC 寄存器值同步到 APB1 总线否则读到错误值通常为 0。BKP 备份寄存器项目说明全称Backup Registers用途存储用户自定义数据VBATVDD 断电后由 VBAT 维持数据容量中容量 20 字节DR1~DR10大容量 84 字节侵入检测TAMPER 引脚PC13触发 → BKP 数据全清RTC 输出PC13 可输出校准时钟 / 闹钟脉冲 / 秒脉冲硬件电路VBAT接 CR2032 纽扣电池3V无电池时接 VDD 100nF 电容推荐 VBAT 电路VDD 和电池各经肖特基二极管 → VBAT 100nF 滤波电容防电流倒灌LSE 晶振32.768KHzOSC32_IN / OSC32_OUT两端各接 10pF 接地电容相关知识BKP— 备份寄存器位于后备区域VBAT供电RTC— 电源控制 DBP 使能依赖 PWR 模块中断系统NVIC— RTC 中断在 NVIC 中配置TIM定时器— 定时器可类比学习实时时钟代码— RTC 初始化代码实现RTC待机模式唤醒— PWR_EnterSTANDBYMode 待机模式唤醒停止模式参考RTC后备区域供电机制视频字幕重点片段时间内容00:01-08:59BKP 简介VBAT 供电、RAM 特性、侵入检测08:59-20:19RTC 简介框图、时钟源选择、三种中断20:19-28:13RTC 预分频器原理PRLDIV 分频输出 1Hz28:27-33:29硬件电路VBAT 供电方案、LSE 晶振电路33:47-44:41操作注意事项RSF/RTOFF/CNF 三标志位详解 理论视频BV1th411z7sn P42 实时时钟理论 实操视频BV1th411z7sn P43 [12-3]代码实操