RTC
RTC (Real-Time Clock),中文叫实时时钟。
1. 形象比喻
- TIM (通用定时器):是你手里的秒表。
- 特点:跑得飞快(微秒级),用来测百米赛跑、产生 PWM 波。但在断电的那一瞬间,秒表清零。
- 缺点:它不知道现在是公元几几年,也不知道今天是星期几。
- RTC:是你手腕上的电子表(而且带万年历)。
- 特点:跑得慢(一秒跳一下),用来告诉你“现在是 2023年10月5日 14:30:00”。
- 核心能力:掉电不丢数据! 哪怕单片机主电源(VDD)断了,只要挂了一颗纽扣电池(VBAT),RTC 就在后台默默走字。
2. 它在芯片里长什么样?
RTC 其实是一个独立的定时器模块,但它经过了特殊设计:
- 超低功耗:为了省纽扣电池的电,它设计得非常“抠门”,耗电极低。
- BCD 编码:它的寄存器里存的不是普通的二进制,通常是 BCD 码(比如 12点30分,寄存器里存的就是 0x12, 0x30),方便人类阅读。
二、 RTC 和 RCC
关系:RCC 是 RTC 的“能源局”。
RTC 想要走字,必须要有频率源(震荡源)。这个频率源是谁给的?是 RCC 选好并送过来的。
在 RCC 的配置图里,有一块专门的区域叫 Backup Domain (备份域),专门负责给 RTC 供油。
RCC 给 RTC 提供了三道“菜”(时钟源选择):
- LSE (Low Speed External) —— 首选!
- 是什么:板子上那个细细长长的、圆柱体的晶振(32.768 kHz)。
- 优点:最准! 而且可以用纽扣电池驱动。
- 老鸟经验:做产品必须用这个,否则你的表一天能慢好几分钟。
- LSI (Low Speed Internal) —— 备胎
- 是什么:芯片内部的一个 RC 振荡电路。
- 缺点:极其不准。受温度影响大。
- 用途:只能用于看门狗或者对时间精度要求不高的场合。
- HSE / 128 (High Speed External 分频) —— 凑合
- 是什么:用主晶振(8MHz)分频下来给 RTC 用。
- 致命伤:不能用电池供电。主电源一断,HSE 也就停了,RTC 也就挂了。
结论:
配置 RTC 之前,必须先在 RCC 里把 LSE 打开,并把 RTC 的时钟源选为 LSE。这就是 RCC 对 RTC 的控制权。
三、 资深工程师的“避坑指南” (重点)
RTC 是所有外设里最容易让新手**“写了代码却跑不起来”的模块,原因就在于它有特殊的保护机制**。
坑 1:备份域保护 (Backup Domain Protection)
现象:你代码逻辑完美,RCC 开了,RTC 初始化了,但就是写不进时间,或者 RCC 报错。
原因:RTC 和备份寄存器(BKP)属于“皇家重地”。为了防止程序跑飞时误改时间,STM32 上电默认把这块区域锁死了。
解决:在操作 RTC 之前,必须执行两步“解锁”操作(这是标准动作,必须背下来):
- 开启 PWR (电源控制) 时钟。
- 调用
PWR_BackupAccessCmd(ENABLE)(允许访问备份域)。
- 如果不做这两步,你写多少行代码都是徒劳。
坑 2:32.768kHz 晶振不起振
- 现象:代码卡在
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)出不来。 - 原因:LSE 晶振非常娇气(低功耗设计)。如果你的 PCB 布线下面有高频信号穿过,或者助焊剂没洗干净,它就死活不起振。
- 解决:硬件问题。洗板子,或者在晶振两脚并联 6pF-10pF 的电容试试。
坑 3:上电重置问题
- 场景:你写好了时间 12:00,断电,插上电池,再上电。
- Bug:时间怎么又变回 12:00 了?它没有继续走吗?
- 原因:你的初始化代码里,每次上电都执行了一句
RTC_SetTime(12:00)。 - 解决:你需要一个标志位。
- RTC 附近通常有 BKP (备份寄存器)。这也是掉电不丢失的。
- 第一次烧录代码:设置时间 -> 往 BKP 寄存器里写一个魔术数字(比如
0xA5A5)。 - 第二次上电:先检查 BKP 里是不是
0xA5A5?如果是,说明设置过时间了,跳过设置时间的步骤,直接显示即可。
四、 总结:RTC 与 RCC
| 模块 | 全称 | 角色 | 掉电表现 | 核心任务 |
|---|---|---|---|---|
| RCC | 复位与时钟控制 | 能源局 | 没电就停 | 负责给 RTC选一个时钟源 (LSE/LSI) |
| RTC | 实时时钟 | 日历表 | 有电池就能跑 | 负责数秒、记日期、闹钟唤醒 |
一句话口诀:
想用 RTC,先去 RCC 找 LSE,进门前记得找 PWR 拿钥匙(解锁备份域)。