今天我们不点LED,我们点WS2812B

今天我们不点LED,我们点一下WS2812B(其实也算LED)

WS2812B是可编程的RGB灯,也就是说不同于我们之前玩的固定颜色的灯,这个灯是可以通过我们的编程来改变颜色的。

一般的LED是通上电就亮了,但是WS2812B是上电了也不亮,要让它亮,我们需要通过一根数据线给它发送数据才行。

我们给WS2812B发送24bit的数据,也就是3个Byte,高位先发,分别代表GRB(记住顺序),通过设置GBR的数值来调整绿蓝红的大小,从而改变WS2812B的颜色。

然后从上面手册里截来的图我们可以发现,我们一次性可以发很多个3Byte,这是因为我们可以把很多个WS2812B串联起来,这样我们只需要一根数据线就能控制多个WS2812B!

比如我们发送3个3Byte的数据给三个串联起来的WS2812B,第一个3Byte会被第一个灯接收,然后第一个灯会把剩下的两个3Byte传下去。

在原理图里就像是下面这样。

第一个灯的DIN接到我们的MCU的引脚上,然后把第一个灯的DOU接到下一个灯的DIN……最后一个灯的DOU直接接地就行。

然后手册里推荐是WS2812B接个10nf(104)的电容。

接着看看参数,范围还是非常大的,容错空间很大。

我是直接用STC8G1K08A来操控WS2812B的,用的5V供电(3.3V也可以的)。

自己画了块板子,上面集成了STC32和STC8两个芯片,一次性就可以玩到两种单片机,过阵子我第二版测试没问题之后再开源出来。

我在板子上的STC8G1K08A这边直接接了个WS2812B,今天我们就来看看怎么点亮它,只要知道了原理,那么换个芯片也是可以轻松点亮的。

刚刚我们知道了我们只需要一根数据线就可以点亮一堆WS2812B,每个WS2812B要接收3个Byte,3Byte按照GRB的顺序来分配绿红蓝的数值,那么问题就只剩下一个,我们应该如何发送数据?

我们可以看看手册。

我们要发送的不是0就是1,剩下RESET码就是用来区分数据批次的。

比如说我一次性要控制三个灯,然后我要让它们亮个颜色A,那么我就发送3*3个Byte。过了一下子我要让它们换个颜色,那么我就需要发送RESET码,表示我这次发送的数据是新的一批,你可别再把数据往后面送了(因为WS2812B可以串联很多个,并且它们并不知道自己后面究竟串联了多少个)

RESET码就是拉低电平一段时间。

0码和1码都是先拉高电平再拉低电平,唯一的区别就是高低电平的持续时间。

先看RESET码,因为它只需要拉低电平,比较简单,只要我们把数据线拉低超过80us,那么就算是发送了RESET码。

我们可以在发送数据之前发一下RESET码(反正也才80us),也可以在每次发送完数据之后再发送RESET码。

接着是0码和1码。

0码的高电平时间是0.2~0.35us,低电平的时间是0.55~1.2us,然后我们要注意一点,每个码元的之间不能小于0.89us,也就是说我们发送0码或者1码的高低电平的时间加起来要超过0.89us。

我们就用表格中的典型值,高电平给0.3us,低电平给0.6us。

1码和0码差不多,高低电平是顺序一样,都是先高电平后低电平,不一样的是持续时间,持续时间其实也差不多,就是高低电平的时间反过来,所以我们1码的高电平时间定为0.6us,低电平时间定为0.3us。

现在我们知道如何发送三个码元(0码1码RESET码)之后就可以开始敲代码了。

唯一的难点在于我们如何控制时间,因为时间单位是us,甚至ns,ns级别就有点难控制了。

一个办法就是用定时器,另一个土办法,我们直接延时。

因为我用的芯片是STC8,所以可以直接拿他家的烧录程序来获取延时函数。

但是人算不如天算,最低精度是1us。

这也难不倒我,经过我一顿操作和计算,STC8G1K08A的主频为24MHz,一个_nop_()大概耗时是63+ns,其实我计算的结果应该是44ns,因为1/24 000 000 约等于是40ns,但是我拿着40一个_nop_()的结果去写代码,发现好像不对劲,最后定位在了一个_nop_()大概耗时是60+ns。

不过这都不是重点,重点是我们要点亮WS2812B。

所以我们之间说的0.3us那就是需要五个_nop_()来延时,但是以防万一,我用的是四个,比较时间范围是0.2~0.35us。

0.6us就用十个_nop_()就行。

然后RESET码因为80us算是时间比较长的,我们就用STC烧录软件提供的延时代码就行。

具体可以参考下面的代码。包含的头文件是STC8的官方库函数。

#include "STC8G_H_Delay.h"
#include "STC8G_H_GPIO.h"

