1. 低功耗设计概述:为什么物联网设备需要低功耗?

说实话,我做了十几年嵌入式开发,早期压根没把功耗当回事。那时候接个电源,跑就完了。但到了物联网时代,情况完全变了。

你想想看,一个温湿度传感器,装在仓库角落里,拉根电线?不现实。用电池?那得撑一年以上。这就是物联网设备的真实处境——没人在乎你的CPU跑多快,只在乎你的电池能撑多久

1.1 物联网设备的功耗困境

我见过太多产品,功能做得花里胡哨,结果用户用三个月就得换电池。用户直接骂娘。为什么会这样?

说白了,物联网设备有几个天然痛点:

  • 部署环境恶劣:野外、墙壁、管道里,换电池成本比设备本身还高
  • 通信开销大:Wi-Fi、NB-IoT、LoRa,一发数据就是几十毫安
  • 待机时间要求长:少则半年,多则三五年
  • 成本敏感:加个大电池?成本上去了,客户不买账

我记得有个项目,客户要求用两节AA电池撑两年。当时团队都觉得不可能。但最后我们做到了,靠的就是把每个微安都抠出来。嗯,这就是低功耗设计的价值。

1.2 电池续航的计算模型

做低功耗设计,你得先会算账。电池续航不是拍脑袋定的,有个基本公式:

续航时间(小时) = 电池容量(mAh) / 平均工作电流(mA)

但实际没那么简单。我习惯把设备的工作状态拆成几个阶段:

工作状态 典型电流 持续时间 占比
深度休眠 2~5 µA 大部分时间 99.5%
轻度休眠 50~200 µA 几秒 0.3%
数据采集 5~20 mA 几十毫秒 0.1%
无线通信 50~200 mA 几百毫秒 0.1%

你看,休眠占了99.5%的时间。所以低功耗设计的核心,说白了就是把休眠电流压到最低,把工作时间缩到最短

举个例子。一个设备用1000mAh电池,每天发一次数据:

  • 休眠电流 5µA,一天耗电 0.12mAh
  • 通信电流 100mA,持续 500ms,一天耗电 0.014mAh
  • 一天总耗电约 0.134mAh
  • 理论续航:1000 / 0.134 ≈ 7462天 ≈ 20年

但实际呢?电池自放电、温度影响、电压跌落……能到5年就不错了。我曾经被这个坑过——理论算出来8年,实际2年就趴窝了。后来才明白,电池的放电曲线不是线性的,电压降到一定程度,设备就罢工了。

避坑提醒:我曾经在计算续航时只算了平均电流,忽略了电池的脉冲放电能力。有些电池标称容量很大,但大电流放电时电压掉得厉害,设备直接复位。所以一定要留余量,至少留30%~50%。

1.3 RT-Thread低功耗架构全景

RT-Thread的低功耗设计,我总结下来就三个层次:

第一层:内核级低功耗

RT-Thread的Idle线程里,有个钩子函数。当系统没有任务可跑时,就会进入这个钩子。你可以在里面调用MCU的WFI或WFE指令,让CPU停下来。这是最基础的省电手段。

// 在Idle钩子里让CPU休眠
void idle_hook(void)
{
    /* 进入休眠模式 */
    __WFI();
}

但光这样不够。你想想看,如果系统每1ms就有一个定时器中断,那CPU刚睡下就被叫醒了。所以还得配合tickless模式。

第二层:tickless模式

RT-Thread支持tickless机制。说白了,就是动态调整系统心跳。没有任务要调度时,把系统tick停掉,让MCU深度睡眠。等有事件来了再唤醒。

我做过一个项目,默认tick是1ms,功耗在200µA左右。开了tickless后,直接降到15µA。效果立竿见影。

小技巧:开启tickless后,要注意定时器的精度会受影响。如果你的应用需要毫秒级定时,建议保留一个硬件定时器作为基准,别全依赖系统tick。

第三层:PM组件

RT-Thread有个PM(Power Management)组件,这是真正的大杀器。它把功耗管理抽象成几个等级:

  • PM_SLEEP_MODE_NONE:全速运行
  • PM_SLEEP_MODE_IDLE:CPU空闲
  • PM_SLEEP_MODE_LIGHT:轻度睡眠
  • PM_SLEEP_MODE_DEEP:深度睡眠
  • PM_SLEEP_MODE_STANDBY:待机(RTC唤醒)
  • PM_SLEEP_MODE_SHUTDOWN:关机

PM组件会自动根据系统负载切换睡眠等级。比如没有数据要发时,自动进入深度睡眠。有数据来了,再快速唤醒。

我习惯的做法是:

  1. 先确定应用场景,哪些外设在什么阶段必须工作
  2. 给每个外设注册PM通知回调
  3. 在回调里控制外设的电源和时钟
  4. 用PM组件统一管理睡眠深度

举个例子,一个NB-IoT水表:

/* 注册PM通知 */
rt_pm_notify_set(PM_SLEEP_MODE_DEEP, water_meter_pm_notify);

static void water_meter_pm_notify(enum pm_sleep_mode mode)
{
    switch(mode) {
    case PM_SLEEP_MODE_DEEP:
        /* 关掉传感器电源 */
        rt_pin_write(SENSOR_POWER_PIN, PIN_LOW);
        /* 关掉NB-IoT模块 */
        nbiot_power_off();
        break;
    case PM_SLEEP_MODE_NONE:
        /* 打开传感器电源 */
        rt_pin_write(SENSOR_POWER_PIN, PIN_HIGH);
        /* 打开NB-IoT模块 */
        nbiot_power_on();
        break;
    }
}

这套架构的好处是,应用层不用关心底层怎么睡。你只管调用PM接口,系统自动帮你做最优选择。

核心要点:RT-Thread的低功耗设计不是让你手动去控制每个寄存器,而是通过PM组件、tickless、Idle钩子这三层架构,实现自动化的功耗管理。你只需要告诉系统「什么时候该睡,什么时候该醒」,剩下的交给框架。

好了,这一章我们理清了低功耗设计的必要性、续航计算模型,以及RT-Thread的整体架构。下一章,我会带你深入MCU的睡眠模式,看看不同睡眠等级到底差了多少功耗。嗯,到时候我会拿实际测量的数据给你看,保证让你大吃一惊。