1、低功耗概览:为什么物联网设备需要低功耗?FreeRTOS低功耗方案全景图

1.1 物联网设备的“电池焦虑”

做嵌入式这么多年,我见过太多产品因为功耗问题翻车了。

你想想看,一个智能门锁,用户装好电池,结果三个月就没电了。用户会怎么想?肯定骂娘。物联网设备不像手机,用户没有每天充电的习惯。它们被部署在墙角、天花板、野外,甚至埋在地下。换电池?那成本比设备本身还高。

所以,低功耗不是锦上添花,是生存刚需。

我遇到过最夸张的一个项目:客户要求用两节AA电池,让一个温湿度传感器跑两年。当时团队里有人说“不可能”,但最后我们做到了。靠的是什么?就是FreeRTOS的低功耗调度。

核心矛盾:设备要“一直在线”接收指令,但又不能“一直耗电”。说白了,就是既要马儿跑,又要马儿不吃草。

1.2 功耗都去哪了?

要解决问题,先得知道问题在哪。一个典型的物联网节点,功耗大头通常有三个:

  • 射频发射(RF TX):发一次数据,几十毫安。这是最吃电的环节。
  • 射频接收(RF RX):等待接收,几毫安到十几毫安。很多设备死就死在这个“空等”上。
  • MCU活跃模式:CPU跑着,外设开着,几毫安到几十毫安。

剩下的传感器采样、RTC计时,其实都是小头。

我记得有个项目,客户说“我休眠电流已经做到2uA了,为什么电池还是撑不住?”我一看日志,发现他每秒钟醒来一次,每次醒来跑50ms。算下来平均电流反而比一直休眠还高。这就是典型的“频繁唤醒陷阱”。

我的经验:低功耗设计,80%的精力要花在“减少活跃时间”和“降低活跃电流”上。休眠电流做到uA级只是基本功,不是决胜点。

1.3 FreeRTOS低功耗方案全景图

FreeRTOS本身是一个实时内核,它不会自动帮你省电。但它提供了一套机制,让你能优雅地管理功耗。说白了,它给你搭好了舞台,戏还得你自己唱。

整个方案,我习惯分成三层来看:

层级 核心机制 我常用的场景
第一层:Tickless模式 空闲时停止系统滴答定时器,让MCU进入深度睡眠 大部分传感器节点,数据上报间隔>1秒
第二层:自定义空闲钩子 在空闲任务中执行低功耗模式切换 需要精细控制唤醒源的场景
第三层:外设与时钟管理 动态关闭未使用的外设时钟,降低运行功耗 多外设、多传感器的复杂产品

嗯,这里要注意:Tickless模式是FreeRTOS官方推荐的入门方案。但如果你直接拿来用,可能会发现一个问题——它只考虑了CPU的睡眠,没管你的外设。我曾经在一个LoRa节点上踩过这个坑:CPU睡了,但SPI和UART的时钟还开着,白白浪费了十几微安。

1.4 Tickless模式到底干了什么?

简单说,就是“没事别乱醒”。

传统RTOS,系统滴答定时器每1ms中断一次,哪怕所有任务都在睡觉,CPU也得爬起来处理这个中断。Tickless模式把这个行为改了:当系统空闲时,它计算下一次任务唤醒的时间,然后让MCU睡到那个时间点再醒。

举个例子:

// 传统模式:每1ms中断一次
// 即使空闲,CPU也在频繁进出中断
// 功耗:约500uA(以STM32L0为例)

// Tickless模式:空闲时直接睡10秒
// 10秒后才醒来处理任务
// 功耗:约5uA(睡眠)+ 短暂活跃

你想想看,这差距是不是很直观?

避坑指南:我曾经在一个项目里直接开启了Tickless模式,结果发现WiFi模块连不上网了。查了半天,原来是睡眠时间太长,导致WiFi的keep-alive包没及时处理。所以,Tickless模式不是万能的。如果你的设备需要频繁响应外部事件(比如按键、串口数据),睡眠时间就不能设太长。

1.5 空闲钩子:给你更大的自由度

Tickless模式是“自动挡”,适合大多数场景。但如果你需要手动控制,那就用空闲钩子。

空闲钩子,说白了就是FreeRTOS在空闲任务里给你留的一个回调函数。你可以在这里做任何事:关外设、降频、进睡眠、甚至关掉部分内存。

我个人的习惯是:

  • 如果项目简单,用Tickless模式,省心。
  • 如果项目复杂,比如有多个唤醒源、需要动态调整睡眠深度,那就用空闲钩子自己写。

举个例子,我曾经在一个多传感器采集器上,用空闲钩子实现了“分级睡眠”:

void vApplicationIdleHook(void)
{
    // 检查是否有外设还在工作
    if (xSemaphoreTake(xPeriphBusy, 0) == pdTRUE)
    {
        // 外设忙,只进轻度睡眠
        MCU_EnterSleep();
    }
    else
    {
        // 所有外设空闲,进深度睡眠
        MCU_EnterStop();
    }
}

这样,既保证了数据采集的实时性,又最大化了省电效果。

1.6 外设与时钟管理:被忽视的“偷电贼”

很多人只盯着CPU的睡眠电流,却忘了外设。我见过一个产品,CPU休眠时只有2uA,但一个没关的I2C上拉电阻就吃掉了10uA。你说冤不冤?

所以,低功耗设计一定要有“系统思维”。FreeRTOS本身不帮你管外设,但你可以利用任务调度,在进入空闲时统一关闭外设时钟。

我的做法是:

  1. 每个外设驱动里,增加一个“低功耗退出”函数。
  2. 在空闲钩子或Tickless的预处理中,遍历所有已注册的外设,调用它们的低功耗函数。
  3. 醒来时,再按需恢复。

说白了,就是给每个外设装一个“开关”。

一个小技巧:很多MCU的GPIO在输出模式下,即使CPU休眠,也会持续耗电。我习惯在进休眠前,把所有不用的GPIO都设为模拟输入或高阻态。这个操作,往往能再省下几微安。

1.7 本章小结

低功耗不是某一个技巧,而是一整套策略。FreeRTOS给了你三个武器:Tickless模式、空闲钩子、外设管理。但怎么用,取决于你对产品的理解。

下一章,我会带你手把手移植Tickless模式,并分享我在实际项目中遇到的几个“坑”。到时候咱们再细聊。

记住一句话:省电不是目的,在省电的同时保证功能完整,才是真本事。