STM32 进阶封神之路(二十三):低功耗深度解析 ------ 从睡眠模式到停机模式(底层原理 + 寄存器配置)
上一篇我们掌握了 DMA 多场景实战,这一篇聚焦嵌入式系统的 "续航核心"------STM32 低功耗技术。在电池供电场景(如智能穿戴、传感器节点、物联网设备)中,低功耗直接决定设备续航能力,STM32F103 支持三种核心低功耗模式(睡眠模式、停止模式、待机模式),各自适配不同功耗与唤醒需求。
本文基于实战资料,从低功耗核心价值、STM32 电源架构、三种模式原理对比,到寄存器配置、唤醒机制,手把手带你吃透低功耗的底层逻辑,为下一篇实战(电池供电传感器节点)打下坚实基础!
一、低功耗核心认知:为什么它是嵌入式必备技能?
1. 低功耗的核心价值与应用场景
(1)核心价值
- 延长续航:电池供电设备(如物联网传感器节点)通过降低非工作状态功耗,可将续航从几天延长至数月甚至数年;
- 降低发热:减少无效功耗,降低芯片发热,提升设备稳定性(尤其工业控制场景);
- 适配严格功耗要求:部分场景(如医疗设备、无线传感器)对功耗有强制限制,低功耗是必备特性。
(2)典型应用场景
- 物联网(IoT)传感器节点:如土壤湿度传感器、温湿度采集器,定期唤醒采集数据,其余时间休眠;
- 智能穿戴设备:如手环、手表,仅在屏幕点亮、数据更新时高功耗运行;
- 无线通信设备:如蓝牙模块、LoRa 模块,通信完成后进入低功耗模式;
- 电池供电的工业控制设备:如远程阀门控制器、数据记录仪。
2. STM32 电源架构解析(低功耗的硬件基础)
STM32F103 的电源系统分为 "主电源域" 和 "备份域",低功耗模式的本质是通过关闭不同电源域的外设时钟、降低核心电压,实现功耗优化:
(1)核心电源域划分
表格
| 电源域 | 包含组件 | 供电来源 | 低功耗控制方式 |
|---|---|---|---|
| 主电源域(VDD) | CPU、GPIO、ADC、定时器、USART 等核心外设 | 主电源(3.3V) | 关闭外设时钟、降低核心电压、停止 CPU 运行 |
| 备份域(VBAT) | RTC、BKP 寄存器 | 主电源 / VBAT 备用电源 | 独立供电,主电源关闭时由 VBAT 维持工作 |
(2)电源管理单元(PMU)核心作用
STM32 内置 PMU(电源管理单元),负责:
- 电压调节:根据工作模式调节核心电压(VCORE),低功耗模式下降低 VCORE;
- 模式切换:响应软件指令,切换 CPU 和外设的工作状态;
- 唤醒检测:检测唤醒源,触发系统从低功耗模式恢复。
3. STM32 三种低功耗模式核心对比(面试高频)
STM32F103 支持三种低功耗模式,核心差异体现在功耗、唤醒时间、保留资源三个维度,实战需根据需求选型:
表格
| 对比维度 | 睡眠模式(Sleep) | 停止模式(Stop) | 待机模式(Standby) |
|---|---|---|---|
| 核心状态 | CPU 停止,外设正常运行 | CPU 停止,外设时钟关闭 | 整个芯片近乎断电,仅备份域工作 |
| 典型功耗(3.3V) | 1~5mA | 10~50μA | 1~5μA |
| 唤醒时间 | 极短(≤1μs) | 中等(≤10μs) | 较长(≤1ms) |
| 保留资源 | 所有寄存器、RAM 数据 | 寄存器、RAM 数据 | 仅备份域(RTC/BKP)数据 |
| 唤醒源 | 任意中断(如 USART、TIM、EXTI) | 外部中断(EXTI)、RTC 闹钟、USB 唤醒 | WKUP 引脚上升沿、RTC 闹钟 |
| 退出后状态 | 从当前指令继续执行 | 从停止模式指令后继续执行 | 相当于上电复位(需重新初始化) |
| 适用场景 | 短时间等待(如等待串口数据) | 长时间低功耗(如传感器定时采集) | 超长时间休眠(如设备待机) |
4. 低功耗关键术语(必掌握)
- 静态功耗:芯片无活动时的功耗(如待机模式下的漏电流);
- 动态功耗:芯片运行时的功耗(与时钟频率、核心电压正相关);
- 唤醒源:触发系统从低功耗模式恢复的事件(中断、引脚信号、RTC 闹钟等);
- 电压调节:低功耗模式下降低核心电压(VCORE),减少静态功耗;
- 时钟门控:关闭未使用外设的时钟,避免无效功耗。
二、睡眠模式深度解析:轻量级低功耗(CPU 休眠,外设运行)
睡眠模式是 "最轻量级" 的低功耗模式,核心是 "CPU 停止运行,外设保持工作",唤醒后可快速恢复执行,适合短时间等待场景。
1. 睡眠模式工作原理
- CPU 停止取指和执行指令,但内核寄存器、RAM 数据完全保留;
- 所有外设(USART、TIM、ADC、DMA 等)正常运行,时钟保持不变;
- 功耗主要来自外设运行,比正常模式略低(约为正常模式的 50%~80%);
- 任意中断触发后,CPU 立即唤醒,从暂停的指令继续执行。
2. 睡眠模式两种类型(库函数配置)
STM32 睡眠模式分为 "普通睡眠" 和 "深度睡眠",核心区别是 "睡眠时是否响应内核暂停请求":
表格
| 类型 | 库函数配置 | 核心特点 | 适用场景 |
|---|---|---|---|
| 普通睡眠 | __WFI()(Wait For Interrupt) |
等待中断,仅 CPU 停止,外设正常 | 等待外部事件(如串口数据、按键中断) |
| 深度睡眠 | __WFE()(Wait For Event) |
等待事件,可响应内核暂停请求 | 需降低更多功耗,且事件触发后快速唤醒 |
3. 睡眠模式寄存器配置(底层逻辑)
睡眠模式通过操作 SLEEPDEEP 位和 SLEEPONEXIT 位控制,核心寄存器为SCB->SCR(系统控制寄存器):
c
运行
// 1. 普通睡眠模式配置(__WFI())
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; // SLEEPDEEP=0(普通睡眠)
__WFI(); // 进入睡眠,等待中断唤醒
// 2. 深度睡眠模式配置(__WFE())
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; // SLEEPDEEP=1(深度睡眠)
__WFE(); // 进入深度睡眠,等待事件唤醒
关键寄存器位说明:
SLEEPDEEP(SCB_SCR [2]):0 = 普通睡眠,1 = 深度睡眠;SLEEPONEXIT(SCB_SCR [1]):1 = 中断处理完成后自动返回睡眠模式,0 = 唤醒后继续执行。
4. 睡眠模式实战配置步骤(库函数版)
c
运行
// 睡眠模式初始化(以USART1中断唤醒为例)
void Sleep_Mode_Init(void) {
// 1. 初始化USART1(用于触发唤醒)
USART1_Init(); // 串口初始化(115200bps,使能接收中断)
// 2. 配置睡眠模式(普通睡眠,等待中断)
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; // 普通睡眠模式
}
// 进入睡眠模式
void Enter_Sleep_Mode(void) {
printf("进入睡眠模式,等待串口数据唤醒...\r\n");
__WFI(); // 等待USART1接收中断唤醒
printf("从睡眠模式唤醒!\r\n");
}
// USART1接收中断服务函数(唤醒源)
void USART1_IRQHandler(void) {
uint8_t rx_data;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
rx_data = USART_ReceiveData(USART1);
printf("接收数据:%c,触发唤醒\r\n", rx_data);
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
5. 睡眠模式关键注意事项
- 唤醒后无需重新初始化外设,RAM 和寄存器数据保留;
- 若需 "唤醒后自动返回睡眠",可设置
SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk; - 功耗降低有限,不适合长时间低功耗场景,仅用于短时间等待。
三、停止模式深度解析:中量级低功耗(CPU + 外设时钟关闭)
停止模式是 "最常用" 的低功耗模式,核心是 "CPU 停止,外设时钟关闭",功耗大幅降低(μA 级),同时保留 RAM 和寄存器数据,唤醒后可快速恢复,适合长时间低功耗场景。
1. 停止模式工作原理
- CPU 停止运行,所有外设时钟(HSE、HSI、APB1、APB2)关闭;
- 核心电压(VCORE)降低至低功耗水平,静态功耗显著减少;
- RAM 和寄存器数据完全保留,唤醒后无需重新初始化外设(仅需重启时钟);
- 仅支持特定唤醒源(外部中断 EXTI、RTC 闹钟、USB 唤醒),其他中断无法唤醒。
2. 停止模式核心配置步骤(库函数版)
停止模式配置需遵循 "关闭外设时钟→配置唤醒源→设置停止模式→进入低功耗" 的顺序:
c
运行
// 停止模式初始化(以EXTI0按键中断+RTC闹钟唤醒为例)
void Stop_Mode_Init(void) {
// 1. 配置EXTI0按键唤醒(PA0,下降沿触发)
GPIO_InitTypeDef GPIO_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
// 使能GPIOA和AFIO时钟(EXTI依赖AFIO)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
// 配置PA0为浮空输入
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置EXTI0中断(PA0映射到EXTI0)
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
EXTI_InitStruct.EXTI_Line = EXTI_Line0;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿触发
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
// 配置NVIC中断优先级
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
// 2. 配置RTC闹钟唤醒(可选,增加唤醒源)
RTC_Config(); // RTC初始化,配置闹钟时间(如每隔10秒触发一次)
}
// 进入停止模式
void Enter_Stop_Mode(void) {
// 1. 关闭不必要的外设时钟(降低功耗)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_ADC1, DISABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_USART2, DISABLE);
// 2. 配置PWR电源管理(停止模式核心配置)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); // 使能PWR时钟
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); // 进入停止模式
// 3. 唤醒后重启时钟(停止模式下时钟关闭,需重新配置)
SystemInit(); // 重启系统时钟(或手动配置HSE/HSI)
printf("从停止模式唤醒!\r\n");
}
// EXTI0中断服务函数(唤醒源)
void EXTI0_IRQHandler(void) {
if(EXTI_GetITStatus(EXTI_Line0) != RESET) {
printf("按键触发停止模式唤醒!\r\n");
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
// RTC闹钟中断服务函数(唤醒源)
void RTC_IRQHandler(void) {
if(RTC_GetITStatus(RTC_IT_ALR) != RESET) {
printf("RTC闹钟触发停止模式唤醒!\r\n");
RTC_ClearITPendingBit(RTC_IT_ALR);
RTC_WaitForLastTask();
}
}
3. 停止模式寄存器配置(底层逻辑)
停止模式核心是通过 PWR 寄存器配置电压调节器和进入方式:
c
运行
// 底层寄存器配置停止模式
void Enter_Stop_Mode_Reg(void) {
// 1. 使能PWR时钟
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
// 2. 配置电压调节器为低功耗模式(PWR_CR[1] = LPSDSR=1)
PWR->CR |= PWR_CR_LPSDSR;
// 3. 配置SLEEPDEEP=1(深度睡眠)
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
// 4. 进入停止模式(WFI等待中断)
__WFI();
// 5. 唤醒后重启时钟
SystemInit();
}
4. 停止模式关键注意事项
- 唤醒后必须重新配置系统时钟(停止模式下 HSE/HSI 关闭);
- 仅支持特定唤醒源(EXTI、RTC 闹钟、USB 唤醒),其他中断无法唤醒;
- 关闭不必要的外设时钟可进一步降低功耗;
- 电压调节器选择 "低功耗模式"(
PWR_Regulator_LowPower),比 "正常模式" 功耗更低。
四、待机模式深度解析:重量级低功耗(近乎断电,仅备份域工作)
待机模式是 "功耗最低" 的低功耗模式,核心是 "整个芯片近乎断电,仅备份域(RTC/BKP)工作",适合超长时间休眠场景(如设备待机、电池供电设备长时间不工作)。
1. 待机模式工作原理
- 主电源域(VDD)断电,仅备份域(VBAT)供电;
- CPU、所有外设完全断电,RAM 和寄存器数据丢失(仅备份域数据保留);
- 功耗极低(μA 级),仅来自备份域的漏电流;
- 唤醒后相当于上电复位,需重新执行初始化流程(
main函数从头开始)。
2. 待机模式核心配置步骤(库函数版)
c
运行
// 待机模式初始化(以WKUP引脚+RTC闹钟唤醒为例)
void Standby_Mode_Init(void) {
// 1. 配置WKUP引脚(PA0,上升沿唤醒)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 2. 配置RTC闹钟唤醒(备份域工作,掉电不丢失)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE); // 解除备份域写保护
RTC_Config(); // 配置RTC闹钟(如每隔1分钟触发一次)
// 3. 清除待机标志位(若之前进入过待机模式)
PWR_ClearFlag(PWR_FLAG_SB);
}
// 进入待机模式
void Enter_Standby_Mode(void) {
printf("进入待机模式,等待WKUP引脚或RTC闹钟唤醒...\r\n");
// 1. 使能PWR时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
// 2. 配置待机模式(使能WKUP引脚唤醒)
PWR_WakeUpPinCmd(ENABLE); // 使能WKUP引脚
// 3. 进入待机模式
PWR_EnterSTANDBYMode(); // 进入待机模式(无返回值,相当于复位)
}
// RTC闹钟中断服务函数(唤醒源,仅备份域工作)
void RTC_IRQHandler(void) {
if(RTC_GetITStatus(RTC_IT_ALR) != RESET) {
// 待机模式下RTC中断触发唤醒,无需处理(唤醒后重新初始化)
RTC_ClearITPendingBit(RTC_IT_ALR);
RTC_WaitForLastTask();
}
}
3. 待机模式寄存器配置(底层逻辑)
c
运行
// 底层寄存器配置待机模式
void Enter_Standby_Mode_Reg(void) {
// 1. 使能PWR和BKP时钟
RCC->APB1ENR |= RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN;
// 2. 解除备份域写保护
PWR->CR |= PWR_CR_DBP;
// 3. 使能WKUP引脚唤醒(PWR_CR[8] = EWUP=1)
PWR->CR |= PWR_CR_EWUP;
// 4. 清除待机标志位(PWR_CSR[0] = SBF=0)
PWR->CR |= PWR_CR_CWUF;
// 5. 配置SLEEPDEEP=1
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
// 6. 进入待机模式
__WFI();
}
4. 待机模式关键注意事项
- 唤醒后相当于上电复位,所有外设和 RAM 数据丢失,需重新初始化;
- 仅支持 WKUP 引脚上升沿和 RTC 闹钟唤醒,其他中断无法唤醒;
- 必须解除备份域写保护才能配置 RTC;
- 进入待机模式前需清除待机标志位(
PWR_FLAG_SB),否则可能无法正常进入。
五、低功耗模式唤醒源深度解析(实战核心)
唤醒源是低功耗模式的 "触发条件",不同模式支持的唤醒源不同,合理选择唤醒源是低功耗实战的关键。
1. 常用唤醒源分类与配置
(1)外部中断(EXTI)唤醒
- 支持模式:睡眠模式、停止模式;
- 配置要点:将 GPIO 引脚映射到 EXTI 线,配置触发方式(上升沿 / 下降沿 / 双边沿);
- 典型应用:按键唤醒、传感器中断唤醒(如 PIR 人体感应传感器)。
(2)RTC 闹钟唤醒
- 支持模式:睡眠模式、停止模式、待机模式;
- 配置要点:配置 RTC 闹钟时间,使能 RTC 闹钟中断;
- 典型应用:定时唤醒(如传感器每隔 10 秒采集一次数据)。
(3)USART 中断唤醒
- 支持模式:仅睡眠模式;
- 配置要点:使能 USART 接收中断,串口接收数据时触发唤醒;
- 典型应用:等待串口指令唤醒(如蓝牙模块发送指令)。
(4)WKUP 引脚唤醒
- 支持模式:仅待机模式;
- 配置要点:使能 WKUP 引脚(PA0),上升沿触发;
- 典型应用:按键唤醒待机模式的设备。
(5)USB 唤醒
- 支持模式:仅停止模式;
- 配置要点:使能 USB 唤醒功能,USB 设备连接时触发唤醒;
- 典型应用:USB 设备连接唤醒低功耗设备。
2. 唤醒源优先级与冲突处理
- 多个唤醒源同时触发时,按 NVIC 中断优先级仲裁;
- 待机模式下,RTC 闹钟和 WKUP 引脚唤醒无优先级,哪个先触发哪个生效;
- 停止模式下,外部中断优先级高于 RTC 闹钟唤醒。
六、低功耗相关面试高频题(附标准答案)
1. 问题 1:STM32F103 支持哪些低功耗模式?各自的核心特点和适用场景是什么?
标准答案:
- 支持三种低功耗模式:睡眠模式、停止模式、待机模式;
- 核心特点与适用场景:
- 睡眠模式:CPU 停止,外设运行,唤醒快(≤1μs),保留所有数据,适用于短时间等待(如等待串口数据);
- 停止模式:CPU + 外设时钟关闭,功耗低(10~50μA),保留 RAM / 寄存器数据,唤醒源为 EXTI/RTC,适用于长时间低功耗(如传感器定时采集);
- 待机模式:近乎断电,功耗最低(1~5μA),仅保留备份域数据,唤醒后复位,适用于超长时间休眠(如设备待机)。
2. 问题 2:停止模式和待机模式的核心区别是什么?
标准答案:
- 功耗:待机模式功耗(1~5μA)远低于停止模式(10~50μA);
- 保留资源:停止模式保留 RAM 和寄存器数据,待机模式仅保留备份域数据;
- 唤醒源:停止模式支持 EXTI/RTC/USB 唤醒,待机模式仅支持 WKUP 引脚和 RTC 唤醒;
- 退出后状态:停止模式唤醒后从当前指令继续执行,待机模式唤醒后相当于上电复位;
- 适用场景:停止模式适合定时唤醒采集,待机模式适合超长时间不工作的场景。
3. 问题 3:如何降低 STM32 的功耗?除了低功耗模式,还有哪些优化手段?
标准答案:
- 低功耗模式选择:根据场景选择睡眠 / 停止 / 待机模式;
- 其他优化手段:
- 降低系统时钟频率:动态调整时钟(如不需要高速时切换到 HSI 8MHz);
- 关闭未使用外设时钟:如关闭未使用的 USART、ADC、TIM 时钟;
- 优化 GPIO 配置:未使用的 GPIO 配置为输入模式(减少漏电流);
- 降低核心电压:低功耗模式下启用电压调节器低功耗模式;
- 减少中断频率:避免频繁触发中断(如优化串口接收缓冲区);
- 使用 DMA 传输:减少 CPU 干预,降低动态功耗。
4. 问题 4:STM32 从停止模式唤醒后,为什么需要重新配置系统时钟?
标准答案:
- 停止模式的核心是 "关闭所有外设时钟(HSE、HSI、APB1、APB2)",以降低功耗;
- 唤醒后,所有时钟处于关闭状态,CPU 和外设无法正常工作;
- 因此需要重新配置系统时钟(如通过
SystemInit函数重启时钟,或手动初始化 HSE/HSI),才能恢复外设和 CPU 的正常运行。
七、总结:低功耗底层原理核心要点与实战铺垫
1. 核心要点回顾
- STM32 三种低功耗模式:睡眠(轻量级,快速唤醒)、停止(中量级,低功耗)、待机(重量级,最低功耗);
- 核心选择逻辑:根据 "功耗要求" 和 "唤醒速度" 选型,短等待用睡眠,长休眠用停止 / 待机;
- 配置关键:睡眠模式需使能中断,停止模式需配置唤醒源 + 重启时钟,待机模式需配置备份域;
- 唤醒源:睡眠模式支持任意中断,停止模式支持 EXTI/RTC,待机模式支持 WKUP/RTC。
2. 下一篇实战铺垫
掌握底层原理后,下一篇我们将聚焦低功耗实战开发,覆盖:
- 电池供电传感器节点:结合 DHT11+RTC,实现 "定时唤醒采集→发送数据→进入停止模式";
- 功耗优化实战:关闭未使用外设、动态调整时钟、优化 GPIO 配置,进一步降低功耗;
- 唤醒源联动:RTC 闹钟 + EXTI 按键双唤醒源,提高设备可靠性;
- 功耗测试:通过万用表测量不同模式下的功耗,验证优化效果。