#define WS2812B_IN P32

// 复位
void WS2812B_SendReset(void) {
    unsigned char data i, j;
    WS2812B_IN = 0;  // 拉低80us
    i = 2;
    j = 219;
    do {
        while (--j)
            ;
    } while (--i);
}

// 发送1码
void WS2812B_SendOne(void) {
    WS2812B_IN = 1;     // 拉高延时1us
    _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
    WS2812B_IN = 0;     // 拉低延时0.3us
    _nop_();_nop_();_nop_();_nop_();
}

// 发送0码
void WS2812B_SendZero(void) {
    WS2812B_IN = 1;     // 拉高延时0.3us
    _nop_();_nop_();_nop_();_nop_();
    WS2812B_IN = 0;     // 拉低延时1us
     _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
}
// 纯红光
void WS2812B_SendRed(void) {
    unsigned char i;
    WS2812B_SendReset();
    for (i = 0; i < 8; ++i)
        WS2812B_SendZero();
    for (i = 0; i < 8; ++i)
        WS2812B_SendOne();
    for (i = 0; i < 8; ++i)
        WS2812B_SendZero();
}
// 纯绿光
void WS2812B_SendGreen(void) {
    unsigned char i;
    WS2812B_SendReset();
    for (i = 0; i < 8; ++i)
        WS2812B_SendOne();
    for (i = 0; i < 8; ++i)
        WS2812B_SendZero();
    for (i = 0; i < 8; ++i)
        WS2812B_SendZero();
}
// 纯蓝光
void WS2812B_SendBlue(void) {
    unsigned char i;
    WS2812B_SendReset();
    for (i = 0; i < 8; ++i)
        WS2812B_SendZero();
    for (i = 0; i < 8; ++i)
        WS2812B_SendZero();
    for (i = 0; i < 8; ++i)
        WS2812B_SendOne();
}


void main(void) {
    P3_MODE_OUT_PP(GPIO_Pin_2);     // 设置P32为推挽输出

    while (1) {
        WS2812B_SendRed();
        delay_ms(1000);
        WS2812B_SendBlue();
        delay_ms(1000);
        WS2812B_SendGreen();
        delay_ms(1000);
    }
}

我是让WS2812B循环更换红色蓝色绿色三种颜色的灯。

效果还行。

我有个大胆的想法,既然WS2812B可以用一根数据线来操控多个,那我直接做个可以调颜色的发光棒,主控芯片就用STC8G1K08A(成本0.3元),然后多放几个WS2812B上去……

过阵子看看实现一下。

03-12
### WS2812B LED驱动方式 WS2812B是一种集成控制电路和RGB芯片于一体的LED光源,其内部包含了电源稳压器、信号整形放大驱动电路以及高精度的内置恒流电路。这种设计使得每一个像素都能独立设置亮度和颜色,从而可以创建复杂的视觉效果。 对于WS2812B来说,数据传输采用单线串行接口协议,即只需要一根数据线即可完成通信。该协议规定了严格的时序要求来定义逻辑电平‘0’和‘1’,其中Treset时间用于区分不同帧之间的间隔[^1]。 为了简化开发者的工作量并提高效率,多个开源项目提供了专门针对WS2812B的驱动库。例如LibDriver WS2812B就是一款专为此类设备定制的功能完备的驱动程序集合;而像ESP32-S3-CAM这样的平台则可以通过调用现有的Arduino库如`WS2812FX`快速上手操作这类器件[^2]。 以下是基于Arduino环境下的简单代码片段展示如何初始化并亮一组连接到指定引脚上的WS2812B灯条: ```cpp #include <Adafruit_NeoPixel.h> #define PIN D2 // 定义数据输入管脚 #define NUMPIXELS 15 // 设置LED的数量 // 创建NeoPixels对象实例化 Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); void setup() { pixels.begin(); // 初始化 NeoPixel 库 } void loop() { // 循环遍历所有LED,并依次改变它们的颜色 for(int i=0; i<NUMPIXELS; i++) { setPixel(i); delay(50); // 延迟一段时间让变化可见 } } void setPixel(int Pixel){ byte red = random(0, 256); byte green = random(0, 256); byte blue = random(0, 256); pixels.setPixelColor(Pixel, pixels.Color(red,green,blue)); pixels.show(); } ``` 上述例子展示了基本的操作流程:先引入必要的头文件,接着声明全局变量指明使用的GPIO编号及总共有多少颗LED组成链表形式排列在一起;最后编写具体的业务逻辑函数,在主循环体内不断更新各个单元格的状态直至满足预期目标为止。 需要注意的是,随着所管理灯具数目增多,所需占用RAM资源也会相应增加。因此如果计划构建较大规模的应用场景,则可能需要考虑优化算法或者选用具备更强处理能力MCU作为控制器[^3]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值