当前位置: 欣欣网 > 码农

解决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