2023-01-20

使用 RP2040微控制器 控制 NeoPixel

傳統 LED 或 RGB LED 都是對應控制不同顏色光源的引腳傳送訊號
越多光源,即使以多路複用接駁,仍然需要越多引腳
而且數碼訊號只能控制開關操作,如果要控制亮度便需要具備 PWM 的引腳
因此尋找其他替代品可以更方便控制

RP2040-Zero 外觀

見下文
RP2040-Zero 正面

見下文
RP2040-Zero 使用 GP16 以 NeoPixel RGB LED 取代傳統 LED 作為 電路板LED
增強視覺訊號效果

見下文
1P 2MB 快閃記憶體

見下文
使用 USB Type-C 插口

見下文
與 Raspberry Pi Pico 相同的 RP2040晶片焊接在 RP2040-Zero 背後

見下文
使用 12MHz 晶體振盪器

見下文
J2 3.3V 線性穩壓器

RP2040-Zero 引腳

見下文
RP2040-Zero 雖然細少,但能夠使用所有 GPIO引腳
GP0 至 GP15 及 GP26 至 GP29 引腳使用 0.1英寸間隔引腳
其中 GP0 至 GP8, GP14, GP15, GP26 至 GP29 引腳使用 雙列直插 設計,能夠安裝到麵包板上使用
而 GP9 至 GP13 則在 RP2040-Zero 末端,能夠讓 通孔裝置 直接連接使用

正面左側引腳 正面右側引腳
5V 5V 電源輸出 GP0 第0數碼引腳
GND 接地 GP1 第1數碼引腳
3V3 3.3V 電源輸出 GP2 第2數碼引腳
GP29 第29數碼引腳,第3類比引腳 GP3 第3數碼引腳
GP28 第28數碼引腳,第2類比引腳 GP4 第4數碼引腳
GP27 第27數碼引腳,第1類比引腳 GP5 第5數碼引腳
GP26 第26數碼引腳,第0類比引腳 GP6 第6數碼引腳
GP15 第15數碼引腳 GP7 第7數碼引腳
GP14 第14數碼引腳 GP8 第8數碼引腳
正面末端引腳(左至右)
GP13 第13數碼引腳
GP12 第12數碼引腳
GP11 第11數碼引腳
GP10 第10數碼引腳
GP9 第9數碼引腳

見下文
另外 RP2040-Zero 背後的 GP17 至 GP25 引腳則使用表面焊接焊墊

RP2040-One 外觀

見下文
RP2040-One 正面

見下文
RP2040-One 同樣使用 GP16 以 NeoPixel RGB LED 取代傳統 LED 作為 電路板LED

見下文
WK 3.3V 線性穩壓器

見下文
25Q32JVS1Q 4MB 快閃記憶體

見下文
使用 USB Type-A 插頭,能夠不需要連接線路、直接安裝到大部分電腦上使用

見下文
同樣 RP2040晶片焊接在 RP2040-One 背後

見下文
同樣使用 12MHz 晶體振盪器

RP2040-One 引腳

見下文
見下文
與 RP2040-Zero 相同佈局的引腳

見下文
見下文
RP2040-One 及 RP2040-Zero 基本上完全相同,兩者都是非常方面連接到電腦

NeoPixel 引腳

NeoPixel 是一種使用 WS2812B晶片 控制的 RGB LED
不計算 電源引腳 及 接地引腳 ,只需要1支 DI引腳 便能夠控制 LED的顏色及亮度

NeoPixel 訊號

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
NeoPixel RGB LED 色碼以 GRB 次序排序,而非 RGB
3種顏色 及 8位元亮度,總共 24位元,並依 最高有效位 開始
向 NeoPixel 發送 24位元訊號大約需要 30000納秒 (Nanosecond)
因此,平均每1位元訊號大約需要 1250納秒

要向 NeoPixel 發送 位元訊號 並非單純將 DI引腳 設定為 高電壓訊號 或 低電壓訊號

0
要讓 DI引腳 保持 高電壓大約 300納秒 ,再讓 DI引腳 保持 低電壓大約 950納秒,將低位訊號 寫入到緩衝區

