news 2026/9/28 1:29:06

STM32 VBAT备用电池实现RTC断电不停钟:硬件、HAL库与调试全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32 VBAT备用电池实现RTC断电不停钟:硬件、HAL库与调试全解析

做项目做到一半,最尴尬的往往不是代码跑不通,而是你关掉电源再上电,辛辛苦苦校好的墙上钟、设备日志时间、传感器打点时间全部归零,当场回到 2000 年 1 月 1 日。被这种问题折磨过几次之后,我把 STM32 内部 RTC 和 VBAT 备用电池的整套玩法彻底摸了一遍。这篇东西不写虚的,直接围绕“如何用 VBAT 电池让 RTC 在断电之后继续跑”这条主线,把硬件接线、软件初始化、掉电恢复判断、调试排坑一次讲透,代码基于 HAL 库,F1/F4 系列都能参考。

1. 断电丢时间问题的根因:RTC 的供电域设计到底在保护什么

很多人在 STM32 上第一次用 RTC 都有个困惑:明明初始化代码写得好好的,上电也能跑,时间也能读出来,但只要主电源一断再上电,时间就回到初始值。这不是芯片坏了,也不完全是代码问题,而是你还没理解 RTC 的供电架构。

1.1 普通外设和 RTC 的供电差异

STM32 内部大致可以分成两个供电域:一个是主电源域 VDD,几乎所有 GPIO、外设、Flash、RAM 都在这个域里;另一个是备份域,包含 RTC 核心计数器、备份寄存器(BKP)、以及外部低速晶振 LSE 的振荡电路。备份域比较特殊,它可以在主电源 VDD 掉电之后,改用 VBAT 引脚上的电池继续供电。

如果你只在主电源域里跑 RTC,关机等于拔掉 CPU 的“主食”,RTC 自然跟着停摆。需要做的是把 RTC 放到“备份域”这个不依赖 VDD 的小房间里,再给它单独接一个 VBAT 电源,这样即使主电源掉电,RTC 部分的电路仍有电可吃,时间就不会丢。

1.2 备份域和 VBAT 的关系

VBAT 引脚就是专门给备份域供电的备用电源入口。正常工作时,STM32 内部的电源切换电路会自动选择 VDD 供电给备份域;在主电源掉电时,则自动切到 VBAT 供电。整个过程不需要软件控制,硬件自动完成。

需要重点理解的是,VBAT 不仅给 RTC 计数器供电,还给整组备份寄存器供电。这就是为什么很多人掉电恢复后能靠备份寄存器里的标志来判断“是不是第一次上电”——因为只要 VBAT 有电,备份寄存器里的数据就能一直保持。

1.3 多数人漏掉的细节:VBAT 不接电池时不能悬空

如果你的项目暂时不用电池,VBAT 引脚也不能空着不接。ST 官方要求是直接接到 VDD,也就是 3.3V 电源上。不少开发板上预留了 VBAT 和 VDD 之间的跳线帽,就是这个原因。如果悬空,备份域供电处于不确定状态,可能导致 RTC 工作异常,甚至让内部电源切换电路发生不明行为,表现在现象上就是时间偶尔跳变、复位后丢失。

我第一次画板子时就把 VBAT 空着了,结果并联的备用电池死活不起作用。后来查引脚手册才发现,VBAT 和 VDD 之间必须有一个明确连接路径,不是随便推一个电池到引脚就完事。

2. 硬件侧设计要点:电池选型、VBAT 引脚电路与最小系统避坑

RTC 软件写得好不好暂且不说,硬件这边但凡有一点草率,后面调试就会花掉几倍时间。VBAT 的电路其实非常简单,但“简单”不代表可以随便接,几个关键点直接决定电池能不能撑住、时间能不能稳住。

2.1 电池选型:纽扣电池、超级电容、大电容三种方案怎么选

理论上任何能从 VBAT 引脚提供 1.65V~3.6V 的电源都可以用,但实际产品中主流方案就三种。

纽扣电池(CR1220 / CR2032)是最常见的选择。容量大,CR2032 典型容量在 200mAh 以上,在 STM32 RTC 典型备份电流只有几微安的情况下,撑两三年问题不大。缺点是体积大、需要电池座、不适合高温环境。

超级电容适合短时间断电保持的场景。比如 1F 耐压 5.5V 的超级电容充满后,维持 RTC 跑几小时到一天是可能的,成本低、可充电、环保,但不能像电池那样撑几个月。

