先说结论:STM32做低功耗,Stop模式是性价比最高的选择——功耗够低(几μA)、唤醒源多、寄存器数据还能保存,绝大多数电池供电项目用它就够了。如果对功耗要求极致(比如要电池用10年),再考虑Standby模式,但代价是唤醒后要从头启动,实时性差一些。Sleep模式功耗太高,一般不用。
做低功耗设计,最忌讳的就是"软件优化了半天,结果硬件上有个漏电流"。我们团队做过不少电池供电项目,最有代表性的是TMR(隧道磁阻)流量计——用一节3.6V锂亚电池,要求至少用6年。最开始做出来的板子,休眠电流3mA,按这个速度,电池半年就没了。后来一点点抠,最后做到了休眠约2μA,唤醒采集+上报总共不到5ms,电池寿命轻松超过8年。
今天把这些年踩过的坑、总结的经验都写出来。做低功耗是个细活,差一个μA都可能影响电池寿命好几年。
一、STM32的3种低功耗模式,到底该选哪个
STM32(以L4系列为例)有三种主要的低功耗模式,从浅到深分别是:Sleep、Stop、Standby。越往深功耗越低,但唤醒也越麻烦。
| 模式 | 典型功耗(3.3V) | 内核状态 | 外设/寄存器 | 唤醒方式 | 唤醒时间 |
|---|---|---|---|---|---|
| Sleep(睡眠) | 约1~3 mA | 停止,时钟关闭 | 全部保持运行 | 任意中断 | 即时(几个时钟周期) |
| Stop(停止) | 约0.5~5 μA | 停止,时钟关闭 | 寄存器保持,SRAM保持 | 外部中断、RTC、LPTIM等 | 约3~20 μs |
| Standby(待机) | 约0.1~0.5 μA | 断电 | 大部分掉电,仅备份域保持 | WKUP引脚、RTC闹钟 | 约2~5 ms(相当于重新启动) |
三种模式怎么选?我们的经验:
- Sleep模式:几乎不用。功耗还是毫安级,跟运行模式差不了多少,还不如优化一下运行时间。
- Stop模式:首选。功耗降到了μA级,唤醒也快,寄存器数据还在,唤醒后可以接着跑。大多数电池供电项目用这个就够了。
- Standby模式:极致功耗场景用。比如那种一天只需要工作几次、每次工作时间很短的设备。缺点是唤醒相当于重启,程序要从头跑,实时性差。
二、硬件低功耗设计要点——比软件更重要
很多人做低功耗,一上来就调软件、配寄存器,折腾半天发现功耗降不下来。最后一查,是硬件的问题——某个IO没配置好、某个芯片没断电、LDO静态电流太大。
低功耗设计,硬件是基础。硬件没设计好,软件再怎么优化也白搭。
1. 电源设计:选对LDO是第一步
LDO的静态电流(IQ)是低功耗设计里最容易被忽视的参数。普通LDO的静态电流可能有几十μA甚至上百μA,而低功耗LDO的静态电流可以做到1μA以下。差了100倍!
| LDO型号 | 静态电流(典型) | 输出电流 | 价格(约) | 适用场景 |
|---|---|---|---|---|
| AMS1117-3.3 | ~5 mA | 1A | 0.2元 | 供电充足的场景,别用在低功耗 |
| HT7333 | ~4 μA | 250mA | 0.3元 | 一般低功耗,性价比高 |
| TPS78233 | ~0.5 μA | 150mA | 2元 | 极致低功耗,TI的贵但靠谱 |
| MCP1700 | ~1.6 μA | 200mA | 1元 | 低功耗,Microchip的,性价比不错 |
2. 不用的外设要断电
如果有些外设不是一直要用(比如传感器、通信模块),就不要让它一直待机,不用的时候把电源关掉。怎么关?用MOS管做电源开关,MCU的IO控制MOS管的栅极。
举个例子:NB-IoT模块,待机电流可能有几mA甚至几十mA,如果一直开着,电池用不了多久。我们的做法是:需要上传数据的时候才给模块上电,传完就关掉。模块开机+连网+上传+关机,整个过程不到10秒,虽然电流大(峰值可能200mA),但时间短,平均下来功耗还是很低的。
3. IO口配置——这个坑踩的人最多
进入低功耗模式前,所有不用的IO口一定要配置好。如果IO口悬空或者状态不对,可能会有额外的漏电流。
我们的配置原则:
- 不用的IO:配置成模拟输入(Analog模式),这是功耗最低的状态
- 外部有上拉/下拉的IO:跟外部电平保持一致,别反着来。比如外部有10K上拉,你内部就别再下拉了,不然电流从上拉流到下拉,白白消耗
- 输出IO:进入低功耗前,输出什么电平要想好。比如控制MOS管关断的IO,要输出关断的那个电平
- 调试接口(SWD):量产版可以把SWD引脚改成普通IO,省一点电。但开发阶段别改,不然调试器连不上
4. 传感器选型——静态电流很关键
传感器的待机/静态电流,对整个系统功耗影响很大。选传感器的时候,别只看精度和价格,静态电流一定要看。
比如温度传感器,普通的可能待机电流几μA,低功耗的可能只有0.1μA。看起来差得不多,但如果你的系统休眠电流总共才2μA,多了3μA就等于功耗翻倍了。
三、软件低功耗优化——细节决定成败
硬件没问题了,软件才能发挥作用。低功耗的软件优化,核心思想就是:能睡觉就睡觉,能少干活就少干活,醒着的时候越快干完越好。
1. 合理选择低功耗模式
前面说了,大多数场景用Stop模式就够了。那具体怎么进Stop模式呢?以STM32L4为例,大概是这么个流程:
// 进入Stop模式前的准备工作 —— 每一步都不能少,少一步功耗就可能下不去 void enter_stop_mode(void) { // 1. 关闭所有不用的外设时钟 —— 省电流的大头 __HAL_RCC_GPIOA_CLK_DISABLE(); __HAL_RCC_GPIOB_CLK_DISABLE(); __HAL_RCC_GPIOC_CLK_DISABLE(); // 注意:用到的外设(比如RTC、LPTIM)时钟不能关 // 团队经验:GPIO时钟关了功耗能降不少,但要注意唤醒后重新打开 // 2. 配置不用的IO为模拟输入 —— 减少漏电流 // 这个函数自己写,把所有不用的引脚都设成Analog + NoPull GPIO_set_all_analog(); // 3. 关闭SysTick —— 不然SysTick中断会把它唤醒 HAL_SuspendTick(); // 4. 配置低功耗调节器 —— Stop模式下用低功耗调节器更省电 HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE2); // 5. 进入Stop模式 HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI); // STM32L4有Stop0/Stop1/Stop2三种,Stop2功耗最低 // 实测发现:Stop2比Stop0大约省30%的电流 // 6. 唤醒后重新配置时钟 —— Stop模式下HSI/HSE都停了 SystemClock_Config(); // 7. 恢复SysTick HAL_ResumeTick(); // 8. 恢复GPIO和外设时钟 GPIO_restore_config(); __HAL_RCC_GPIOA_CLK_ENABLE(); // ... 其他外设恢复 } // 这里容易踩坑:唤醒后一定要重新配置系统时钟 // Stop模式出来默认用的是MSI,频率很低,不重新配的话系统跑得巨慢 // 很多人唤醒后发现串口波特率不对、延时不准,就是这个原因
2. 唤醒源的选择
Stop模式下可以用的唤醒源很多,常用的有:
- RTC闹钟/唤醒定时器:最常用,定时唤醒,比如每5秒醒一次采集数据
- 外部中断(EXTI):比如按键唤醒、传感器中断唤醒
- LPTIM(低功耗定时器):比RTC更灵活,可以做更短周期的定时
- USART/LPUART:串口收到数据唤醒,适合需要随时响应的场景
选哪个唤醒源,看你的应用场景。大多数周期性采集的设备,用RTC就够了。
3. 运行时也要省——降低频率、缩短时间
低功耗不只是休眠的时候省,醒着的时候也要省。两个原则:
原则一:能用低频就不用高频。比如采集个传感器数据,不需要80MHz跑,8MHz就够了。频率越低,电流越小。STM32L4在80MHz运行时约15mA,降到8MHz就只有2mA左右,差了7倍多。
原则二:醒着的时间越短越好。醒来之后,赶紧把该干的事干完,干完马上回去睡觉。别在那磨磨蹭蹭的。比如采集+计算+存储,能在5ms内干完就别拖到10ms。
// 低功耗设备的主循环大概长这样 —— 醒来干活,干完睡觉 int main(void) { system_init(); while (1) { // 醒着的时候:干活 read_sensor(); // 读传感器 process_data(); // 处理数据 check_alarm(); // 判断报警 // 到了上报时间才传数据,平时就存本地 if (time_to_upload()) { upload_data(); // 上传到云平台 } // 干完了?赶紧睡觉! enter_stop_mode(); // 睡5秒,RTC唤醒,然后循环往复 } } // 团队经验:休眠占空比是关键指标 // 比如5秒醒一次,每次醒5ms,占空比 = 5ms / 5000ms = 0.1% // 也就是说,99.9%的时间都在睡觉,平均功耗主要由休眠电流决定 // 所以优化休眠电流比优化运行电流更划算
4. 中断唤醒 vs 轮询——别傻等
运行的时候,也要尽量用中断代替轮询。比如等传感器转换完成,别在那死循环等,开个中断,转换完了再继续。等待的时间里,CPU可以进Sleep模式(虽然Sleep功耗不低,但比全速跑空循环强)。
四、TMR流量计项目:从3mA到2μA的优化过程
说再多理论,不如看个实际案例。我们给客户做的TMR(隧道磁阻)流量计,要求用一节3.6V/8500mAh的锂亚电池供电,寿命不少于6年。
第一版做出来的时候,测了一下休眠电流:约3mA。按这个算,8500mAh / 3mA ≈ 2833小时 ≈ 118天,也就4个月。差距太大了。
然后我们开始了漫长的优化过程,一步一步抠:
| 优化步骤 | 优化后休眠电流 | 降低了多少 | 说明 |
|---|---|---|---|
| 初始版本(F103 + AMS1117) | ~3000 μA | — | 啥也没优化,跑的就是个半成品 |
| 换LDO:AMS1117 → HT7333 | ~250 μA | 降了约92% | LDO本身的静态电流从5mA降到4μA |
| 换芯片:STM32F103 → STM32L431 | ~35 μA | 降了约86% | 低功耗系列的Stop模式就是给力 |
| 配置不用的IO为模拟输入 | ~18 μA | 降了约49% | 悬空的IO有漏电流,一个个改完就下来了 |
| 关闭不用的外设时钟 | ~8 μA | 降了约56% | GPIO、ADC、SPI不用的时钟全关掉 |
| 传感器电源用MOS管控制,休眠时断电 | ~4 μA | 降了约50% | TMR传感器待机电流有4μA,断掉就没了 |
| 进一步优化:用Stop2模式+低功耗调节器 | ~2 μA | 降了约50% | 最终稳定在2μA左右 |
最后做到了约2μA的休眠电流,加上每次唤醒的平均电流,算下来平均功耗约3μA。8500mAh / 3μA ≈ 283万小时 ≈ 323年——当然这是理论值,电池有自放电,实际打个折,用10年以上没问题。
五、功耗怎么测?工具和方法
做低功耗,没有合适的测量工具可不行。普通的万用表只能测毫安级的电流,微安级的就不准了。
我们常用的测功耗的工具:
- 数字源表(Keithley 2400等):最准确,nA级都能测,但贵,几万块一台。公司有条件的话买一台,绝对值。
- 功耗分析仪(Power Profiler Kit II):Nordic出的,便宜(一千多块),还能连电脑看实时电流曲线。我们用得最多,性价比最高。
- 高精度万用表(μA级):测静态电流可以,测动态电流不行。
- 串联电阻+示波器:土方法,串个小电阻(比如10Ω),用示波器测电阻两端电压换算电流。能看波形,但精度一般。
测量的时候要注意:
- 用稳压电源供电,别用电池测,电池电压会变,影响读数
- 等电流稳定了再读——刚进入低功耗模式的时候电流可能需要一段时间才降下来
- 多测几次取平均,电流有时候会波动
- 注意单位换算:1A = 1000mA = 1,000,000μA = 1,000,000,000nA
六、常见的6个低功耗大坑
坑1:调试器连着测功耗
现象:怎么测休眠电流都有几百μA,比预期高很多。
原因:SWD调试接口连着呢,调试器会给板子供电或者灌电流。
解决:测功耗一定要把调试器拔掉!用电池或者独立电源供电。我们团队新人第一次测功耗,基本都会踩这个坑。
坑2:串口连着导致电流下不去
现象:休眠电流偏高,拔掉串口线就正常了。
原因:串口的TX/RX引脚,如果另一端接了USB转串口模块,电流会从串口线倒灌进MCU。
解决:测功耗的时候把所有外接的线都拔了,只留电源线。量产的时候注意串口电路设计,必要时加隔离。
坑3:LED灯忘了关
现象:功耗总是多几mA。
原因:有个LED指示灯在那亮着呢!一个LED亮着就是几mA。
解决:低功耗模式下把所有LED都关掉。需要指示的话,用LED闪烁的方式,亮1ms灭5秒,平均功耗可以忽略不计。
坑4:外部上拉/下拉跟内部反着
现象:某个IO口有持续的漏电流。
原因:外部电路有个10K上拉,你内部又开了下拉,电流就从上拉流到下拉了,3.3V/10K=330μA,可不小。
解决:进入低功耗前,把IO配置成跟外部电平一致的状态。有外部上拉的,内部就别开下拉了,或者干脆配置成模拟输入。
坑5:RTC时钟源没选对
现象:Stop模式下功耗总是比datasheet高。
原因:RTC用的是内部LSI RC振荡器,LSI的功耗比外部LSE(32.768kHz晶振)高。而且LSI精度差,时间不准。
解决:低功耗项目建议用外部32.768kHz晶振(LSE),既准又省电。一颗晶振也就几毛钱,性价比很高。
坑6:Flash等待周期没调
现象:运行时功耗偏高。
原因:主频降下来了,但Flash等待周期(WS)还是按高主频设的,浪费了。
解决:降低主频的时候,相应地减少Flash等待周期。比如STM32L4,主频16MHz以下可以设0个等待周期,既快又省电。
七、常见问题FAQ
Q1:STM32哪个系列最低功耗?做电池供电选哪个型号?
答:ST的低功耗系列是L系列,从低到高大概是:L0(最便宜,功耗也不错)、L4(性能和功耗平衡,我们用得最多)、L5(带安全功能)、U5(最新的,功耗更低)。一般项目用L4就够了,性价比最高。如果成本特别敏感,可以看看L0。如果追求极致低功耗,可以看看U5系列。具体型号还要看你需要多少Flash、多少RAM、多少外设。
Q2:电池供电的产品,怎么估算电池能用多久?
答:简单估算公式:电池容量(mAh) ÷ 平均工作电流(mA) = 使用时间(小时)。关键是平均电流怎么算。比如:休眠电流2μA,每5秒醒一次,每次醒5ms,运行时电流5mA。平均电流 = 休眠电流 × 休眠占比 + 运行电流 × 运行占比 = 2μA × (5000-5)/5000 + 5000μA × 5/5000 ≈ 2μA + 5μA = 7μA。然后用电池容量除以平均电流就行。注意要留余量,电池有自放电,低温下容量也会下降,建议按理论值的60%~70%来估算。
Q3:低功耗模式下,RTC还走吗?数据会不会丢?
答:Stop模式下,RTC是可以继续运行的(只要你开了RTC时钟),SRAM里的数据也会保持。所以唤醒之后,程序可以接着跑,变量都还在。Standby模式就不一样了,SRAM会掉电,只有备份寄存器和RTC保持,唤醒相当于重新上电,程序从main函数开始跑。所以如果你需要保存数据,要么用RTC的备份寄存器(数量很少,一般几十个字节),要么存到Flash里。
Q4:进入低功耗模式后,串口还能收到数据吗?
答:看模式。Sleep模式下,外设都还在运行,串口能收到数据并触发中断唤醒。Stop模式下,普通的USART是不行的(因为时钟停了),但LPUART(低功耗串口)可以,它用LSI或LSE时钟,Stop模式下还能工作。Standby模式下所有串口都不行,只能靠WKUP引脚或者RTC唤醒。所以如果需要串口随时唤醒,就用LPUART,或者干脆别进太深的低功耗。
Q5:锂亚电池和普通锂电池有什么区别?低功耗项目该怎么选?
答:锂亚电池(就是水表燃气表里常用的那种)的特点是:容量大(同体积是普通锂电池的2~3倍)、自放电极低(每年不到1%)、电压高(3.6V)、但不能充电、输出电流小(最大几十mA)。普通锂电池(比如18650)可以充电、输出电流大,但自放电高(每月百分之几)、容量相对小。所以长期不用充电的低功耗设备(比如水表、燃气表、环境监测传感器),选锂亚电池;需要经常工作、电流大、可以充电的,选普通锂电池+充电管理。
总结
低功耗设计是个细活,差1μA都可能差出好几年的电池寿命。硬件是基础,软件是锦上添花。硬件没设计好,软件再怎么优化也白搭。
我们团队做了这么多电池供电项目,最深的体会是:做低功耗,一定要测,而且要早测。别等板子都做出来了才发现功耗超标,那时候改硬件成本就高了。原理图阶段就要算一遍大概的功耗,打样回来第一时间就测功耗,有问题尽早改。
希望这篇文章能帮你少走点弯路。如果你的项目在低功耗上遇到了瓶颈,也可以找我们聊聊——从毫安级到微安级的优化经验都有,说不定一句话就能点醒你。
还想接着看
- 智慧供暖物联网终端低功耗全栈优化实录——用从12mA到28μA的真实降耗案例对照本文的功耗设计方法。
- UART与蓝牙功耗分析报告——定位外设耗电大头,细化通信环节的功耗优化。
- STM32 HAL库传感器驱动开发实战——在低功耗主控上接入传感器时的驱动与调度配合要点。