STM32F4 无外部晶振秒级唤醒:LSE 停振后硬件 RTC 备份域实战指南
👁 1 阅读 · 2026-08-27 · 嵌入式
在低功耗嵌入式设计中,LSE 晶振易受环境干扰而停振,导致 RTC 失效。本文深入解析 STM32F4 备份域工作原理,提供一套无需外部晶振、仅靠内部 LSI 驱动的硬件 RTC 秒级唤醒方案。通过配置备份域寄存器、校准 LSI 频率,并利用 RTC 闹钟中断实现周期性唤醒,同时给出完整代码与调试注意事项,帮助开发者构建稳定可靠的定时唤醒系统。
# STM32F4 无外部晶振秒级唤醒:LSE 停振后硬件 RTC 备份域实战指南
## 1. 问题背景与解决方案概述
在电池供电的嵌入式产品中,LSE(32.768kHz 低速外部晶振)常用于 RTC 计时,但其起振慢、易受温湿度影响,一旦停振,RTC 将失去时钟源。传统做法是切换至 LSI(内部低速 RC 振荡器,约 32kHz),但 LSI 精度差(误差可达 ±5%),且默认不备份域供电。
本文方案:**利用 STM32F4 的备份域(Backup Domain)特性,在 LSE 停振后自动切换至 LSI,并通过 RTC 闹钟实现秒级唤醒**。核心思路是:
- 备份域由 VBAT 供电,RTC 寄存器与备份寄存器独立于主电源。
- 配置 RTC 时钟源为 LSI,并启用闹钟中断。
- 通过软件校准 LSI 频率,提高计时精度。
## 2. 硬件 RTC 备份域原理
STM32F4 的 RTC 模块位于备份域中,其供电引脚为 VBAT(通常接电池或大电容)。备份域包含:
- RTC 计数器、闹钟寄存器、预分频器。
- 20 个 32 位备份寄存器(BKP)。
- 复位控制:备份域复位(BDRST)不影响主域。
**关键点**:
- 当主电源 VDD 掉电时,备份域由 VBAT 维持,RTC 继续运行。
- LSE 和 LSI 均可作为 RTC 时钟源,但 LSE 失效时需手动切换。
- 切换时钟源前,必须进入备份域复位状态,否则写操作无效。
## 3. 配置步骤(以 STM32F407 为例)
### 3.1 使能电源与备份域时钟
```c
// 使能 PWR 和 RCC 时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
// 允许访问备份域
PWR_BackupAccessCmd(ENABLE);
```
### 3.2 检测 LSE 状态并切换至 LSI
```c
// 尝试启动 LSE,等待超时
RCC_LSEConfig(RCC_LSE_ON);
uint32_t timeout = 100000;
while ((RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) && (timeout--));
if (timeout == 0) {
// LSE 停振,切换至 LSI
RCC_LSICmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);
// 备份域复位,重新配置 RTC
RCC_BackupResetCmd(ENABLE);
RCC_BackupResetCmd(DISABLE);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
RCC_RTCCLKCmd(ENABLE);
// 初始化 RTC
RTC_InitTypeDef RTC_InitStruct;
RTC_StructInit(&RTC_InitStruct);
RTC_InitStruct.RTC_HourFormat = RTC_HourFormat_24;
RTC_InitStruct.RTC_AsynchPrediv = 0x7F; // 128 分频
RTC_InitStruct.RTC_SynchPrediv = 0x00; // 1 分频,得到 1Hz
RTC_Init(&RTC_InitStruct);
} else {
// LSE 正常,使用 LSE
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
// 正常初始化 RTC...
}
```
### 3.3 配置 RTC 闹钟中断
```c
// 设置闹钟时间为 1 秒后
RTC_AlarmTypeDef RTC_AlarmStruct;
RTC_AlarmStruct.RTC_AlarmTime.RTC_H12 = RTC_H12_AM;
RTC_AlarmStruct.RTC_AlarmTime.RTC_Hours = 0;
RTC_AlarmStruct.RTC_AlarmTime.RTC_Minutes = 0;
RTC_AlarmStruct.RTC_AlarmTime.RTC_Seconds = 1;
RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay; // 仅匹配时间
RTC_AlarmStruct.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_Date;
RTC_AlarmStruct.RTC_AlarmDateWeekDay = 1;
RTC_SetAlarm(RTC_Alarm_A, &RTC_AlarmStruct);
// 使能闹钟中断
RTC_ITConfig(RTC_IT_ALRA, ENABLE);
// 配置 EXTI 线 17(RTC 闹钟)
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line = EXTI_Line17;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
// 使能 NVIC 中断
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = RTC_Alarm_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
```
### 3.4 进入低功耗模式并等待唤醒
```c
// 进入 STOP 模式,RTC 闹钟可唤醒
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
// 唤醒后重新配置系统时钟(因为 STOP 模式会关闭 HSI/HSE)
SystemInit();
```
## 4. 完整代码示例(关键部分)
```c
// 主函数示例
int main(void) {
// 初始化时钟、GPIO、串口等...
// 配置 RTC 备份域唤醒
RTC_BackupInit();
while (1) {
// 进入 STOP 模式,等待闹钟唤醒
__WFI();
// 唤醒后处理任务
printf("Wake up!\n");
}
}
void RTC_Alarm_IRQHandler(void) {
if (RTC_GetITStatus(RTC_IT_ALRA) != RESET) {
RTC_ClearITPendingBit(RTC_IT_ALRA);
// 重新设置闹钟为 1 秒后
RTC_SetAlarm(RTC_Alarm_A, &alarmStruct);
// 可在此翻转 LED 等
}
}
```
## 5. 注意事项与调试技巧
- **备份域复位**:切换时钟源前必须执行 `RCC_BackupResetCmd(ENABLE)`,否则 RTC 配置无效。
- **LSI 校准**:LSI 频率随温度变化,可在运行时测量 LSI 频率(通过 TIM5 捕获),并调整异步预分频值来补偿。例如,若测得 LSI 为 32.2kHz,则设置 `RTC_AsynchPrediv = 0x7D`(约 125 分频)得到 1Hz。
- **唤醒后时钟恢复**:从 STOP 模式唤醒后,系统时钟默认使用 HSI,需重新配置 PLL 等,否则外设可能异常。
- **VBAT 供电**:确保 VBAT 引脚连接电池或大电容(如 1F 超级电容),否则备份域数据丢失。
- **调试时**:建议先用串口打印 RTC 当前时间,验证秒级递增是否正常。
- **低功耗电流**:使用 LSI 时功耗略高于 LSE,但可接受;若需更低功耗,可考虑外部 32.768kHz 晶振并做好抗干扰设计。
## 6. 总结
通过备份域与 LSI 的配合,STM32F4 在 LSE 停振后仍能实现可靠的秒级唤醒。本方案无需外部晶振,降低了 BOM 成本,同时利用备份域保持 RTC 计时,适合对成本敏感且环境恶劣的嵌入式应用。关键在于正确配置备份域复位、时钟切换和闹钟中断,并注意唤醒后的时钟恢复。