普通电解电容或陶瓷电容组只能支撑几十秒到几分钟。适合做演示、验证功能,不适合实际断电保持。

如果你只是想在实验室里验证“断电不停钟”,最简单的方法是在 VBAT 引脚外挂一个大电容,比如 1000uF,再把主电源断开,观察时间是否延续。注意大电容的充电电流要控制好,否则首次上电瞬间可能拉低电源电压。

2.2 VBAT 引脚的接线细节

无论用哪种备用电源,VBAT 引脚旁边都建议并联两个电容:0.1uF 陶瓷电容用于滤高频干扰,1uF~10uF 电容用于储能缓冲。特别是使用电池座时,电池座本身有接触电阻,瞬间电流需求不大,但加个电容能有效防止接触抖动导致 RTC 复位。

如果使用可充电电池或超级电容,还需要考虑充电电路,不能直接把 VBAT 接在充电输出端就完事,要预留充电限流电阻或专用充电芯片,避免过流损坏电池和芯片引脚。

2.3 外部晶振 LSE 的电路设计

用 VBAT 实现断电不停钟的前提,是 RTC 的时钟源必须能在 VDD 掉电后继续振荡。内部 RC 振荡器通常在掉电时不工作,或者精度不够,所以正经产品都用外部 32.768kHz 晶振,也就是 LSE。

LSE 晶振电路不能照搬高速晶振的布局。32.768kHz 属于低频低功耗振荡,对负载电容和 PCB 走线更敏感。通常晶振两端各接一个负载电容到地,容值根据晶振规格书选择,常见的是 6pF 到 12.5pF 负载电容对应 10pF 到 22pF 的端接电容。走线要短,两个负载电容的地要就近打孔,避免形成天线噪声影响起振。

之前遇到过一个挺隐蔽的问题:晶振外围电路完全正确,但 LSE 就是偶尔不起振。后来用示波器观察发现, PCB 上晶振附近有电源走线穿过,高频纹波耦合到了晶振引脚。把走线绕开、地平面铺好后,问题消失。这种问题不会出现在仿真里,只会在实物上恶心你。

2.4 调试接口的影响

使用 ST-Link 或 J-Link 调试 RTC 程序时,SWD 的 SWCLK 和 SWDIO 引脚通常分别是 PA13 和 PA14,大多数情况下和 VBAT、LSE 没有电路冲突。但要注意,如果代码里把 PA13/PA14 配成了普通 GPIO,可能导致调试器连接失败。这在调试 RTC 这种“需要反复下电验证”的场景里尤其烦,因为你正要测掉电特性,结果程序把调试口禁了。

解决方案是在初始化阶段延迟一段时间再配置 GPIO,或者调试阶段先不要配置 SWD 引脚,等功能验证完再关闭。ST-Link 连不上时,可以按住板子复位键,在点击 Connect 的瞬间松开复位,利用“芯片处于复位状态”的空窗期连接调试器,再擦除 Flash。

3. 软件实现思路:从初始化到掉电恢复的完整链路

硬件准备好之后,软件才是决定成败的关键。这里给出一个比较完整的 HAL 库例程设计思路,覆盖首次上电时的 RTC 初始化、正常读取时间、掉电恢复时如何保留时间。

3.1 判断冷启动与掉电恢复的常用做法

很多人每次上电都去执行一遍 RTC 初始化并设置时间,这是最典型的错误。掉电恢复后如果重新写时间,哪怕用的是 RTC->CNT 里的旧值,也可能因为时序问题覆盖掉真正在走的时间。正确做法是判断备份域里的数据是否有效。

思路是这样的:在备份寄存器 BKP_DR1 里写一个魔数,比如 0xA5A5。上电后先读这个寄存器,如果值等于 0xA5A5,说明备份域在上一次掉电时没有复位,RTC 还在走,直接跳过 RTC 初始化和时间设置;如果不等于,说明可能是首次上电,或者备份域曾经掉电,需要做完整初始化并写入当前时间。

3.2 RTC 初始化代码(HAL 库示例)

下面这段代码以 STM32F103 系列为例,使用 HAL 库。工程中需要先使能电源接口时钟和备份域访问权限,再操作 RTC。

