Learning Objectives
- 用電池容量與平均電流估算使用時間,說明為什麼感測節點要睡覺
- 比較 ESP32 運作、輕度睡眠、深度睡眠的耗電數量級
- 說明 lightsleep 醒來接著執行、deepsleep 醒來從頭執行的差別,並用 reset_cause 判斷是不是睡醒
- 寫出「醒來、量測、上傳、睡覺」的程式,把需要記住的資料存起來
插 USB 和裝電池是兩回事
接在電腦 USB 上時,ESP32 想用多少電都可以。放到花園裡量土壤濕度、靠電池供電時,問題就變成:電池能撐多久?
電池容量常用毫安培小時(mAh)表示。粗略的估算是:
使用時間(小時)≈ 電池容量(mAh)÷ 平均電流(mA)
例如一顆 2000 mAh 的電池:
| 平均電流 | 大約可以用 |
|---|---|
| 100 mA(Wi-Fi 一直開著) | 2000 ÷ 100 = 20 小時,不到一天 |
| 1 mA | 2000 小時,約 83 天 |
| 0.1 mA | 20000 小時,兩年多 |
這只是數量級的估算:實際上電池會自己放電、低溫時容量變小、穩壓器也會耗電。但它說明了重點: 平均電流降低 100 倍,使用時間就變成 100 倍。而土壤濕度不需要每秒量一次,十分鐘量一次就夠了,其他時間可以讓 ESP32 睡覺。
ESP32 的工作模式
ESP32 可以關掉不用的部分來省電。下表是 Espressif 的 ESP32 資料手冊列的晶片耗電,只看數量級(實際數字依型號、時脈、Wi-Fi 狀態而不同):
| 模式 | 什麼還醒著 | 晶片耗電(數量級) |
|---|---|---|
| 運作,Wi-Fi 發射中 | 全部 | 約 200 mA |
| 運作,Wi-Fi 接收或等待 | 全部 | 約 100 mA |
| 數據機睡眠(modem-sleep) | CPU 運作,無線電關閉 | 數十 mA |
| 輕度睡眠(light-sleep) | CPU 暫停,記憶體保留 | 約 1 mA |
| 深度睡眠(deep-sleep) | 只剩 RTC 計時器與一小塊 RTC 記憶體 | 約 10 μA(0.01 mA) |
從 Wi-Fi 發射到深度睡眠,差了大約兩萬倍。
注意:上表是晶片本身。一般的 ESP32 開發板還有 USB 轉序列晶片、穩壓器、電源指示燈,深度睡眠時整塊板子常常還要消耗好幾 mA, 比晶片規格大上百倍。真正要用電池的作品,會選低功耗設計的板子或直接用模組,並拆掉或關掉用不到的 LED。
MicroPython 有兩個睡眠函式,差別非常大:
machine.lightsleep(毫秒) |
machine.deepsleep(毫秒) |
|
|---|---|---|
| 記憶體 | 保留,變數都還在 | 不保留 |
| 醒來後 | 從下一行接著執行 | 像重新開機,從頭執行 boot.py、main.py |
| Wi-Fi | 要重新連線 | 要重新連線 |
| 省電程度 | 中等 | 最多 |
兩種睡眠都不會保持 Wi-Fi 連線(Espressif 的文件明確寫了這一點),醒來後要量測、上傳,就要重新連 Wi-Fi。
逐步看:輕度睡眠醒來接著執行
先看比較溫和的輕度睡眠。注意左上角的時間:每次 lightsleep(1000) 時間就跳 1 秒,而 count 一直累加,沒有不見。
逐步看:工作一次,然後深度睡眠
這是電池供電感測節點最常見的寫法。看最後一步:執行 machine.deepsleep(10000) 之後,模擬停止,
電路畫面顯示「進入深度睡眠」,最後一行永遠不會執行。
醒來的方式、醒來之後
誰來叫醒 ESP32
| 喚醒來源 | 怎麼寫 | 適合 |
|---|---|---|
| 計時器 | machine.deepsleep(60000):60 秒後醒來 |
定時量測 |
| 一支腳位(ext0) | esp32.wake_on_ext0(Pin(4, Pin.IN), esp32.WAKEUP_ALL_LOW) |
按鈕、門窗磁簧開關 |
| 多支腳位(ext1) | esp32.wake_on_ext1((腳位, 腳位), esp32.WAKEUP_ANY_HIGH) |
好幾個按鈕任一個 |
| 觸控 | esp32.wake_on_touch(True) |
觸控按鍵 |
deepsleep() 不給時間,就會一直睡,直到腳位或觸控把它叫醒。
深度睡眠時只有連到 RTC 的腳位能叫醒 ESP32,MicroPython 文件列出的是 GPIO 0、2、4、12~15、25~27、32~39;
接喚醒按鈕前先確認腳位。
import esp32
from machine import Pin
import machine
button = Pin(4, Pin.IN, Pin.PULL_UP)
esp32.wake_on_ext0(button, esp32.WAKEUP_ALL_LOW) # 按下(低電位)就醒來
machine.deepsleep() # 不給時間:等按鈕
醒來後什麼都忘了
深度睡眠醒來像重新開機:所有變數、Wi-Fi 連線、MQTT 連線都沒了。要記住的東西有兩個地方可以放:
- RTC 記憶體:深度睡眠時仍然通電的一小塊記憶體,MicroPython 在 ESP32 上用
machine.RTC().memory()讀寫,預設最多 2048 個位元組。斷電就消失。 - 檔案:存在快閃記憶體裡,斷電也不會消失(第 16 課會詳細介紹檔案系統)。但快閃記憶體能抹寫的次數有限,不適合幾秒就寫一次。
模擬器沒有模擬 RTC 記憶體,下一個範例用檔案記錄「醒來第幾次」。電路規格裡先放了一個 count.txt,內容是 2,代表之前已經醒來過兩次。
逐步看:用檔案記住醒來的次數
每次醒來,程式從頭執行:先讀檔案取回上一次的次數,加一、存回去,再睡覺。執行完看輸出區的「檔案」分頁,count.txt 變成 3。
小測驗:兩種睡眠
下面的程式放在 main.py,ESP32 執行到 machine.deepsleep(5000)。5 秒後會發生什麼事?
import machine
print("A")
machine.deepsleep(5000)
print("B")
把上一題的 deepsleep 換成 lightsleep,5 秒後會發生什麼事?
想在 ESP32 醒來時知道「這次是不是從深度睡眠醒來」,要怎麼寫?
小測驗:估算與設計
下面的程式算出平均電流(mA),會印出什麼?
awake_ms, awake_ma = 2000, 100
sleep_ms, sleep_ma = 598000, 0.01
avg = (awake_ms * awake_ma + sleep_ms * sleep_ma) / (awake_ms + sleep_ms)
print(round(avg, 2))
一個門窗感測器平常沒事,只有門被打開時才需要發一則 MQTT 訊息。最省電的寫法是?
重點整理
- 使用時間 ≈ 電池容量 ÷ 平均電流;平均電流主要由「醒著的時間」決定。
- ESP32 晶片耗電:Wi-Fi 運作約 100~200 mA 等級,輕度睡眠約 1 mA,深度睡眠約 10 μA(開發板整塊會更高)。
lightsleep(ms)保留記憶體,醒來接著執行;deepsleep(ms)最省電,醒來從頭執行。兩者醒來都要重連 Wi-Fi。machine.reset_cause() == machine.DEEPSLEEP_RESET判斷是不是睡醒;要記住的資料放 RTC 記憶體或檔案。- 喚醒來源:計時器、外部腳位(ext0/ext1,限 RTC 腳位)、觸控。
- 典型的電池感測節點:醒來 → 量測 → 連 Wi-Fi、上傳 → 關掉周邊 → 深度睡眠。
下一課看 ESP32 開機時執行的 boot.py、main.py,以及怎麼把 Wi-Fi 密碼這類設定放進設定檔。