1
要讓 DI引腳 保持 高電壓大約 800納秒 ,再讓 DI引腳 保持 低電壓大約 450納秒,將高位訊號 寫入到緩衝區

Reset
讓 DI引腳 保持 低電壓大約 50000納秒,令緩衝區的資料寫到晶片,觸發效果

訊號模擬

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
紅(DEC) 綠(DEC) 藍(DEC) RGB(HEX)
(Arduino適用)
GRB(DEC)
(*Python適用)
十進制 0 0 0 0 (0, 0, 0)
十六進制 0x00 0x00 0x00 #000000 (0x00, 0x00, 0x00)

RP2040-Zero 使用 12MHz 晶體振盪器, 1 / 12000000 = 0.000000083秒 = 82納秒
因此能夠應付 NeoPixel 的訊號要求

測試 NeoPixel

見下文
NeoPixel 能混合顯示不同顏色

見下文
NeoPixel 具備 8位元亮度

使用 MicroPython

由於 MicroPython 已經內建 NeoPixel 函式庫,不需要額外函式庫已經能夠驅動 WS2812B
from machine import Pin
from time import sleep
from neopixel import NeoPixel

DELAY = 1
LEVEL = 0x10
CLEAR = 0x00
COLOR = [
	(CLEAR, CLEAR, CLEAR), # NONE
	(LEVEL, CLEAR, CLEAR), # RED
	(CLEAR, LEVEL, CLEAR), # GREEN
	(CLEAR, CLEAR, LEVEL), # BLUE
	(LEVEL, LEVEL, CLEAR), # YELLOW
	(CLEAR, LEVEL, LEVEL), # CYAN
	(LEVEL, CLEAR, LEVEL), # MAGENTA
	(LEVEL, LEVEL, LEVEL), # WHITE
]
PIN = 16
NUM = 1

rgb = NeoPixel(Pin(PIN, Pin.OUT), NUM)

while True:
	for i in COLOR:
		for j in range(NUM):
			rgb[j] = i
			rgb.write()
			sleep(DELAY)

使用 CircuitPython

import digitalio 
from neopixel_write import neopixel_write
from adafruit_pixelbuf import PixelBuf

class NeoPixel(PixelBuf):
	def __init__(self, dinPin, number):
		super().__init__(number, auto_write = False, byteorder = "GRB")
		self.__din = digitalio.DigitalInOut(dinPin)
		self.__din.direction = digitalio.Direction.OUTPUT
	def _transmit(self, buffer):
		neopixel_write(self.__din, buffer)

這個類別實際只是將 Adafruit 的 neopixel.py 簡化到與 MicroPython 用途相似的的內容
import board
from time import sleep
from neopixel import NeoPixel

DELAY = 1
LEVEL = 0x10
CLEAR = 0x00
COLOR = [
	(CLEAR, CLEAR, CLEAR), # NONE
	(CLEAR, LEVEL, CLEAR), # RED
	(LEVEL, CLEAR, CLEAR), # GREEN
	(CLEAR, CLEAR, LEVEL), # BLUE
	(LEVEL, LEVEL, CLEAR), # YELLOW
	(LEVEL, CLEAR, LEVEL), # CYAN
	(CLEAR, LEVEL, LEVEL), # MAGENTA
	(LEVEL, LEVEL, LEVEL), # WHITE
]
PIN = board.GP16
NUM = 1

rgb = NeoPixel(PIN, NUM)

while True:
	for i in COLOR:
    	for j in range(NUM):
			rgb[j] = i
			rgb.show()
			sleep(DELAY)

使用 Arduino

#include <Adafruit_NeoPixel.h>

