本文主要介绍使用.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:
cs
int WS2812_Count = 1;
int WS2812_Pin = 21;
var leddev = new Ws2812b(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 反色问题
通过官方仓库的 源码 我们可以看到,Ws2812b
类的构造函数中,使用了 BitmapImageNeo3
类来初始化 Image
属性,而 Ws2812c
类中使用的是 BitmapImageWs2808Grb
。根据根据板子使用的 XL-0807RGBC-WS2812B
技术数据表来看,其颜色数据使用的是RGB顺序,这就不难发现问题所在了。
针对这种情况,我们可以通过继承 Ws28xx
类,然后自行修改,来解决这个问题。之前BitmapImageWs2808Grb
、BitmapImageWs2808
等这些类都是 internal
,无法继承。目前最新的版本已经将这些类修改为 public
,我们可以直接继承这些类,然后修改 Image
对象使用BitmapImageWs2808
,来解决这个问题。
cs
public class XlWs2812b : Ws28xx
{
public XlWs2812b(int gpioPin, int width, int height = 1)
: base(gpioPin, new BitmapImageWs2808(width, height))
{
ClockDivider = 2;
OnePulse = new RmtCommand(32, true, 18, false);
ZeroPulse = new RmtCommand(16, true, 34, false);
ResetCommand = new RmtCommand(2000, false, 2000, false);
}
}
添加好这个类,我们就可以通过 XlWs2812b
类来驱动我们的 LED 了。
4. 工作状态灯的应用
为了更好的了解设备的工作状态,我们可以通过工作状态灯来显示设备的工作状态。这样,我们就可以通过灯光的颜色来了解设备的工作状态。
4.1 工作状态灯的设计
首先我们先定义一个枚举,用于表示设备的工作状态:
cs
/// <summary>
/// 定义设备状态
/// </summary>
public enum RunStatus
{
/// <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
类,用于控制灯光的显示,这个类的构造函数中,我们可以设置灯光的引脚,以及灯光的检查间隔。这个类中,我们使用了一个线程来检查灯光的状态,这样我们就可以在其他线程中,通过修改灯光的状态来控制灯光的显示。
cs
/// <summary>
/// 工作灯控制
/// </summary>
/// <param name="pin">Gpio Pin</param>
/// <param name="checkDelay">控制检查间隔</param>
public BoardLedControl(int pin = 21,int checkDelay = 500)
{
WS2812_Pin = pin;
leddev = new XlWs2812b(WS2812_Pin, 1, 1);
image = leddev.Image;
statusThread = new Thread(() => {
while (true)
{
if (autoUpdate)
{
UpdateLedStatus();
}
}
});
statusThread.Start();
}
4.2 几种灯光模式
在 BoardLedControl
类中,我们定义了几种灯光模式,常亮,闪烁,呼吸灯等。
cs
/// <summary>
/// 灯光效果-闪烁
/// </summary>
/// <param name="color">颜色</param>
/// <param name="delay">时延</param>
public void LedBlink(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>
public void LedSet(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>
public void LedBreath(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
方法,用于检查灯光的状态,然后根据灯光的状态来控制灯光的显示。
cs
/// <summary>
/// 更新灯光
/// </summary>
public void UpdateLedStatus()
{
// 根据设备状态更新灯光
switch (DeviceStatus)
{
case RunStatus.Start:
LedSet(Color.Blue);
break;
case RunStatus.OnIdentify:
LedBlink(Color.Blue, 200);
break;
case RunStatus.AuthSuccess:
LedSet(Color.Green);
break;
case RunStatus.Connecting:
LedBlink(Color.Orange, 200);
break;
case RunStatus.ConfigFailed:
LedBlink(Color.Red);
break;
case RunStatus.ConnectFailed:
LedSet(Color.Red);
break;
case RunStatus.Working:
LedBreath(Color.Green);
break;
default:
LedSet(Color.Black);
break;
}
}
4.4 使用工作状态灯
在使用工作状态灯时,我们可以通过以下代码来使用:
cs
// 初始化灯光控制
var _led = new BoardLedControl();
// 开启工作灯,蓝色引擎启动!
_led.StartAutoUpdate();
// ....
// 更改状态
_led.DeviceStatus = RunStatus.OnIdentify;
在使用中,我们可以通过修改 DeviceStatus
属性来控制灯光的显示,这样我们就可以通过灯光的颜色来了解设备的工作状态了。当然,也可以不启用自动更新StartAutoUpdate()
或在合适时候使用StopAutoUpdate
方法关闭自动更新,然后通过直接调用 LedSet
、LedBlink
、LedBreath
等方法来控制灯光的显示。
5. 最后
虽然在使用 ESP32 的板载 WS2812B LED 可能会遇到一些问题,但只要你理解了这些问题的原因,就可以找到解决方案。同时,工作状态灯是一种非常有效的工具,可以帮助你更好地了解设备的工作状态。我们希望本文能对你在使用 ESP32驱动 WS2812B LED 时提供帮助。文章中的代码已经上传到 Github ESP32_S3_Samples 项目,欢迎大家下载使用。