[开发工具] 【新定义MCU开发板测评】WS2812B炫彩灯环控制

[复制链接]
 楼主| HonestQiao 发表于 2022-11-20 00:13 | 显示全部楼层 |阅读模式
本帖最后由 HonestQiao 于 2022-11-20 00:14 编辑

#申请原创#
我有一个宝贝WS2812B灯环,玩过的板子,我都要给点亮一番。



一、WS2812B控制信号了解:

WS2812B的具体介绍,这里就不详细说明了,在网上,有大量的文章资料进行说明。
要点亮WS2812B,重点在于理解以下要点:
  • WS2812B是通过单总线控制的,也就是一根信号线,控制所有的LED
  • WS2812B每收到一个特定的信号时,会认为收到了0码或者1码:信号总线上,高电平保持1s,低电平保持0.25s,则认为收到了1码;反之,如果高电平保持0.25s,低电平保持1s,则认为收到了0码。
  • 每8个0/1码,对应一种颜色控制,我们可以理解为1个8位二进制,所以范围为0~255;一颗LED,共有三种颜色,接受顺序为GRB,每种颜色取值范围在0~255,十六进制0x00~0xFF;也就是控制一颗灯珠,需要3组8个的0/1码,一个24个0/1码
  • 如果要控制多颗灯珠,则连续发送多组上述数据即可;及时某颗灯珠熄灭,也需要发送对应的0码,使其不亮。
  • 如果要多次发送控制数据,则两次之间,需要低电平保持至少50us

了解了以上信息,我们就可以考虑使用NBK-RD8x3x核心开发板来进行控制。

二、NBK-RD8x3x核心开发板能否满足要求:
从上面的说明,可以看到WS2812B对信号时序有特定的要求,这就需要我们的控制板能够满足这些要求。
进过一番测试,确认在NBK-RD8x3x核心开发板上,直接通过控制IO接口的高低电平,即可满足要求。

通过官方资料了解到:RD8T36 系列具有超高速 1T 8051 CPU 内核,运行频率高达 32MHz。
那么,如果运行在32MHz,则每一个时钟周期的时间为:T0=1/fsoc=1/32MHz=0.03125us
WS2812B要求的最小控制时间细腻度为0.25us,也就是8个T0,因为 0.25us / T0 = 0.25us / 0.03125us = 8.

在C51上,使用1个nop(),就表示一次时钟周期,那么使用8次nop(),就能够实现0.25us的时间控制了。

做好了以上前期准备工作,我们就可以开始正式的工作了。

三、连线:

在NBK-RD8x3x核心开发板的核心开发板上,有两排共4组Arduino管脚,具体如下:
75856a9477a84d60999710a9a2f316cb

我使用的WS2812B灯环,有DIN和OUT两个接口,控制信号从DIN接入,OUT用于级联下级。
DIN上有三根线,就接到Arduino管脚上,包括5V、GND和信号控制引脚。信号控制引脚,选择了D8。

从官方提供的电路原理图,可以了解到D8具体对应的IO口:
0802ca75a2b2434a1189b2896d4b540e
10314e7c9a16008e25614b71702fce3a
从上图中,可以了解到D8对应的IO口为P06。

最终实物连接如下:
6bba171a0b9de2302745c9b79dc290c8

四、代码编写:

万事俱备,只欠代码。