#include "rtc.h" RTC_HandleTypeDef hrtc; static uint8_t RTC_IsBackupValid(void) { return (HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1) == 0xA5A5); } static void RTC_SetDefaultTime(void) { RTC_TimeTypeDef sTime = {0}; RTC_DateTypeDef sDate = {0}; sTime.Hours = 10; sTime.Minutes = 30; sTime.Seconds = 0; sDate.WeekDay = RTC_WEEKDAY_MONDAY; sDate.Month = RTC_MONTH_JANUARY; sDate.Date = 1; sDate.Year = 24; HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN); HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN); HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, 0xA5A5); } void MX_RTC_Init(void) { RCC_OscInitTypeDef rccOscInit = {0}; RCC_PeriphCLKInitTypeDef periphClkInit = {0}; __HAL_RCC_PWR_CLK_ENABLE(); __HAL_RCC_BKP_CLK_ENABLE(); HAL_PWR_EnableBkUpAccess(); /* 如果备份域已经有有效数据,说明 RTC 在由 VBAT 供电运行,不能再重新初始化 */ if (RTC_IsBackupValid()) { hrtc.Instance = RTC; return; } /* 使能 LSE 外部低速晶振 */ rccOscInit.OscillatorType = RCC_OSCILLATORTYPE_LSE; rccOscInit.LSEState = RCC_LSE_ON; if (HAL_RCC_OscConfig(&rccOscInit) != HAL_OK) { Error_Handler(); } periphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC; periphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; if (HAL_RCCEx_PeriphCLKConfig(&periphClkInit) != HAL_OK) { Error_Handler(); } __HAL_RCC_RTC_ENABLE(); hrtc.Instance = RTC; hrtc.Init.HourFormat = RTC_HOURFORMAT_24; hrtc.Init.AsynchPrediv = 127; hrtc.Init.SynchPrediv = 255; hrtc.Init.OutPut = RTC_OUTPUT_DISABLE; hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; if (HAL_RTC_Init(&hrtc) != HAL_OK) { Error_Handler(); } RTC_SetDefaultTime(); }

代码逻辑值得展开说几点。

第一,判断函数 RTC_IsBackupValid 必须在使能备份域访问之后执行。有的库版本里 HAL_RTCEx_BKUPRead 之前如果没调用 HAL_PWR_EnableBkUpAccess,读回来的一直是 0。

第二,HAL_RTCEx_BKUPWrite 写备份寄存器的前提是 RTC 已经初始化,且备份域时钟已经打开。顺序反了会出现写入失败但代码不报错的现象。

第三是预分频值。F1 的 RTC 预分频是异步分频,两个寄存器值分别是异步预分频和同步预分频,典型配置是 127 和 255,这样 32.768kHz 经过 (127+1)x(255+1) 分频后正好得到 1Hz。F4/H7 系列内部结构不同,但原理类似,配置时不要照搬 F1 的寄存器操作代码。

3.3 掉电恢复后的时间读取流程

掉电恢复后,MCU 从头开始跑程序。由于 VBAT 有电,备份域里 RTC 计数器和备份寄存器数据都还在,MX_RTC_Init 里判断出备份数据有效,会直接跳过重新设置时间的逻辑。接下来只需要正常读取时间即可。

void RTC_GetTimeDisplay(char* buf, uint8_t len) { RTC_TimeTypeDef sTime = {0}; RTC_DateTypeDef sDate = {0}; HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN); HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN); snprintf(buf, len, "%04d-%02d-%02d %02d:%02d:%02d", 2000 + sDate.Year, sDate.Month, sDate.Date, sTime.Hours, sTime.Minutes, sTime.Seconds); }

注意一个细节:HAL 库要求先读时间再读日期,顺序不能反过来。因为读取时间时才会将内部影子寄存器里的日期数据锁存,如果你先读日期,再读时间,可能会导致两次读到的日期跨秒时不一致。

3.4 备份寄存器不仅是魔数仓库

备份寄存器除了存魔数,还能存一些掉电期间必须保留的业务数据。比如一个高精度设备的校准参数、上电计数、设备序列号或者状态机状态。这样即使在主控完全断电的情况下,这些数据也能由 VBAT 保留。不过备份寄存器数量有限,F1 系列有 10 个 16 位寄存器,F4 有 20 个 32 位寄存器,用的时候要规划好,别把大数组往里塞。

4. 代码调试技巧:LSE 不起振、时间乱跳、复位清零怎么排查

