Learning Objectives
- 說明 NeoPixel(WS2812)為什麼一支腳位就能控制整條燈的每一顆顏色
- 用 neopixel.NeoPixel 設定單顆或全部燈的 RGB 顏色,並用 write() 送出
- 用迴圈與 sleep 寫出跑馬燈這類動畫
- 依亮度估算燈條的電流,判斷什麼時候需要外接電源
一支腳位控制一整條燈
第 03 課的 LED 一支腳位只能控制一顆燈,而且只有亮和暗。如果要做一整排會變色的燈,例如 30 顆的氣氛燈條, 照第 03 課的方法需要 90 支腳位(每顆燈的紅、綠、藍各一支),ESP32 根本沒有這麼多腳位。
NeoPixel 是 Adafruit 對一類「可定址 LED」的稱呼,最常見的晶片是 WS2812B。它的做法是: 每一顆燈裡面除了紅、綠、藍三個 LED,還有一顆小小的控制晶片;所有燈用一條資料線串在一起。
這一課要回答:
- 一條資料線怎麼分別告訴每一顆燈要亮什麼顏色?
- MicroPython 程式怎麼設定顏色、做出動畫?
- 燈條全亮時要多少電,什麼時候不能直接用開發板供電?
資料怎麼傳到每一顆燈
開發板從資料線送出一長串位元,每一顆燈需要 24 位元(綠、紅、藍各 8 位元)。 第一顆燈收下最前面的 24 位元留給自己,把後面的資料轉送給下一顆;第二顆再收下 24 位元,依此類推。 所以燈條上的燈有順序,程式用索引 0、1、2…指定第幾顆。
ESP32 GPIO5 ──▶ [燈 0] ──▶ [燈 1] ──▶ [燈 2] ──▶ … ──▶ [燈 7]
收 24 位元 收 24 位元 收 24 位元
WS2812B 的資料速度是 800 Kbps,一顆燈的 24 位元大約 30 微秒就送完,所以就算有幾百顆燈,更新一次也很快。
晶片實際的順序是「綠、紅、藍」,不過 MicroPython 的 neopixel 模組會幫你換好,程式裡一律寫 (紅, 綠, 藍)。
RGB:三個 0~255 的數字
每一種顏色用三個整數表示:紅(R)、綠(G)、藍(B),每個從 0 到 255,剛好是一個位元組(8 位元)。
三個位元組可以組合出 256 × 256 × 256 = 16,777,216 種顏色。網頁上的色碼 #FF5000 也是同一件事,只是用十六進位寫:
| 寫法 | 紅 | 綠 | 藍 | 看起來 |
|---|---|---|---|---|
(255, 0, 0) |
255 | 0 | 0 | 紅 |
(255, 80, 0) |
255 | 80 | 0 | 橘(#FF5000) |
(255, 255, 255) |
255 | 255 | 255 | 白(三色全亮) |
(0, 0, 30) |
0 | 0 | 30 | 很暗的藍 |
(0, 0, 0) |
0 | 0 | 0 | 熄滅 |
數字越大越亮。同樣的比例、較小的數字,就是同一種顏色比較暗的版本,例如 (30, 30, 30) 是暗一點的白。
逐步看:設定顏色,再 write() 送出
注意第 6~8 行設定顏色時,上方的燈條還沒有變;要等第 10 行 np.write() 執行完,燈條才一起換成新的顏色。
np[0] 這些索引設定的只是開發板記憶體裡的資料。
逐步看:跑馬燈
動畫就是「改顏色、write()、等一下」一直重複。每一輪先全部關掉,再只點亮第 i 顆,看起來就像一顆光點往前跑。
燈條要多少電
NeoPixel 好用,但很耗電。Adafruit 的說明文件提到,每一顆燈在三色全亮(白色、最亮)時最多大約 60 mA, 平常顯示各種顏色時,可以用每顆約 20 mA 粗略估計。
| 燈數 | 全亮白色最多 | 粗估(每顆 20 mA) |
|---|---|---|
| 8 顆 | 480 mA | 160 mA |
| 30 顆 | 1.8 A | 600 mA |
| 60 顆 | 3.6 A | 1.2 A |
開發板的 USB 供電與板上穩壓器能提供的電流有限,幾顆燈的小燈環通常沒問題,長燈條要用外接的 5V 電源, 並且把電源的 GND 和 ESP32 的 GND 接在一起(訊號才有共同的參考電位)。 程式也能幫忙省電:把顏色數字調小,亮度降低,電流也跟著降低。
接線時的幾個好習慣(來自 Adafruit 的建議):
- 在燈條的電源正負極之間並聯一顆大電容(500~1000 μF,耐壓 6.3V 以上)
- 資料線串一顆 300~500Ω 的電阻,放在靠近第一顆燈的那一端
- 接上已通電的電路時,先接 GND,再接電源,最後接資料線
- 5V 供電的燈條,最好用 5V 的資料訊號;ESP32 輸出的是 3.3V,有時需要電位轉換(level shifter)模組
下一個範例的
estimate_ma用「全亮 60 mA」依亮度比例估算,只是粗略的估計,實際電流要看燈的規格與量測。
逐步看:調亮度並估算電流
dim 函式把三個顏色乘上同一個比例。看每一輪的輸出:亮度變成十分之一,估計的電流也變成十分之一左右。
小測驗:資料與顏色
每一顆 WS2812B 的顏色資料是 24 位元(紅、綠、藍各 8 位元),一顆燈可以表示幾種顏色?
程式執行 np[3] = (0, 0, 255) 之後就結束了,沒有呼叫 np.write()。第 3 顆燈會怎樣?
下面的程式會印出什麼?
def dim(color, level):
r, g, b = color
return (int(r * level), int(g * level), int(b * level))
print(dim((200, 100, 50), 0.3))
小測驗:動畫與供電
下面的程式會印出什麼?(兩種顏色輪流,常用來做交錯閃爍的效果)
colors = [(255, 0, 0), (0, 255, 0)]
for i in range(5):
print(colors[i % 2][1], end=" ")
一條 30 顆的燈條要全部亮最亮的白色,以每顆最多 60 mA 估計,最多需要多少電流?
跑馬燈的迴圈裡少了 np.fill((0, 0, 0)) 這一行,看起來會怎樣?
重點整理
- NeoPixel(WS2812B)每一顆燈都有控制晶片,所有燈用一條資料線串接,每顆收下 24 位元、其餘轉送下一顆。
np = NeoPixel(Pin(5), 8)建立燈條;np[i] = (r, g, b)設定第 i 顆、np.fill(顏色)設定全部,數值 0~255。- 設定只改記憶體,
np.write()才會送出,燈條才改變。 - 動畫=改顏色、write()、sleep,一直重複;跑馬燈要記得先把其他燈關掉。
- 每顆燈全亮白色最多約 60 mA;燈多時用外接 5V 電源、共地,並在電源加電容、資料線加電阻。
下一課讀溫溼度感測器,再把數值顯示在 OLED 小螢幕上。