嵌入式C语言智能手表功耗优化:让设备7天续航的编程细节拆解
7天续航不是挑颗低功耗MCU就完事。200~300mAh电池摊到7天,平均电流得压到1.5mA以内,屏、传感器、BLE、MCU各占一块预算。 代码层要做的就一句:系统99%时间睡着,唤醒只干必要活,干完立刻回去睡。
一、睡眠架构:事件驱动替代轮询
主循环里while(1)轮询按键、I2C查传感器状态,MCU根本进不了深睡。正确是全部中断化:
RTC闹钟:定时采样、亮屏刷新
加速度INT:抬腕、步数、跌倒
触摸/按键:用户交互
BLE事件:连接、GATT写
外设FIFO阈值:DMA搬完再唤醒CPU
FreeRTOS开Tickless,空闲任务进WFI/Stop;裸机直接主循环末尾__WFI()。
void enter_low_power(void){
adc_stop();
spi_i2c_clk_off(); // 关非必要外设时钟
gpio_unused_analog(); // 悬空脚配模拟输入,防漏电
rtc_set_alarm(next_wake);
__disable_irq();
if(!pending_event){
__WFI(); // 睡到中断来
}
__enable_irq();
sysclk_reinit(); // Stop唤醒后重配时钟
}
顺序错了电流压不下来:先停业务→关外设时钟→IO定型→开唤醒源→再睡。
二、外设时钟门控
很多项目睡眠电流卡在几百μA,就是SPI/I2C/ADC时钟没关。寄存器层面按需使能:
RCC->APB1ENR &= ~RCC_APB1ENR_I2C1EN;
RCC->APB2ENR &= ~RCC_APB2ENR_SPI1EN;
// 用时再开
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
加速度、RTC、LPTIM、BLE射频保留时钟,其余全关。SWD脚休眠时也别浮空,调试口是隐性漏电大户。
三、传感器:低占空比+事件触发
PPG/心率是耗电大头,别25Hz常开。静止时降到1Hz,睡眠再降,运动才拉到25~100Hz。
typedef enum { HR_OFF, HR_1HZ, HR_25HZ } hr_rate_t;
hr_rate_t hr_rate_by_activity(act_t a){
if(a==ACT_RUN) return HR_25HZ;
if(a==ACT_IDLE) return HR_1HZ;
return HR_OFF;
}
void ppg_session(void){
ppg_power_on();
for(int i=0;i<25;i++){ // 开100ms采一段
dma_acquire(buf+i);
}
hr = calc_hr(buf);
ppg_power_off(); // 马上断电
}
加速度走中断唤醒,PPG/陀螺仪被它触发才上电。这样PPG平均功耗能砍60~80%。
步数、抬腕检测放Sensor Hub或加速度自带FIFO,主MCU不醒。
四、屏幕:局部刷新+息屏策略
OLED/LCD亮屏时功耗占比25~35%,是手表第一耗电源。
规则:
默认息屏,抬腕/按键才亮
亮屏时长超时(3~5s)自动熄
时间只刷时分区域,秒针别每秒全屏重绘
SPI屏发完一帧立刻CS拉高、背光PWM归零
环境光传感器调亮度,别常亮100%
void ui_refresh_watchface(void){
lcd_set_window(0,0,63,20); // 只刷时间区
lcd_write_pixels(time_buf, ...);
// 不碰其余区域
}
e-paper类更要局部刷,全屏刷新又耗电又闪。
五、BLE:拉长连接间隔+批量同步
BLE常连本身不算最耗电,频繁交互才是。待机时把连接间隔拉到500~1000ms,从机延迟开几拍:
// Nimble/GAP参数协商
conn_params.interval_min = 800; // 1s
conn_params.interval_max = 800;
conn_params.slave_latency = 4;
conn_params.supervision_timeout = 2000;
数据别每条都发:
心率每分钟聚一次均值
步数累计到整点再上报
通知消息事件触发
OTA/大数据临时切高速连接,完事退回
广播间隔非连接态设1s,别100ms狂发。
六、电源域分级
常电域只留RTC、LPO、加速度中断、BLE唤醒;主MCU电源、PPG驱动、背光、GPS、扬声器全走MOS开关,不用就断电。
gpio_off(PPG_EN); // 切断PPG LDO
gpio_off(BACKLIGHT);
电池低于20%进省电模式:心率降频、亮屏时长减半、BLE同步延到5分钟一次。
七、落坑清单
主循环轮询I2C→永远进不了Stop
睡眠不关SPI时钟→几十μA漏掉
未用GPIO浮空→引脚振荡漏电
PPG常开25Hz→一天掉一半电
每秒全屏刷新表盘→e-paper直接废
BLE连接间隔50ms常驻→射频空耗
每次采样都BLE上报→唤醒爆炸
唤醒后不重配时钟→外设时序错
背光PWM休眠没归零→屏隐性耗电
八、调试方法
示波器+电流探头抓三段电流:
深睡电流(目标μA级)
唤醒峰值时长
通信突发能耗
二分法逐个关外设,每次测静态电流,一个浮空脚能吃掉几百μA。
九、落地顺序
定功耗预算:平均<1.5mA
RTOS开Tickless / 裸机WFI
所有输入改中断,删掉轮询
睡眠前关时钟+GPIO定型
加速度中断唤醒,PPG按需上电
屏幕局部刷+自动熄屏
BLE连接间隔拉长+批量上报
电源域MOS开关,不用就断
电流曲线实测迭代
智能手表续航优化不是“哪个模块省一点”,是让CPU和外设大部分时间处于断电域。C语言层面核心就三件事:中断代替轮询、睡眠前清干净外设、唤醒后批量处理。算法再聪明,只要MCU睡不下去、屏常亮、BLE老唤醒,7天续航就是PPT。实测电流曲线比看datasheet准——没量过静态电流的低功耗方案都不算数。