这一节是全文最有价值的部分。RTC 功能本身代码量不大,但坑密度极高,而且很多坑不是语法错误,而是硬件时序、库调用顺序、调试环境干扰造成的。我把实际开发中碰到的问题按现象分类,每个都给排查链路。

4.1 现象一:LSE 始终不起振,程序卡死在时钟配置

LSE 起振需要几百毫秒到一两秒,如果晶振没焊好、负载电容不对、或者晶振本身坏了,HAL_RCC_OscConfig 可能一直等到超时。此时程序毫无输出,调试器连上后单步会发现卡在 while 循环里。

排查链路:

  1. 先用示波器或逻辑分析仪测晶振引脚,看有没有 32.768kHz 波形。注意不要用普通 10x 探头长时间直接测,探头电容可能压住振荡,最好用低电容探头或干脆通过 MCO 引脚输出时钟观察。

  2. 如果不方便测波形,可以把 LSE 的旁路电容先减小,有些晶振对负载要求更小,端接电容太大反而起振困难。

  3. 检查 LSE 的使能时序。如果代码里先使能了 LSE,又把 RTC 使能,顺序反了也会导致起振异常。按上面的示例顺序来:先 PWR/BKP 时钟 → 访问备份域 → 配置 LSE → 选择 RTC 时钟源 → 使能 RTC。

  4. 检查代码中是否有 RCC_BackupResetCmd(ENABLE) 之类的调用。标准库里有些人为了复位 RTC 模块会调用备份域复位,如果这个调用在 LSE 起振之后被误触发,就会把备份域整个清掉,时间归零,LSE 也重新停振。

4.2 现象二:主电源断电再上电后时间归零,但备份寄存器里的数据还在

这个现象比较奇怪,像是“时间丢了,但魔数没丢”。实际上是因为 RTC 计数器和备份寄存器虽然都在备份域,但某些芯片中 RTC 的复位源和备份寄存器不完全一样。更多情况是,你虽然判断了备份数据有效并跳过了初始化,但 RTC 的预分频、计数寄存器也可能因为软件配置错误被重置。

一个经典原因是 HAL_RTC_Init 在每次上电都会执行,且 hrtc.Init 里配置了同步/异步预分频。这个函数内部可能根据某些标志决定是否重新初始化 RTC。如果你在判断 RTC_IsBackupValid 为真的分支里只是设置了 hrtc.Instance = RTC 就返回,但主流程后面的代码又把 MX_RTC_Init 重新调用了一次,就会被再次配置。

做法是:只有在备份数据无效时才执行完整初始化,并让 MX_RTC_Init 在“数据有效”分支直接 return,确保不会走到 RTC 重新初始化的代码。同时检查主循环里有没有其他地方调用了 HAL_RTC_Init。

4.3 现象三:串口打印出来的时间每隔一段时间就跳变一次

时间跳变通常有三个来源:一是 RTC 计数基准不对,二是串口读取时序问题,三是晶振频率偏移。

先说 RTC 计数基准。F1 系列 RTC 是一个 32 位计数器,预分频值决定秒钟跳变节奏。如果 LSE 不是 32.768kHz,而是内部低速 RC(LSI),计数基准就完全不对。有些人想省成本用 LSI 做 RTC,断电之后 LSI 停振,时间必丢,而且 LSI 精度差,一天可能偏几十秒。所以规划项目时就别走这条路。

串口读取时序问题,常见于中断和主循环同时访问 RTC 寄存器。HAL_RTC_GetTime 本身不是线程安全的,如果在 RTC 闹钟中断里读时间,同时主循环也在读,可能导致读到半更新状态的数据。建议串口打印前关闭全局中断,读完成后再打开。

晶振频率偏移则需要校表。32.768kHz 晶振本身有频率误差,常见在 +/-20ppm 左右,一天累计误差约 1.7 秒。如果产品需要精确计时,得做软件校准,比如用网络时间或 GPS 秒脉冲来定期校准。校准方法可以简单实现:记录一天时间误差,然后按比例调整每秒计数。

4.4 现象四:为什么一进调试器时间就乱走

这一点很多新手不理解。ST-Link/J-Link 在调试状态下触发内核暂停时,RTC 外设是否继续走,取决于调试配置。默认情况下,RTC 的时钟来自 LSE,LSE 振荡器是独立于内核时钟域的,所以内核暂停时 RTC 依然在后台计数。等你恢复运行、再次读取时间时,看到的数值已经往前走了不少,这不是 bug,是正常现象。

