当前位置:首页 > 消费电子 > 消费电子
[导读]消费电子低功耗不是“主循环最后加一句WFI”就完事。电流大头分布在四层:主频动态功耗、外设时钟门控、GPIO漏电、睡眠模式选择。调睡眠前不收时钟,Sleep模式照样几mA;睡眠选太深又频繁唤醒,进出功耗反而比不睡还高。


消费电子低功耗不是“主循环最后加一句WFI”就完事。电流大头分布在四层:主频动态功耗、外设时钟门控、GPIO漏电、睡眠模式选择。调睡眠前不收时钟,Sleep模式照样几mA;睡眠选太深又频繁唤醒,进出功耗反而比不睡还高。

一、时钟:按需降频+关门控

动态功耗随主频走,能跑4MHz别开48MHz。任务分档:

按键响应/LED呼吸:MSI 2~4MHz

传感器采样:8~16MHz

蓝牙发包/解码:临时切PLL高频,发完切回

进低功耗前先降频关PLL,再关外设时钟门控:

void enter_lowpower_clock(void){

   RCC->APB1ENR = 0;          // 关UART/I2C/TIM时钟

   RCC->APB2ENR &= ~(ADC1EN|SPI1EN);

   ADC->CR &= ~ADC_CR_ADEN;   // 模拟模块也关

   SwitchToMSI(MSI_2MHZ);     // 切回内部低速

   PWR->CR |= PWR_CR_ULP;     // 超低功耗

}

休眠期间只留LSE(32.768kHz)给RTC/LPTIM,HSI/HSE/PLL全关。

二、GPIO:别留浮空

未用引脚浮空输入会贯导漏电流,几十个脚加起来几μA到几十μA:

模拟输入(关施密特触发器)最稳

或输出推挽固定低电平

禁止内部上下拉闲置

调试SWD引脚量产固件里关掉,否则仿真器挂着睡不下去

GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;

HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

三、睡眠模式:选对档位再睡

三类模式本质差异是“关了多少”:

Sleep:CPU停,外设时钟还在 → mA级,唤醒即时

Stop:时钟全停,SRAM/寄存器保留 → μA级,RTC/EXTI唤醒

Standby:内核域断电,RAM丢 → nA级,等同复位

消费电子周期采集/蓝牙广播首选Stop:RAM不丢、变量还在、唤醒后只需重配时钟。Standby只在“几天一醒”的遥控器/秤类用,状态存备份寄存器。

void mcu_sleep(void){

   enter_lowpower_clock();

   HAL_SuspendTick();              // 关SysTick

   HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON,PWR_STOPENTRY_WFI);

   SystemClock_Config();           // 唤醒后重配PLL

   HAL_ResumeTick();

}

⚠️ Stop唤醒后默认走HSI 8MHz,不重配时钟外设全偏。

四、任务调度:事件驱动替代轮询

低功耗天敌是while(!flag)忙等和1ms SysTick一直跑。正确模型:

任务等事件标志/队列/信号量,不占CPU

无任务可跑→进Idle任务→钩子里睡

定时靠LPTIM/RTC,不靠软件延时

FreeRTOS开Tickless:

#define configUSE_TICKLESS_IDLE 1

#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 5

Idle钩子逻辑:

void PreSleepProcessing(uint32_t t){

   if(t < 5) return;                 // 太短不睡,进出开销不划算

   LPTIM_SetTimeout(t);              // 低功耗定时器顶替SysTick

   HAL_SuspendTick();

}

void PostSleepProcessing(uint32_t t){

   uint32_t slept = LPTIM_Elapsed();

   vTaskStepTick(slept);             // 补系统节拍

   SystemClock_Config();

   HAL_ResumeTick();

}

要点:

最小睡眠阈值设进出耗时5~10倍,否则碎片唤醒更费电

补偿用LPTIM实际计数值,不用预设值

外设驱动超时别用xTaskGetTickCount,睡眠时SysTick冻了

临界区别太长,否则进不了Idle

五、低功耗“投票锁”

多个任务/外设忙时别硬睡:

uint32_t lpm_lock;

void lpm_lock_set(uint8_t bit){ taskENTER_CRITICAL(); lpm_lock|=bit; taskEXIT_CRITICAL(); }

void lpm_lock_clr(uint8_t bit){ taskENTER_CRITICAL(); lpm_lock&=~bit; taskEXIT_CRITICAL(); }

#define can_sleep() (lpm_lock==0)

BLE收发、Flash擦写、I2C传输期间置锁,完事清锁。

六、外设短时使能

ADC:采样前开时钟→单次转换+DMA→关时钟

UART:发前开时钟,发完关

传感器:I2C读完立刻进Downsampling模式

屏幕:局部刷新+TE同步,空闲关背光PWM

七、落坑清单

只WFI不关外设时钟→Sleep电流下不来

Stop唤醒不重配PLL→外设波特率全错

未用脚浮空→漏电流吃掉μA级收益

SysTick当驱动超时→Tickless下死循环

最小睡眠阈值=2tick→频繁进出更费电

Standby当默认模式→全局变量没了

临界区抱着外设操作睡→低功耗失效

调试器没拔→休眠电流虚高

软件定时器做低功耗闹钟→睡了不响

轮询按键替代中断→CPU永不闲

八、落地顺序

主频分档:运行高频、空闲降MSI

外设时钟用前开、用完关

未用GPIO统一模拟输入

Sleep先跑通,再切Stop

唤醒钩子重配时钟+恢复外设

任务改事件驱动,删忙等

开Tickless,LPTIM补tick

低功耗锁保护BLE/Flash/通信

低功耗本质是“让MCU绝大多数时间什么都不做”:时钟能关就关、主频能降就降、任务能等事件就别轮询、睡眠选Stop兼顾RAM保留和μA电流。SysTick不停就别想深睡,外设时钟不关就别怪电流下不来,GPIO不收口再深的Stop也压不到1μA。消费电子续航差距往往不在芯片选型,而在“睡得去、醒得对、不白醒”这三件事有没有串成一条线。



本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