本文主要介紹使用.Net nanoFramework驅動驅動 ESP32-S3-Zero 板載的 WS2812B LED的問題,以及如何設計一個燈光控制類,來方便的使用工作狀態燈來顯示裝置的工作狀態。
1. 引言
在使用Net nanoFramework驅動 ESP32-S3-Zero 的板載 WS2812B LED 時,你可能遇到一些挑戰,如LED反色問題。本文將詳細探討如何解決這些問題,以及如何有效地利用工作狀態燈來顯示裝置的工作狀態。我們將使用
Iot.Device.Ws28xx.Esp32
庫,這是一個專為ESP32板設計的庫,用於驅動WS28xx系列的LED。
2. 板載 LED 的使用
在硬體上的開發與純軟體不同,因為我們使用的硬體的一些特異性,往往同樣的程式碼在不同的硬體上會有不同的表現。這就需要我們在開發的時候,對硬體的特性有一定的了解,這樣才能更好的使用硬體。
一般來說透過
Iot.Device.Ws28xx.Esp32
庫,我們即可方便的驅動自己的 LED。根據板子的資料我們可以查到 ESP32-S3-Zero 板載了一顆 WS2812B LED,這顆 LED 的引腳是 GPIO 21,我們可以透過以下程式碼來驅動這顆 LED:
int WS2812_Count = 1;
int WS2812_Pin = 21;
var leddev = newWs2812b(WS2812_Pin, WS2812_Count);
BitmapImage img = leddev.Image;
img.SetPixel(0, 0, Color.Red);
leddev.Update();
Thread.Sleep(1000);
img.SetPixel(0, 0, Color.Green);
leddev.Update();
Thread.Sleep(1000);
img.SetPixel(0, 0, Color.Blue);
leddev.Update();
這樣我們就可以透過這顆 LED 來顯示不同的顏色了。但是實際情況是,燈光顏色奇奇怪怪,都趨近於白色。當我們將
Ws2812b
更換為
Ws2812c
時,可以驅動正常的顏色了,但是顏色卻是反的。
3. 解決 LED 反色問題
透過官方倉庫的
源碼
[1]
我們可以看到,
Ws2812b
類的建構函式中,使用了
BitmapImageNeo3
類來初始化
Image
內容,而
Ws2812c
類中使用的是
BitmapImageWs2808Grb
。根據根據板子使用的
XL-0807RGBC-WS2812B
技術數據表來看,其顏色數據使用的是RGB順序,這就不難發現問題所在了。
針對這種情況,我們可以透過繼承
Ws28xx
類,然後自行修改,來解決這個問題。之前
BitmapImageWs2808Grb
、
BitmapImageWs2808
等這些類都是
internal
,無法繼承。目前最新的版本已經將這些類修改為
public
,我們可以直接繼承這些類,然後修改
Image
物件使用
BitmapImageWs2808
,來解決這個問題。
public classXlWs2812b : Ws28xx
{
publicXlWs2812b(int gpioPin, int width, int height = 1)
: base(gpioPin, newBitmapImageWs2808(width, height))
{
ClockDivider = 2;
OnePulse = newRmtCommand(32, true, 18, false);
ZeroPulse = newRmtCommand(16, true, 34, false);
ResetCommand = newRmtCommand(2000, false, 2000, false);
}
}
添加好這個類,我們就可以透過
XlWs2812b
類來驅動我們的 LED 了。
4. 工作狀態燈的套用
為了更好的了解裝置的工作狀態,我們可以透過工作狀態燈來顯示裝置的工作狀態。這樣,我們就可以透過燈光的顏色來了解裝置的工作狀態。
4.1 工作狀態燈的設計
首先我們先定義一個列舉,用於表示裝置的工作狀態:
/// <summary>
/// 定義裝置狀態
/// </summary>
publicenumRunStatus
{
/// <summary>
/// 啟動中,燈藍色常亮
/// </summary>
Start,
/// <summary>
/// 請求辨識,藍色快閃
/// </summary>
OnIdentify,
/// <summary>
/// 驗證成功,燈綠色常亮
/// </summary>
AuthSuccess,
/// <summary>
/// wifi連線中,橙色快爍
/// </summary>
Connecting,
/// <summary>
/// wifi 配置問題,紅色閃爍
/// </summary>
ConfigFailed,
/// <summary>
/// wifi 連線失敗,紅色常亮
/// </summary>
ConnectFailed,
/// <summary>
/// 正常工作中,綠色呼吸燈
/// </summary>
Working,
/// <summary>
/// 關閉燈光
/// </summary>
Close
}
然後我們定義一個
BoardLedControl
類,用於控制燈光的顯示,這個類的建構函式中,我們可以設定燈光的引腳,以及燈光的檢查間隔。這個類中,我們使用了一個執行緒來檢查燈光的狀態,這樣我們就可以在其他執行緒中,透過修改燈光的狀態來控制燈光的顯示。
/// <summary>
/// 工作燈控制
/// </summary>
/// <param name="pin">Gpio Pin</param>
/// <param name="checkDelay">控制檢查間隔</param>
publicBoardLedControl(int pin = 21,int checkDelay = 500)
{
WS2812_Pin = pin;
leddev = newXlWs2812b(WS2812_Pin, 1, 1);
image = leddev.Image;
statusThread = newThread(() => {
while (true)
{
if (autoUpdate)
{
UpdateLedStatus();
}
}
});
statusThread.Start();
}
4.2 幾種燈光模式
在
BoardLedControl
類中,我們定義了幾種燈光模式,常亮,閃爍,呼吸燈等。
/// <summary>
/// 燈光效果-閃爍
/// </summary>
/// <param name="color">顏色</param>
/// <param name="delay">時延</param>
publicvoidLedBlink(Color color,int delay = 500)
{
image.SetPixel(0, 0, color);
leddev.Update();
Thread.Sleep(delay);
image.SetPixel(0, 0, Color.Black);
leddev.Update();
Thread.Sleep(delay);
}
/// <summary>
/// 燈光顏色設定
/// </summary>
/// <param name="color">顏色</param>
/// <param name="sleepDuration">等待</param>
publicvoidLedSet(Color color, int sleepDuration = 0)
{
image.SetPixel(0, 0, color);
leddev.Update();
if (sleepDuration > 0)
{
Thread.Sleep(sleepDuration);
}
}
/// <summary>
/// 燈光效果-呼吸
/// </summary>
/// <param name="color">顏色</param>
/// <param name="duration">時長</param>
/// <param name="steps">步長</param>
publicvoidLedBreath(Color color, int duration = 3900, int steps = 20)
{
// 限制參數範圍
steps = steps < 10 ? 10 : steps;
duration = duration < 1000 ? 1000 : duration;
// 計算每一步的暫停時長 (單位:毫秒)
int sleepDuration = duration / (2 * steps);
for (int i = 1; i <= steps; i++)
{
// 計算當前明度
float brightness = (float)i / steps;
// 設定顏色
Color currentColor = Color.FromArgb(
(int)(color.R * brightness),
(int)(color.G * brightness),
(int)(color.B * brightness));
LedSet(currentColor, sleepDuration);
}
for (int i = steps; i > 0; i--)
{
float brightness = (float)i / steps;
Color currentColor = Color.FromArgb(
(int)(color.R * brightness),
(int)(color.G * brightness),
(int)(color.B * brightness));
LedSet(currentColor, sleepDuration);
}
}
4.3 燈光狀態檢查
在
BoardLedControl
類中,我們定義了一個
UpdateLedStatus
方法,用於檢查燈光的狀態,然後根據燈光的狀態來控制燈光的顯示。
/// <summary>
/// 更新燈光
/// </summary>
publicvoidUpdateLedStatus()
{
// 根據裝置狀態更新燈光
switch (DeviceStatus)
{
caseRunStatus.Start:
LedSet(Color.Blue);
break;
caseRunStatus.OnIdentify:
LedBlink(Color.Blue, 200);
break;
caseRunStatus.AuthSuccess:
LedSet(Color.Green);
break;
caseRunStatus.Connecting:
LedBlink(Color.Orange, 200);
break;
caseRunStatus.ConfigFailed:
LedBlink(Color.Red);
break;
caseRunStatus.ConnectFailed:
LedSet(Color.Red);
break;
caseRunStatus.Working:
LedBreath(Color.Green);
break;
default:
LedSet(Color.Black);
break;
}
}
4.4 使用工作狀態燈
在使用工作狀態燈時,我們可以透過以下程式碼來使用:
// 初始化燈光控制
var _led = newBoardLedControl();
// 開啟工作燈,藍色引擎啟動!
_led.StartAutoUpdate();
// ....
// 更改狀態
_led.DeviceStatus = RunStatus.OnIdentify;
在使用中,我們可以透過修改
DeviceStatus
內容來控制燈光的顯示,這樣我們就可以透過燈光的顏色來了解裝置的工作狀態了。當然,也可以不啟用自動更新
StartAutoUpdate()
或在合適時候使用
StopAutoUpdate
方法關閉自動更新,然後透過直接呼叫
LedSet
、
LedBlink
、
LedBreath
等方法來控制燈光的顯示。
5. 最後
雖然在使用 ESP32 的板載 WS2812B LED 可能會遇到一些問題,但只要你理解了這些問題的原因,就可以找到解決方案。同時,工作狀態燈是一種非常有效的工具,可以幫助你更好地了解裝置的工作狀態。我們希望本文能對你在使用 ESP32驅動 WS2812B LED 時提供幫助。文章中的程式碼已經上傳到 Github ESP32_S3_Samples [2] 計畫,歡迎大家下載使用。
References
[1]
源碼:
https://github.com/nanoframework/nanoFramework.IoT.Device/blob/develop/devices/Ws28xx.Esp32/Ws2812B.cs?wt.mc_id=DT-MVP-5005195
[2]
ESP32_S3_Samples:
https://github.com/sangyuxiaowu/ESP32_S3_Samples?wt.mc_id=DT-MVP-5005195