STM32低功耗设计实战指南:从nA级到产品化的踩坑记录

做了4年电池供电项目,把TMR流量计从3mA降到2μA的完整优化过程,硬件软件一起讲,附实测数据

2026-09-14
STM32低功耗电池供电Stop模式Standby模式功耗优化微安级

先说结论: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(相当于重新启动)
注意:上面的功耗是芯片本身的典型值,实际产品里整个系统的功耗肯定比这个高——外部电路有漏电流、LDO有静态电流、传感器有待机电流。所以别光看 datasheet 上的数字,那是理想条件下测的,实际做出来能做到10μA以内就已经很不错了。

三种模式怎么选?我们的经验:

项目经验:我们的TMR流量计项目,最开始用的是F1系列,Stop模式下功耗约20μA,加上外部电路总共30多μA。后来换成了L431,Stop模式(带RTC)只有约1.2μA,加上外部电路总共约2μA。同样是锂电池供电,电池寿命从3年提升到了8年以上。所以如果你的项目对功耗要求高,选芯片的时候就要选低功耗系列(L0/L4/L5/U5),别选F1/F4这种高性能系列,后期再怎么优化也优化不了多少。

二、硬件低功耗设计要点——比软件更重要

很多人做低功耗,一上来就调软件、配寄存器,折腾半天发现功耗降不下来。最后一查,是硬件的问题——某个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的,性价比不错
真实踩坑:我们第一个低功耗项目,用了AMS1117-3.3,因为便宜嘛,0.2元一片。结果测功耗的时候,怎么调休眠电流都有5mA以上,查了三天,最后发现LDO本身的静态电流就有5mA!感情MCU的功耗都还没LDO大。换成HT7333,整个板子的休眠电流一下就降到了30μA。你看,选对一个元件,功耗直接降两个数量级。

2. 不用的外设要断电

如果有些外设不是一直要用(比如传感器、通信模块),就不要让它一直待机,不用的时候把电源关掉。怎么关?用MOS管做电源开关,MCU的IO控制MOS管的栅极。

举个例子:NB-IoT模块,待机电流可能有几mA甚至几十mA,如果一直开着,电池用不了多久。我们的做法是:需要上传数据的时候才给模块上电,传完就关掉。模块开机+连网+上传+关机,整个过程不到10秒,虽然电流大(峰值可能200mA),但时间短,平均下来功耗还是很低的。

3. IO口配置——这个坑踩的人最多

进入低功耗模式前,所有不用的IO口一定要配置好。如果IO口悬空或者状态不对,可能会有额外的漏电流。

我们的配置原则:

经典坑:有次我们做的板子,休眠功耗总是比预期高20μA,查了一周没找着原因。最后把每个IO一个个断开测,发现是一个按键的IO——按键另一端接GND,我们配置了内部上拉,按键没按下的时候电流从上拉电阻流到GND,20μA就这么没了。改成外部上拉+休眠前关内部上拉,问题就解决了。别小看这20μA,电池供电的产品,20μA可能就是差一两年寿命的事。

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就够了。

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年以上没问题。

经验总结:做低功耗优化,要一步一步来,每改一个地方就测一次功耗,这样你才知道每个改动到底省了多少电。千万别一次性改一堆,最后功耗降了,但你不知道是哪一步起的作用,下次项目还是不会。我们团队做低功耗项目,都会建个功耗优化记录表,每一步改了什么、效果如何,都记下来,攒多了就是宝贵经验。

五、功耗怎么测?工具和方法

做低功耗,没有合适的测量工具可不行。普通的万用表只能测毫安级的电流,微安级的就不准了。

我们常用的测功耗的工具:

测量的时候要注意:

六、常见的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都可能差出好几年的电池寿命。硬件是基础,软件是锦上添花。硬件没设计好,软件再怎么优化也白搭。

我们团队做了这么多电池供电项目,最深的体会是:做低功耗,一定要测,而且要早测。别等板子都做出来了才发现功耗超标,那时候改硬件成本就高了。原理图阶段就要算一遍大概的功耗,打样回来第一时间就测功耗,有问题尽早改。

希望这篇文章能帮你少走点弯路。如果你的项目在低功耗上遇到了瓶颈,也可以找我们聊聊——从毫安级到微安级的优化经验都有,说不定一句话就能点醒你。

还想接着看

低功耗做不好,电池用不久?

沧州艾诺威 — 从3mA到2μA,多类电池供电项目经验
硬件设计 · 软件优化 · 功耗测试,一条龙帮你搞定

立即微信咨询

电话:13930711029 | 邮箱:tech@czinv.com | 24小时内响应