具体的代码如下:WS2812B_Init.c
  1. #include "H/Function_Init.H"
  2. #include <intrins.h>

  3. #define NOP                                                                    \
  4.   {                                                                            \
  5.     _nop_();                                                                   \
  6.     _nop_();                                                                   \
  7.     _nop_();                                                                   \
  8.     _nop_();                                                                   \
  9.     _nop_();                                                                   \
  10.     _nop_();                                                                   \
  11.     _nop_();                                                                   \
  12.     _nop_();                                                                   \
  13.   }
  14. #define LOW 0
  15. #define HIGH 1
  16. #define DIN P06
  17. #define NUM 24

  18. //拉低DIN保持50us以上
  19. void ws2812_init() {
  20.   uchar i;
  21.   DIN = LOW;
  22.   for (i = 0; i <= 200; i++) {
  23.     NOP;
  24.   }
  25. }

  26. //高电平0.25us,低电平1us
  27. void ws2812_write_0() {
  28.   DIN = HIGH;
  29.   NOP;
  30.   DIN = LOW;
  31.   NOP;
  32.   NOP;
  33.   NOP;
  34.   NOP;
  35. }

  36. //高电平1us,低电0.25us
  37. void ws2812_write_1() {
  38.   DIN = HIGH;
  39.   NOP;
  40.   NOP;
  41.   NOP;
  42.   NOP;
  43.   DIN = LOW;
  44.   NOP;
  45. }

  46. void ws2812_write_24bits(unsigned long dat) {
  47.   uchar t[NUM] = {0};
  48.   uchar i;

  49.   for (i = 0; i < NUM; i++) {
  50.     if (dat >> i & 1) {
  51.       t[i] = HIGH;
  52.     } else {
  53.       t[i] = LOW;
  54.     }
  55.   }
  56.   for (i = 0; i < NUM; i++) {
  57.     if (t[i]) {
  58.       ws2812_write_1();
  59.     } else {
  60.       ws2812_write_0();
  61.     }
  62.   }
  63. }

  64. void WS2812B_Test() {
  65.   unsigned int i = 0;
  66.   unsigned int j = 0;
  67.   unsigned int index = 1;
  68.   unsigned long colors[8] = {0x000000, 0xff0000, 0x00ff00, 0x0000ff,
  69.                              0xffff00, 0xff00ff, 0x00ffff, 0xffffff};

  70.   ws2812_init();
  71.   while (1) {
  72.     for (i = 0; i < NUM; i++) {
  73.       if (index % NUM == i) {
  74.         ws2812_write_24bits(colors[index % 7 + 1]);
  75.       } else {
  76.         ws2812_write_24bits(colors[0]);
  77.       }
  78.     }
  79.     index++;
  80.     if (index >= NUM) {
  81.       index = 0;
  82.     }

  83.     for (j = 0; j <= 5; j++) {
  84.       for (i = 0; i <= 4000; i++) {
  85.         NOP;
  86.       }
  87.     }
  88.   }
  89. }



上述代码关键说明:
  • #define NOP:用于定义8个nop()调用,获得0.25us时间占用
  • ws2812_init():提供50us以上低电平保持
  • ws2812_write_0():输出0码
  • ws2812_write_1():输出1码
  • ws2812_write_24bits():根据颜色值,输出24位的0/1码
  • WS2812B_Test():测试主逻辑程序
  • colors: 使用到的颜色值定义

代码中,还用到了index变量,通过其控制当前应该点亮第几颗灯珠,并使用其对7取余,从而则colors中选用对应的颜色。

然后,在main.c中调用即可,具体如下:
5ce350a88432b60a3d8cc22b8f6aceaa

最后,编译下载,WS2812B灯环,就会欢快的跳跃起来:
RD_灯环效果.gif

90af01ff621c1c0db487fd435ffdd091
lzbf 发表于 2023-2-7 20:25 | 显示全部楼层
这个定时器直接操作 的吗?              
benjaminka 发表于 2023-2-7 20:46 | 显示全部楼层
这个最大可以驱动多少个WS2812B?
nomomy 发表于 2023-2-7 21:10 | 显示全部楼层
WS2812B的时序还是比较严格
updownq 发表于 2023-2-7 21:45 | 显示全部楼层
可以移植arduino的库过来的吗?
cashrwood 发表于 2023-2-7 21:59 | 显示全部楼层
可以使用spi控制的吗?              
weifeng90 发表于 2023-2-10 08:41 来自手机 | 显示全部楼层
RGB灯就是炫酷啊
uiint 发表于 2023-3-7 21:04 | 显示全部楼层
怎么通过定时器实现1us的延时呢?
geraldbetty 发表于 2023-3-7 21:23 | 显示全部楼层
直接定时器控制WS2812B可靠吗?
caigang13 发表于 2023-3-7 21:30 来自手机 | 显示全部楼层
WS2812被玩出彩了啊,各种DIY产品。
lzbf 发表于 2023-3-7 21:39 | 显示全部楼层
此驱动器可以驱动多少个WS2812B?
albertaabbot 发表于 2023-3-9 13:28 | 显示全部楼层
WS2812B的功耗特别大,还是通过专用的驱动电路吧。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

42

主题

110

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部