1. 引言

在使用Net nanoFramework驱动 ESP32-S3-Zero 的板载 WS2812B LED 时,你可能遇到一些挑战,如LED反色问题。本文将详细探讨如何解决这些问题,以及如何有效地利用工作状态灯来显示设备的工作状态。我们将使用Iot.Device.Ws28xx.Esp32库,这是一个专为ESP32板设计的库,用于驱动WS28xx系列的LED。

解决ESP32板载WS2812B LED反色问题及工作状态灯的应用-LMLPHP

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 = 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 类,然后自行修改,来解决这个问题。之前BitmapImageWs2808GrbBitmapImageWs2808 等这些类都是 internal,无法继承。目前最新的版本已经将这些类修改为 public,我们可以直接继承这些类,然后修改 Image 对象使用BitmapImageWs2808,来解决这个问题。

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 工作状态灯的设计

首先我们先定义一个枚举,用于表示设备的工作状态:

/// <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 类,用于控制灯光的显示,这个类的构造函数中,我们可以设置灯光的引脚,以及灯光的检查间隔。这个类中,我们使用了一个线程来检查灯光的状态,这样我们就可以在其他线程中,通过修改灯光的状态来控制灯光的显示。

/// <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 类中,我们定义了几种灯光模式,常亮,闪烁,呼吸灯等。

/// <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 方法,用于检查灯光的状态,然后根据灯光的状态来控制灯光的显示。

/// <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 使用工作状态灯

在使用工作状态灯时,我们可以通过以下代码来使用:

// 初始化灯光控制
var _led = new BoardLedControl();
// 开启工作灯,蓝色引擎启动!
_led.StartAutoUpdate();
// ....
// 更改状态
_led.DeviceStatus = RunStatus.OnIdentify;

解决ESP32板载WS2812B LED反色问题及工作状态灯的应用-LMLPHP

在使用中,我们可以通过修改 DeviceStatus 属性来控制灯光的显示,这样我们就可以通过灯光的颜色来了解设备的工作状态了。当然,也可以不启用自动更新StartAutoUpdate()或在合适时候使用StopAutoUpdate方法关闭自动更新,然后通过直接调用 LedSetLedBlinkLedBreath 等方法来控制灯光的显示。

5. 最后

虽然在使用 ESP32 的板载 WS2812B LED 可能会遇到一些问题,但只要你理解了这些问题的原因,就可以找到解决方案。同时,工作状态灯是一种非常有效的工具,可以帮助你更好地了解设备的工作状态。我们希望本文能对你在使用 ESP32驱动 WS2812B LED 时提供帮助。文章中的代码已经上传到 Github ESP32_S3_Samples 项目,欢迎大家下载使用。

01-29 12:11