當前位置: 妍妍網 > 碼農

解決ESP32板載WS2812B LED反色問題及工作狀態燈的套用

2024-01-30碼農

本文主要介紹使用.Net nanoFramework驅動驅動 ESP32-S3-Zero 板載的 WS2812B LED的問題,以及如何設計一個燈光控制類,來方便的使用工作狀態燈來顯示裝置的工作狀態。

1. 引言

在使用Net nanoFramework驅動 ESP32-S3-Zero 的板載 WS2812B LED 時,你可能遇到一些挑戰,如LED反色問題。本文將詳細探討如何解決這些問題,以及如何有效地利用工作狀態燈來顯示裝置的工作狀態。我們將使用 Iot.Device.Ws28xx.Esp32 庫,這是一個專為ESP32板設計的庫,用於驅動WS28xx系列的LED。

Ws28xx

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