const unsigned int DELAY = 1000;
const byte LEVEL = 0x10;
const byte CLEAR = 0x00;
const unsigned long COLOR[] = {
	(0UL + CLEAR) << 16 | (0UL + CLEAR) << 8 | CLEAR, // NONE
	(0UL + CLEAR) << 16 | (0UL + LEVEL) << 8 | CLEAR, // RED
	(0UL + LEVEL) << 16 | (0UL + CLEAR) << 8 | CLEAR, // GREEN
	(0UL + CLEAR) << 16 | (0UL + CLEAR) << 8 | LEVEL, // BLUE
	(0UL + LEVEL) << 16 | (0UL + LEVEL) << 8 | CLEAR, // YELLOW
	(0UL + LEVEL) << 16 | (0UL + CLEAR) << 8 | LEVEL, // CYAN
	(0UL + CLEAR) << 16 | (0UL + LEVEL) << 8 | LEVEL, // MAGENTA
	(0UL + LEVEL) << 16 | (0UL + LEVEL) << 8 | LEVEL, // WHITE
};
const byte PIN = 16;
const unsigned int NUM = 1;

Adafruit_NeoPixel rgb = Adafruit_NeoPixel(NUM, PIN, NEO_GRB + NEO_KHZ800);

void setup() {
	rgb.begin();
}

void loop() {
	for (unsigned int i = 0; i < sizeof(COLOR) / sizeof(unsigned long); i++) {
		for (unsigned int j = 0; j < NUM; j++) {
			rgb.setPixelColor(j, COLOR[i]);
			rgb.show();
			delay(DELAY);
		}
	}
}


NeoPixel串列連接

WS2812B NeoPixel VCC GND DI DO VCC SIG GND
只需要 1條訊號線 便可以控 NeoPixel,而往後的訊號線亦 只需要 1條訊號線 ,以串列方式連接
減少 微控制器 引腳的使用數量

NeoPixel燈條

NeoPixel燈條 是最常見的 NeoPixel 串列連接模組

見下文
8位NeoPixel燈條 正面

見下文
使用串列方式連接的 NeoPixel

見下文
8位NeoPixel燈條 背面

見下文
見下文
線路接駁的終端,標示著對應引腳的用途

見下文
在下使用銅線焊接到焊墊上,並屈曲成90度,方便安裝到麵包板或直接安裝到 RP2040-Zero

見下文
很簡單便可以製作 RGB LED 燈飾

NeoPixel燈環

見下文
16位NeoPixel燈環 正面

見下文
NeoPixel燈環 背面

見下文
引腳佈局與燈條略有不同

見下文
在下同樣焊接銅線並屈曲至90度,再加上顏色方便辨認引腳用途

見下文
操作燈環與操作燈條基本上相同,只需要因應 NeoPixel 的數量調整即可

見下文
只要將 前一個 NeoPixel 的 DO引腳 連接至 後一個 NeoPixel 的 DI引腳,再設定數量,即可達到串列連接的效果

NeoPixel燈板

NeoPixel燈板同樣是常見的 NeoPixel 串列連接模組
不少商場公告都使用類似的裝置展示訊息

見下文
64位NeoPixel燈板 正面

見下文
64位NeoPixel燈板 背面

見下文
見下文
使用 0.1寸 通孔引腳設計,方便焊接一般引腳

見下文
見下文
在下使用不同顏色的引腳焊接,方便分辨引腳用途

見下文
操作與燈條及燈環都是相同,便可以很方便地製作 RGB LED 的電子顯示熒幕

見下文
第1欄 第2欄 第3欄 第4欄 第5欄 第6欄 第7欄 第8欄
第1列 1 2 3 4 5 6 7 8
第2列 9 10 11 12 13 14 15 16
第3列 17 18 19 20 21 22 23 24
第4列 25 26 27 28 29 30 31 32
第5列 33 34 35 36 37 38 39 40
第6列 41 42 43 44 45 46 47 48
第7列 49 50 51 52 53 54 55 56
第8列 57 58 59 60 61 62 63 64
NeoPixel燈板只是陣列排列,不是矩陣排列不同﹐因此沒有列欄概念
以 8x8 NeoPixel燈板為例子,控制 第4列第2欄 的 NeoPixel 是 第26格,即是陣列第25項目

補充資料

NeoPixel的結構
NeoPixel 已經很細少,但能夠方便地控制 RGB LED 的 WS2812B 更細小

