BKP & RTC
RTC (实时时钟),就绝对绕不开它的“连体婴”兄弟 —— BKP (Backup Registers,备份寄存器)。
这两兄弟通常是穿一条裤子的。在嵌入式开发(特别是 STM32)中,它们共同组成了芯片中一个最神秘、最坚挺的区域 —— 备份域 (Backup Domain)。
把它们的关系比作:“挂钟”与“保险箱”。
一、 什么是 BKP?(单片机里的保险箱)
你已经知道 RTC 是**“挂钟”(负责走字)。
那 BKP 就是挂钟下面的一个“小保险箱”**。
1. 物理特性
- 空间很小:通常只有几十个字节(比如 STM32F103 有 42 个 16位的寄存器)。它不是用来存大数据的,是用来存**关键“秘密”**的。
- 供电特殊:它和 RTC 一样,也是吃 VBAT (纽扣电池) 的饭。
- 记忆力超强:
- 按下复位键 (NRST)?数据还在。
- 软件重启 (System Reset)?数据还在。
- 主电源 VDD 断电(只要电池还在)?数据还在。
- 只有一种情况会丢失:纽扣电池被拔掉,或者发生了“入侵事件”(Tamper,后面讲)。
2. 它的作用
它是 RAM,读写速度极快,不需要像 Flash 那样擦除。它主要用来保存系统断电后不能丢、但复位后又需要立刻读取的“状态标记”。
二、 为什么 RTC 离不开 BKP?(经典应用场景)
这是嵌入式面试必问的题目:“系统重新上电后,如何防止 RTC 时间被重置?”
场景模拟:
- 你写了一个代码:
RTC_Init(); RTC_SetTime(12:00);。 - 第一次烧录运行:时间设定为 12:00,开始走字。
- 问题来了:当你断电重启,或者按复位键,代码又从头跑了一遍,又执行了一次
RTC_SetTime(12:00)。 - 结果:你的表永远停留在 12:00,或者每次重启都归零。
解决方案:用 BKP 存个“暗号”
因为 BKP 在重启后数据不丢失,我们可以利用它来判断**“这是不是第一次上电”**。
标准代码逻辑(老鸟都在用):
C
// 定义一个暗号,比如 0xA5A5 (随便定义的,只要是个特殊值就行)
#define RTC_CHECK_FLAG 0xA5A5
void RTC_Configuration(void)
{
// 1. 先去打开保险箱看看,里面有没有我们的暗号?
if (BKP_ReadBackupRegister(BKP_DR1) != RTC_CHECK_FLAG)
{
// === 情况 A:没找到暗号 ===
// 说明这是这块板子【第一次】上电,或者电池被扣掉过。
printf("第一次上电,正在初始化 RTC...\n");
RTC_Init(); // 初始化 RTC
RTC_SetTime(12, 0, 0); // 设个默认时间
// 【关键一步】把暗号写进保险箱!
BKP_WriteBackupRegister(BKP_DR1, RTC_CHECK_FLAG);
}
else
{
// === 情况 B:找到了暗号 ===
// 说明板子只是复位了,电池还在,RTC 正在后台默默走字呢。
printf("发现暗号!跳过时间设置,直接显示当前时间。\n");
// 啥也不用干,直接去读 RTC 值就行了
// 这一步如果不跳过,你的时间就被重置了!
}
}结论:
RTC 负责走时,BKP 负责记录“表已经调好了”这个状态。 没有 BKP,RTC 每次重启都会“失忆”。
三、 BKP 的另一个绝技:防拆机(Tamper Pin)
BKP 还有一个非常酷炫的功能,常用于POS 机、加密狗等安全性要求高的产品。
侵入检测 (Tamper Detection)
- 原理:BKP 模块有一个专门的引脚叫
TAMPER。你可以把它接在一个微动开关上,这个开关顶住产品的外壳。 - 动作:如果有人试图撬开外壳,开关弹起,
TAMPER引脚电平发生跳变。 - 后果:BKP 模块会瞬间检测到“入侵”,然后立刻自动清空所有 BKP 寄存器里的数据!
- 目的:毁尸灭迹。黑客撬开机器想读你的密钥(假设你把密钥存在 BKP 里),结果打开一看,全变成了 0,啥也没捞着。
四、 资深工程师的总结
RTC 和 BKP 是备份域里的“难兄难弟”。
| 特性 | RTC (实时时钟) | BKP (备份寄存器) |
|---|---|---|
| 功能 | 计数 (时间/日期) | 存储 (数据) |
| 容量 | 32位计数器 | 几十个字节 (16位 x N) |
| 电源 | VDD 或 VBAT | VDD 或 VBAT |
| 复位影响 | 不受系统复位影响 | 不受系统复位影响 |
| 核心用途 | 提供时间 | 辅助 RTC 判断初始化状态/ 存储掉电数据 / 防拆自毁 |
| 访问前提 | 需 PWR 解锁 | 需 PWR 解锁 |
避坑提醒:
- 必须要使能 PWR 和 BKP 时钟:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); - 必须要解锁:
PWR_BackupAccessCmd(ENABLE); - BKP 不是 Flash:虽然它掉电不丢(有电池时),但如果你把电池扣了,BKP 里的数据就真没了。所以它不适合存永久性的配置参数(那个该存 Flash 或 EEPROM),它只适合存“临时但跨复位”的数据。