如果想让 RTC 在调试暂停时也暂停,可以通过调试寄存器配置,但绝大多数场景不需要。把这个现象写在调试笔记里,省得后续同事误解。

4.5 调试工具里的实用技巧

Keil 调试时可以打开 Watch 窗口,直接输入RTC->CNT查看 F1 系列 RTC 计数器的实时值。如果不想看寄存器原始值,可以在代码里设置断点,观察sTime.Hours、sTime.Minutes等变量的变化。串口打印还是最直观的,但这意味着每次调试都要接线、打开串口工具,效率不高。

我个人的习惯是做一个“心跳”打印函数,每秒钟通过串口输出当前时间的秒数和最低 16 位计数器值。断电后重新上电,如果在串口日志里看到秒数是连续递增的,说明 VBAT 路径和软件判断都没问题;如果看到秒数从 0 开始,就缩小排查范围:先量 VBAT 电压,再查备份寄存器标志是否写入成功。

4.6 关于 RTC 校准的进阶操作

F4/H7 系列 RTC 有数字校准功能,可以微调同步预分频器的计数窗口,精确校准漂移。F1 系列没有这个功能,只能靠外部校正。不管哪个系列,一个通用做法是:用 MCO 引脚输出 LSE 时钟,用频率计测量实际频率,再配合定时器产生秒脉冲,与标准秒脉冲对比,记录误差后做软件补偿。

校准记录示例: 标准时间 24小时,RTC 显示 23:59:58,慢了 2 秒 每 86400 秒慢 2 秒,相当于每天误差 -23.15ppm 若同步预分频为 255,可以在每次秒更新时额外补偿若干子时钟计数

5. 做产品时的额外细节:功耗、电池寿命和 RTC 的扩展玩法

如果只做开发板功能演示,直接上纽扣电池就行。但真正做产品,就要从功耗、成本、可靠性三个维度重新审视 VBAT 方案。

5.1 F1/F4 系列的备份域功耗

STM32F103 系列在仅 VBAT 供电、LSE 运行、RTC 计数的备份域电流一般在 1.4uA 到 3.3uA 之间,具体看型号和温度。F4 系列通常稍大一些,但也在个位数微安。相比主控正常工作的几十毫安,这个电流可以忽略不计,但设计电池容量时不能只看常态电流,还要算上电池自放电和温度影响。

5.2 电池寿命估算

以 CR2032 为例,标称容量 210mAh~230mAh,备份电流取 2uA,理论上 210mAh / 0.002mA = 105000 小时,约 12 年。实际要打折,因为电池自放电、高温、瞬间大电流都会缩短寿命,而且电池容量在接近寿命末期时电压下降,可能导致 VBAT 跌破备用域最低工作电压。工程上按 5 年左右设计比较稳妥,如果产品要求 10 年不断电,建议用更大容量电池或者定期更换策略。

超级电容方案则要计算电容存储能量和掉电持续时间。1F 电容充到 3.3V,放电到 2.0V(RTC 备份域最低电压约 1.65V),可供的能量大约是:

E = 0.5 * C * (V1^2 - V2^2) = 0.5 * 1 * (3.3^2 - 2.0^2) = 0.5 * (10.89 - 4) = 3.445 焦耳

按备份功耗 P = 2uA * 3.3V ≈ 6.6uW,理论维持时间约 3.445 / 6.6e-6 ≈ 522000 秒,约 6 天。但实际电容漏电一般不小,能撑一天已经很理想。用超级电容要注意耐压,5.5V 耐压比较合适,3.3V 直接充没问题,如果用 2.7V 耐压就不行。

5.3 RTC 闹钟和唤醒功能

VBAT 掉电保持不只是为了“看时间”,还能配合 RTC 闹钟实现定时唤醒。系统主电源断掉以后,RTC 继续走,等到设定的闹钟时间到达,RTC 会输出一个脉冲给外部 MCU 的唤醒引脚,或者在 STM32 待机模式下由 RTC 闹钟事件唤醒 MCU。这在低功耗数据采集器里非常常见:平时整机休眠,每隔一小时醒来采集一次数据,再继续睡。

