3.29. 低功耗與睡眠模式¶
電池供電的相機與間歇運作的感測器,並不需要 CPU 一直以全速運行。machine 模組提供四種逐步加深的省電狀態 -- active、idle()、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 -- 必須在睡眠呼叫之前設定好。功耗相對於 active 模式大幅下降;確切數值取決於板子以及仍在設定中的周邊裝置。
3.29.4. deepsleep()¶
machine.deepsleep() 是最深的狀態。CPU 停止、周邊裝置斷電,RAM 內容可能會遺失。唯一仍在耗電的,只有喚醒電路與一小部分常開邏輯。
當喚醒來源觸發時,晶片會從主指令碼的開頭開機 -- deepsleep 不會回傳。指令碼可使用 machine.reset_cause() 來區分這是 deepsleep 喚醒,還是全新上電或硬重置:
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 的備援暫存器)。Deepsleep 帶來最大的省電效果,卻也要求最多的程式重構 -- 應用程式必須表現為一連串以睡眠分隔的短促「測量爆發」,而非一個狀態保存在 RAM 中的長時間運行迴圈。
3.29.5. 選擇狀態¶
正確的狀態取決於相機在等待什麼:
緊密輪詢迴圈,等待數毫秒。 使用
idle()。每個週期的節省雖小,但總和可觀,而且喚醒過程無感。事件之間閒置數秒或數分鐘。 使用
lightsleep()。狀態被保留、喚醒迅速,功耗只是 active 模式的一小部分。在短暫的工作爆發之間閒置數分鐘或更久。 使用
deepsleep()。事件之間晶片實際上等同關閉,指令碼結構則轉變為「喚醒、測量、睡眠」的迴圈。
無論處於哪種狀態,喚醒來源與狀態本身同等重要 -- 只靠計時器喚醒的 deepsleep 是一個工作週期化的測量迴圈;靠接腳 IRQ 喚醒的 lightsleep 則是一個事件驅動的感測器。machine 模組的睡眠函式、RTC 鬧鐘與 irq() 共同提供了這些構件。