
一、引言如果你的设备用电池供电功耗就是产品成败的决定性因素。一个 2000mAh 的 CR2032 纽扣电池如果设备功耗是 50mA只能工作 40 小时——不到两天。但如果功耗降到 10μA就可以工作22 年超过电池自放电寿命。这不是夸张的广告语而是一个可以实现的目标。本文将系统讲解嵌入式低功耗设计的完整方法论STM32 三种低功耗模式的原理与差异外设功耗的精细化管理系统级功耗估算与电池选型低功耗调试工具与方法典型低功耗产品的设计模式平台STM32F103Cortex-M3/ STM32L4超低功耗系列 测量工具Power Profiler Kit IINordic二、功耗的基础认知2.1 功耗公式P_total P_dynamic P_static P_dynamic C × V² × f C 负载电容 V 供电电压 f 开关频率 P_static V × I_leakage 漏电流制程决定 降低功耗的三大方向 1. 降电压 V → 效果最显著平方关系 2. 降频率 f → 线性效果 3. 关断不用的模块 → 消除不必要的 C × V² × f2.2 电流量级认知┌─────────────────────────────────────────────────────────┐ │ 嵌入式系统的电流数量级 │ ├──────────┬──────────────────────────────────────────────┤ │ 100mA │ STM32F103 72MHz 全速运行 所有外设 │ │ 10mA │ STM32F103 8MHz 基本外设 │ │ 1mA │ STM32L4 低功耗运行模式Low-power run │ │ 100μA │ STM32L4 STOP 模式 RTC │ │ 10μA │ STM32L4 STOP 模式无 RTC │ │ 1μA │ STM32L4 STANDBY 模式 RTC │ │ 100nA │ STM32L4 STANDBY无 RTC │ │ 10nA │ 纯硬件方案如独立 RTC 芯片 MCU 完全断电 │ └──────────┴──────────────────────────────────────────────┘三、STM32F103 三种低功耗模式深度对比3.1 架构总览┌──────────────────────────────────────────┐ │ SLEEP 模式 │ │ CPU 停止所有外设继续运行 │ │ 唤醒任意中断 │ │ 唤醒延迟0单周期恢复 │ │ 电流~5mA72MHz取决于外设 │ ├──────────────────────────────────────────┤ │ STOP 模式 │ │ CPU 所有高速时钟(HSE/HIS/PLL)停止 │ │ LSI/LSE 可继续保留 RTC/IWDG │ │ 唤醒EXTI 线外部中断 │ │ 唤醒延迟~5μsHSE 起振时间 │ │ 电流~14μA无 RTC/~16μA有 RTC │ │ ★ RAM 内容保留 │ ├──────────────────────────────────────────┤ │ STANDBY 模式 │ │ CPU 所有时钟停止 1.8V 域断电 │ │ 只有备份域RTC备份寄存器可能存活 │ │ 唤醒WKUP 引脚 / RTC 闹钟 / IWDG 复位 │ │ 唤醒延迟~50μs全系统复位 │ │ 电流~2μA │ │ ★ RAM 内容丢失相当于冷启动 │ └──────────────────────────────────────────┘3.2 模式选择决策树开始 │ 需要保持 RAM ├── NO ──► STANDBY (最低功耗) │ └── YES ──► 需要高速外设运行(USB/USART/DMA) ├── YES ──► SLEEP │ └── NO ──► STOP3.3 完整代码实现// low_power.c —— 三种模式的完整配置 // SLEEP 模式 void EnterSleepMode(void) { // 1. 配置 SLEEPDEEP 0选择 Sleep 而非 Deep Sleep SCB-SCR ~SCB_SCR_SLEEPDEEP_Msk; // 2. 执行 WFIWait For Interrupt或 WFE __WFI(); // 任意中断唤醒后从此处继续执行 // 如果需要定时唤醒可以在进入前配置 SysTick // SysTick_Config(SystemCoreClock / 1000); // 1ms 中断唤醒 } // STOP 模式 void EnterStopMode(void) { // 1. 关闭所有不必要的外设时钟节省 STOP 模式下的静态功耗 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, DISABLE); // 2. ★ 关键将所有未用 GPIO 设为模拟输入最低功耗状态 GPIO_InitTypeDef gpio; gpio.GPIO_Mode GPIO_Mode_AIN; // 模拟输入——关闭数字输入施密特触发器 gpio.GPIO_Pin GPIO_Pin_All; GPIO_Init(GPIOA, gpio); GPIO_Init(GPIOB, gpio); GPIO_Init(GPIOC, gpio); // 但保留唤醒源引脚如 PA0 (WKUP) 或 EXTI 引脚 // PA0 作为 EXTI 唤醒源需要特殊配置 // 3. 配置唤醒源例如PA0 下降沿唤醒 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); EXTI_InitTypeDef exti; exti.EXTI_Line EXTI_Line0; exti.EXTI_Mode EXTI_Mode_Interrupt; exti.EXTI_Trigger EXTI_Trigger_Falling; exti.EXTI_LineCmd ENABLE; EXTI_Init(exti); // ★ 注意STOP 模式下只能使用 EXTI 线唤醒 // 普通 NVIC 中断不能唤醒 STOP 模式 // 4. PWR 进入 STOP 模式 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); // regulator low power 更省电但唤醒慢一点 // WFI Wait For Interrupt, WFE Wait For Event // 5. 唤醒后——重新配置时钟 SystemInit(); // 重新配置 HSE/PLL // 重新使能外设时钟 // ... } // STANDBY 模式 void EnterStandbyMode(void) { // 1. 使能 PWR 时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); // 2. 使能唤醒源WKUP 引脚 PA0 PWR_WakeUpPinCmd(ENABLE); // 3. 清除 STANDBY 标志 PWR_ClearFlag(PWR_FLAG_SB); // 4. 进入 STANDBY PWR_EnterSTANDBYMode(); // 不会执行到这里——STANDBY 唤醒后整个系统复位 // 相当于按了复位键从 Reset_Handler 重新开始 } // 检测是否从 STANDBY 唤醒 int WasStandbyWakeup(void) { return (PWR_GetFlagStatus(PWR_FLAG_SB) ! RESET); }四、外设功耗精细化管理4.1 各外设的功耗参考外设电流STM32F103 72MHz备注GPIO空闲0.1μA/引脚设为模拟输入时最低USART~1.2mA波特率越高功耗越大SPI~0.8mA连续传输时I2C~0.5mA上拉电阻消耗额外电流ADC~1.5mA连续采样模式TIMPWM~0.5mA输出驱动负载另计DMA~0.3mA连续传输时Flash 读取~10mA★ 主要功耗来源4.2 动态关断不需要的外设// 外设电源管理——按需开关 typedef enum { PERIPH_USART1 0, PERIPH_SPI1, PERIPH_ADC1, PERIPH_TIM2, // ... } periph_id_t; // 模拟外设电源域——统一管理 void Periph_PowerOn(periph_id_t id) { switch (id) { case PERIPH_USART1: RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); USART_Cmd(USART1, ENABLE); break; case PERIPH_ADC1: RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); break; // ... } } void Periph_PowerOff(periph_id_t id) { switch (id) { case PERIPH_USART1: USART_Cmd(USART1, DISABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, DISABLE); // 可以不关 GPIO 时钟可能其他外设也用 break; case PERIPH_ADC1: ADC_Cmd(ADC1, DISABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, DISABLE); break; // ... } }4.3 GPIO 的低功耗配置——最重要的一步// GPIO 在所有低功耗模式中都存在漏电流 // 以下配置可节省数十微安的功耗 void GPIO_ConfigureForLowPower(void) { GPIO_InitTypeDef gpio; // 规则 1空闲引脚 → 模拟输入关闭施密特触发器 gpio.GPIO_Mode GPIO_Mode_AIN; gpio.GPIO_Pin GPIO_Pin_All; GPIO_Init(GPIOA, gpio); GPIO_Init(GPIOB, gpio); // 规则 2输出引脚 → 根据外部电路决定状态 // 驱动 LED推挽输出低电平LED 熄灭 // 片选信号推挽输出高电平不选中外设 // I2C 总线开漏输出高电平总线空闲 // 规则 3输入引脚 → 避免浮空 // → 开启内部上拉/下拉消耗少量电流或外部上下拉 // → 如果引脚有外部确定电平使用浮空输入 关闭施密特 // (但 F103 的浮空输入仍有施密特触发器的静态功耗) // 规则 4已使用引脚但 MCU 休眠时外设断电 // → 设为模拟输入外围无电MCU 引脚不能有电流回路 }五、时钟树的功耗优化5.1 降频是最直接的省电手段// 动态频率调节Dynamic Frequency Scaling void SystemClock_SetHigh(void) { // 72MHz: 需要处理大量数据时 RCC_HSEConfig(RCC_HSE_ON); RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); RCC_HCLKConfig(RCC_SYSCLK_Div1); // 72MHz AHB RCC_PCLK2Config(RCC_HCLK_Div1); // 72MHz APB2 RCC_PCLK1Config(RCC_HCLK_Div2); // 36MHz APB1 SystemCoreClock 72000000; } void SystemClock_SetMedium(void) { // 24MHz: 日常运行时 RCC_HSEConfig(RCC_HSE_ON); RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_3); RCC_HCLKConfig(RCC_SYSCLK_Div1); SystemCoreClock 24000000; } void SystemClock_SetLow(void) { // 8MHz: 仅需基本的定时和通信 RCC_HSEConfig(RCC_HSE_ON); RCC_HCLKConfig(RCC_SYSCLK_Div1); // HSE 直接用 8MHz RCC_PLLCmd(DISABLE); SystemCoreClock 8000000; }5.2 HSI vs HSE 的功耗对比┌──────────┬──────────┬────────┬───────────────────┐ │ 时钟源 │ 频率 │ 功耗 │ 精度 │ ├──────────┼──────────┼────────┼───────────────────┤ │ HSI (RC) │ 8MHz │ ~100μA │ ±1%差 │ │ HSE (晶振)│ 8MHz │ ~500μA │ ±20ppm好 │ │ LSI (RC) │ ~40kHz │ ~0.5μA │ ±30%很差 │ │ LSE (晶振)│ 32.768kHz│ ~0.3μA │ ±20ppm好 │ └──────────┴──────────┴────────┴───────────────────┘ 选择策略 - 日常运行 → HSE精度好通信波特率准确 - STOP 模式前 → 切换到 HSI减少唤醒后等待起振时间 - 深度睡眠 → 只保留 LSE为 RTC 提供时钟六、系统级功耗估算6.1 占空比计算低功耗系统的核心降低平均功耗 I_avg (T_active × I_active T_sleep × I_sleep) / (T_active T_sleep) 示例温度传感器节点 每秒采集一次每次采集耗时 10ms - Active: 10ms 30mA - Sleep: 990ms 15μA (STOP mode) I_avg (0.01 × 30mA 0.99 × 0.015mA) / 1.0 (0.3mAs 0.01485mAs) / 1.0s 0.315mA 用 2000mAh CR2032 电池 理论寿命 2000mAh / 0.315mA 6349 小时 ≈ 264 天 优化如果把 Active 时间从 10ms 降到 1ms I_avg (0.001 × 30mA 0.999 × 0.015mA) 0.045mA 理论寿命 2000mAh / 0.045mA 44444 小时 ≈ 1852 天 ≈ 5 年6.2 功耗预算表Power Budget项目BLE 温湿度传感器CR2032 电池 ┌──────────────────────┬──────────┬────────────┬──────────┐ │ 组件 │ Active │ Sleep │ 占空比 │ ├──────────────────────┼──────────┼────────────┼──────────┤ │ MCU (STM32L4 16MHz)│ 3.2mA │ 0.8μA │ 1:100 │ │ BLE Radio (nRF52840) │ 6.0mA │ 0.4μA │ 1:100 │ │ 传感器 (SHT30) │ 0.6mA │ 0.2μA │ 1:100 │ │ LDO/DC-DC │ 0.2mA │ 0.1μA │ 100% │ ├──────────────────────┼──────────┼────────────┼──────────┤ │ 总计 │ 10.0mA │ 1.5μA │ │ │ │ │ │ │ │ 平均功耗 10mA/100 1.5μA 101.5μA │ │ │ 预计寿命 2000mAh / 0.1015mA 19704h ≈ 2.25 年│ │ └──────────────────────┴──────────┴────────────┴──────────┘七、低功耗调试7.1 电流测量方法方法一万用表串联最简单但有局限 电池 ──┬── 电路板 VCC │ 电池- ──┼── 万用表 μA 档 ── 电路板 GND │ 需要并联电容在大电流Active和 小电流Sleep切换时万用表切换量程 导致电压跌落 → MCU 复位 解决万用表两端并一个 100μF 电容 方法二Power Profiler Kit II推荐 PPK2 可以自动切换量程100nA ~ 1A 采样率 100kS/s可看到 μs 级的电流变化。 通过 USB 连接 PC用 nRF Connect 软件 实时查看电流波形。7.2 功耗异常的常见原因症状可能原因排查方法STOP 模式电流 500μAGPIO 浮空输入逐个设为模拟输入STOP 模式电流 100μA某外设时钟未关检查 RCC 寄存器SLEEP 模式电流 20mAFlash 未进入低功耗FLASH-ACR | SLEEP_PD功耗忽高忽低某任务周期性唤醒 MCU用 GPIO Toggle 定位电池寿命远低于理论DC-DC 在轻载时效率极低测量输入/输出功率差八、STM32L4 超低功耗系列特色STM32L4 在 F103 的基础上增加了更多低功耗特性// STM32L4 特有的低功耗特性代码示例 // 1. 低功耗运行模式Low-power run—— 在 STOP 电压下运行 void EnterLowPowerRun(void) { HAL_PWREx_EnableLowPowerRunMode(); // 此时系统时钟限制为 2MHz但电流仅 ~100μA // 可以做简单的 SPI 通信和定时器操作 } // 2. STOP 2 模式 —— RAM 全保留 更多的唤醒源 void EnterStop2Mode(void) { HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI); // 唤醒后不需要重新初始化外设比 F103 的 STOP 方便很多 } // 3. 灵活的时钟配置 // L4 有 MSI (多速率内部振荡器)48kHz~48MHz 可调 // 可以用 MSI 替代 HSE省掉外部晶振的功耗 void SystemClock_MSI_4MHz(void) { RCC_OscInitTypeDef osc {0}; osc.OscillatorType RCC_OSCILLATORTYPE_MSI; osc.MSIState RCC_MSI_ON; osc.MSIClockRange RCC_MSIRANGE_6; // 4MHz HAL_RCC_OscConfig(osc); }九、总结优化手段省电效果代价GPIO 全设模拟输入~20-200μA无最重要的第一步关闭不用的外设时钟~1-5mA无降低主频~3-15mA性能下降STOP 模式从 10mA → 15μA唤醒延迟 ~5μsSTANDBY 模式从 10mA → 2μARAM 丢失用 LSE 代替 LSI~2μA需外部晶振外置 DC-DC 代替 LDO~20-50% 效率提升BOM 成本核心理念低功耗不是某个神秘的低功耗模式而是每一微安的积累。把 MCU 从 72MHz 的 30mA 降到 STOP 的 15μA 是最大的一步但之后 GPIO 配置、外设管理、占空比优化同样重要。低功耗设计是一个系统工程。下一篇预告DMA 控制器与内存数据传输深度解析