F1 系列 RTC 支持闹钟中断,F4/H7 功能更强,支持唤醒定时器。要注意备份域里配置闹钟后,主电源掉电再上电时闹钟设置仍然存在,但如果备份域复位了,闹钟配置也跟着清零。

5.4 防篡改和入侵检测:备份域的隐藏技能

STM32 的备份域里还有个外部入侵检测引脚(Tamper),如果发生外部事件,可以自动清除备份寄存器数据。这个功能可以用来做设备防拆:设备外壳一旦被打开,入侵引脚电平变化,RTC 时间和备份数据立即清零,后续上电就知道设备被拆过。这个玩法在防盗版、计费设备里很有价值,但很多人不知道备份域还有这一层存在。

6. 把“掉电时间保持”做进项目的几条个人经验

最后聊几句在实际产品中沉淀下来的心得,不按顺序,但是句句都是真金白银。

第一,VBAT 电路上的 0.1uF 电容千万别省。我试过一批板子为了省物料,VBAT 引脚只接了电池座,结果用万用表量电压正常,但设备在震动环境里偶尔时间归零,排查到最后是电池座接触不良瞬间断路,RTC 掉电复位。加了电容后,即使电池瞬间离开零点几秒,电容上的电也能维持备份域不丢数据。

第二,用标准库还是 HAL 库不重要,但初始化顺序必须固定。我见过有人把 HAL_PWR_EnableBkUpAccess 放到 MX_RTC_Init 末尾,结果备份寄存器读写失败。把“时钟使能 → 备份域访问 → RTC 配置 → 设置时间 → 写标志”的顺序写成注释放在代码头部,能有效防止后人改坏。

第三,调 RTC 一定要学会用串口辅助定位问题。关掉调试器,直接串口看打印,比单步执行更能复现掉电场景。先把“每次上电都自动设置时间”的代码去掉,再用串口观察时间是否跳过初始值,这样能快速区分是软件覆盖问题还是备份域复位问题。

第四,产品定型前用示波器测一测 VBAT 引脚的上电波形。如果 VBAT 电压上升斜率太慢,会导致电源切换电路判断混乱。正常情况下 VBAT 应该从 0V 很快跳到电池电压,如果出现阶梯状上升,说明电池内阻过大或线路太长,需要加粗走线或换电池。

第五,给 RTC 时间做显示时,注意 BCD 和二进制格式的区别。HAL_RTC_SetTime 和 GetTime 函数里都带了一个 RTC_FORMAT_BIN 或 RTC_FORMAT_BCD 参数。很多从汇编或寄存器开发转过来的同事,喜欢直接跟寄存器交互,容易在格式上栽跟头,读出来的时间像天书。

第六,关于“断电不停钟”的验收,不要只断电一次就算完。我在最终测试时会做一个连续掉电测试:在 RTC 走时过程中,随机时间点切断主电源,保持几秒到几分钟不等,再上电读取时间,反复 50 次,观察是否有时间倒退或跳变。这个过程能同时验证硬件和软件逻辑的鲁棒性,比单次断电更有说服力。

第七,如果产品对时间精度要求很高,比如定位设备、计费设备,不要迷信 32.768kHz 晶振的标称误差。晶振老化、温度变化、焊接应力都会改变频率。最稳妥的做法是在设备里做一个周期性校准流程,用外部标准时间源校一次,把误差补偿值存进备份寄存器,这样即使断电再上电,校准值也不会丢。

回到最开头那个场景:当你把设备断电再上电,看到串口打印出连续跳动的时间,而不是刺眼的 2000 年 1 月 1 日,那种感觉确实让人安心。STM32 RTC 的代码量不大,但它横跨硬件电路、时钟架构、低功耗设计、调试工具多个层面,每一个环节都有细节。希望这篇实战记录能让你少走点弯路,一次就把 VBAT 断电不停钟做靠谱。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 1:28:44

手机秒变蓝牙键鼠:从BLE HID到Serverless信令的跨设备控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:28:41

51单片机计算器实战:从Proteus仿真到PCB打样全流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:28:40

DDR5内存为何必须集成PMIC电源管理芯片

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:27:44

VS Code PlatformIO创建工程太慢?四招提速到两分钟

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:27:06

NMEA-0183协议详解:从GPS模块串口数据到经纬度解析实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:27:04

葡萄图像数据集目标检测实战:YOLO格式转换与迁移学习要点

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华