見下文
NeoPixel 近距離的外觀

見下文
中央是 WS2812B晶片,大約只有 0.3毫米

見下文
左下方是 綠色LED ,大約只有 0.1毫米

見下文
中下方是 紅色LED ,大約只有 0.1毫米

見下文
右下方是 藍色LED ,大約只有 0.1毫米

見下文
近距離觀察三色閃動的 NeoPixel
雖然 三色種LED 都是獨立發放不同顏色的光
當不同顏色的光在近距離亮著時,光線便會混合成另一種顏色的光,便可以混合出不同顏色

顏色挑選器
模擬訊號中,在下使用了 HTML5 的 input color 來啟動 顏色挑選器 (Color Picker)
發現不同作業系統不同網頁瀏覽器有很大差異
雖然與 WS2812B 完全沒有關係,但在下仍然作簡單測試

在 Linux 上的 Firefox
見下文
見下文
Linux 上的 Firefox
操作上不算是最高,但提供基本的預設色板
當預設色板不足時,可以使用自訂開啟 HSV色板 選擇顏色
無法與其他元素即時互動

Chrome
見下文
所有桌面作業系統的 Chrome 都是相效果
直接開啟 HSV色板
能夠與其他元素即時互動

在 Linux 上的 Konqueror
見下文
Linux 上的 Konqueror
提供預設色板、擷取熒幕顏色、自訂色板、HSV色板、HSV數值輸入、RGB數值輸入、HEX數值輸入
能夠與其他元素即時互動

在 Windows 上的 Firefox
見下文
Windows 上的 Firefox ,效果與 Linux 上的 Firefox 完全不同
偏向與 Linux 上的 Konqueror 相似,只是沒有擷取熒幕顏色
能夠與其他元素即時互動

在 Mac 上的 Safari
Mac 上的 Safari 提供大量色板功能,總共有5頁

見下文
圓形色板
能夠與其他元素即時互動

見下文
圓形色板
能夠與其他元素即時互動

見下文
RGB滑桿設定,還有多種色板模式
能夠與其他元素即時互動

見下文
預設色板,除了由Apple提供的預設色板,還有其他預設色板
能夠與其他元素即時互動

見下文
光譜色板,還有多種色板模式
能夠與其他元素即時互動

在 Mac 上的 Firefox
見下文
Mac 上的 Firefox 提供預設色板
按下 顯示顏色 後,會開啟 Mac 上的 Safari 的色板功能
能夠與其他元素即時互動

在 Android 上的 Firefox
見下文
Android 上的 Firefox 只有預設色板
無法與其他元素即時互動

在 Android 上的 Chrome
見下文
見下文
Android 上的 Chrome 的色板與 Linux 上的 Firefox 相似
先顯示預設色板,不足夠時會開啟 HSV滑桿設定顏色
無法與其他元素即時互動

見下文
Samsung 瀏覽器雖然能夠執行 預設色板 及 HSV色板,但選取顏色後無法設定

iOS
iOS 上所有網頁瀏覽器都使用相同效果

見下文
與 Mac 的 Safari 相同的預設色板
能夠與其他元素即時互動

見下文
與 Mac 的 Safari 相同的光譜色板
能夠與其他元素即時互動

見下文
與 Mac 的 Safari 相同的RGB滑桿色板
能夠與其他元素即時互動

零件清單

名稱 數量
RP2040-Zero 1
RP2040-One 1
麵包板 1
USB Type-C 資料線 1
NeoPixel燈條 1
NeoPixel燈環 1
NeoPixel燈板 1
跳線 大約10條

總結

NeoPixel 操作上雖然需要一點程序,但因為 Arduino, MicroPython, CircuitPython 都提供簡單使用的函式庫
所以使用上已經非常簡單,希望所有開發板都預裝 NeoPixel 方便測試
甚至是預裝 有源蜂鳴器 或 無源蜂鳴器 ,滿足視覺效果及聽覺效果的開發

參考資料

沒有留言 :

張貼留言