3.29. 低功耗与睡眠模式

电池供电的摄像头和间歇性工作的传感器并不需要 CPU 始终全速运行。machine 模块提供了四种逐级加深的省电状态——activeidle()lightsleep()deepsleep()。每深入一级都会关闭芯片更多的部分、节省更多功耗,但代价是更长的唤醒时间。选择合适的状态是在摄像头省下多少电与发生事件时它能多快做出反应之间的权衡。

3.29.1. Active(活动)

默认状态。CPU 正在运行 Python,每个外设都有时钟驱动,电流消耗处于最高水平——摄像头逻辑电源轨上达数十毫安,再加上任何外接配件经由它消耗的电流。

3.29.2. idle()

machine.idle() 会关断 CPU 时钟,直到任意中断触发(外设、定时器或引脚 IRQ)。RAM 保持活动,外设保持开启,时钟持续运行——仅 CPU 本身被暂停,当有工作要做时它会在微秒级内被唤醒。

在任何等待外部事件发生的紧凑轮询循环中使用它:

import machine

while not button_pressed():
    machine.idle()

CPU 不再为 while 检查本身消耗时钟周期,并在下一个事件到来时自然唤醒——这点小小的节省在运行数百万次的循环中会累积成可观的效果。

3.29.3. lightsleep()

machine.lightsleep() 是更深一级的状态。CPU 完全停止,芯片的大部分内部时钟被关闭,但 RAM 和外设状态会被保留。当唤醒源触发时,脚本会从调用 lightsleep 的确切位置恢复——变量、打开的句柄和待处理数据全部完好无损——在数毫秒之后。

import machine
from machine import Pin

wake_pin = Pin("P0", Pin.IN, Pin.PULL_UP)
wake_pin.irq(lambda _: None, trigger=Pin.IRQ_FALLING, wake=machine.SLEEP)

while True:
    do_work()
    machine.lightsleep()   # wakes on a falling edge on P0

唤醒源(这里是引脚 IRQ)必须在睡眠调用之前配置好。相对于活动模式,功耗显著下降;具体数值取决于开发板以及仍然处于配置状态的外设。

3.29.4. deepsleep()

machine.deepsleep() 是最深的状态。CPU 停止,外设断电,RAM 内容可能丢失。唯一仍在耗电的只有唤醒电路和一小部分常开逻辑。

当唤醒源触发时,芯片会从主脚本的起始处启动——deepsleep 不会返回。脚本使用 machine.reset_cause() 来区分深度睡眠唤醒与全新上电或硬复位:

import machine

if machine.reset_cause() == machine.DEEPSLEEP_RESET:
    # Woke from deepsleep -- restore state from non-volatile storage,
    # take a measurement, etc.
    pass
else:
    # Fresh boot
    pass

do_work()
machine.deepsleep(60_000)    # arm RTC wake for 60 s, sleep, then restart

传给 deepsleep() 的毫秒参数会在内部装填片上 RTC 闹钟——RTC 正是在睡眠期间承载唤醒计时的部件,因为大多数其他定时器已经断电。不带参数调用 deepsleep() 则将唤醒交给你另行配置的任意源(引脚 IRQ、外部装填的 RTC 闹钟)。

由于脚本会重新启动,下一次迭代所需的任何内容要么必须在 main.py 顶部重新构建,要么持久化到闪存(或在具备该功能的部件上持久化到 RTC 的备份寄存器)。深度睡眠带来最大的功耗节省,但也带来最多的程序重构——应用必须表现为一系列由睡眠隔开的短暂"测量突发",而非一个在 RAM 中保存状态的长时间运行循环。

3.29.5. 选择状态

正确的状态取决于摄像头在等待什么:

  • 紧凑轮询循环,等待数毫秒。 使用 idle()。每个周期节省很小,但总量可观,而且唤醒是无感的。

  • 事件之间空闲数秒或数分钟。 使用 lightsleep()。状态被保留,唤醒迅速,功耗仅为活动模式的一小部分。

  • 在短暂工作突发之间空闲数分钟或更久。 使用 deepsleep()。芯片在事件之间实际处于关闭状态,脚本结构转变为唤醒、测量、睡眠的循环。

无论处于哪种状态,唤醒源与状态本身同样重要——仅由定时器唤醒的深度睡眠是一个按占空比工作的测量循环;由引脚 IRQ 唤醒的轻度睡眠则是一个事件驱动的传感器。machine 模块的睡眠函数、RTC 闹钟以及 irq() 共同提供了这些构建模块。