ws2812 python ws2812 python音乐led_数据

实战microPython(05)-WS2812全彩LED灯串的控制

David Zou 2018-09-17

在喜庆的节日中,我们经常使用彩灯串来增加节日的气氛。最早期的使用的是单色的小灯珠,只有亮灭状态,通过不停的闪动节奏来烘托气氛。随着科技的发展,LED的出现逐渐取代了耗电的小灯珠。而随着彩色的LED的出现,节日灯串也进入了彩色的时代。而彩色的LED也不只用于节日烘托气氛,可以用在更广泛的领域,如家居的氛围照明,LED大屏幕显示,音响的频谱显示等。

那么,对于彩灯串的控制方式由于需要控制每个LED灯珠的颜色,及亮度,因此往往电路都非常复杂。但自从市面出现了以W2812B为芯片的灯珠后,控制方式就大大简化了。所谓基于WS2812B的LED灯珠,就是将一个控制芯片封装进全彩LED灯珠中:

ws2812 python ws2812 python音乐led_全彩LED_02


灯珠只有4个引脚。

ws2812 python ws2812 python音乐led_数据_03


可以看到,处理电源和地引脚(VDD, VSS)外,就是DIN和DOUT,也就是数据输入和输出引脚。因此,我们只需要简单的将一个LED的DOUT引脚接到下一个LED的DIN引脚就可以将LED串接起来了。

ws2812 python ws2812 python音乐led_数据_04


那么,DIN和DOUT中跑的是什么信号呢?当然是颜色信号了,是每个全彩LED的颜色信号。学过绘画知识的人都应该知道,每一种颜色都可以分解成红,绿,蓝三种基色的按比例混合。光的颜色也是同理。我们这里使用1个字节(8bit)代表红绿蓝每种基色的值,这样用3个字节(24bit)就可以表示一种颜色了。如下图:

ws2812 python ws2812 python音乐led_数据_05


可知,G7-G0 表示绿色的值,数值范围:0 - 255

R7-R0 表示红色的值,数值范围:0 - 255

B7-B0 表示蓝色的值,数值范围:0 - 255我们看到数据线只有一根,这么多数据该如何发送?这里使用的是串行的发送方式,将一种颜色的24bit数据按照上图从左至右的顺序,逐bit发送,先发送G7,接下来发G6,G5…直到B0。这样就发送完一个LED的颜色数据。此时这个LED不再接收后面的数据,并将后面的所有数据都从DOUT输出给下一个LED。如此,依次可将所有LED的颜色数据传输完毕。

一根数据线是如何表达0,1信号的?也许,你会简单想到使用GPIO的方式直接输出0或1。但这样是不行的,直接输出0,1信号是无法完成同步的,特别是输出连续的0或1的时候,接收端是无法确认到底发送端发送了几个0或几个1。因此,WS2812B采用了成为NRZ的通讯方式(协议)。及每个bit数据都要求0,1反转一次,以高电平(1信号)的时长确定本bit到底是0还是1。同时,固定每bit数据的时间长度。这样接收端就可以辨认出每个bit数据了。波形如下:

ws2812 python ws2812 python音乐led_WS2812B_06


时间值:

ws2812 python ws2812 python音乐led_数据_07


我们可以看出,0码的高电平(1值)的时间宽度小于1码的。RET Code是复位信号,及数据线保持低电平(0值)超过50us以上后,所有LED将重新接收新的颜色值。我们也可以看到,每个bit的时间宽度TH+TL为1.25us。也就是通讯速率为800kbps。

每个bit位的时间宽度为1.25us这是一个非常小的时间值,如果使用GPIO的方式产生0码和1码在Python解释器中是根本不可能达到的,因为Python的执行效率很低。而实际中即便采用高效率的C语言编程也不能稳定的达到。那么,我们该如何产生这样的快的波形呢?主流方案有两种,一是使用PWM产生这样的波形,二是使用SPI的输出产生这样的波形。由于,主控芯片生成PWM波形使用的是16bit定时器,因此对于每bit需要转换为16bit的定时器数据,那么每个LED的24bit颜色值最终将转换为16 * 24 / 8 =48字节。这是庞大的数据量。如果使用SPI输出波形,使用一个4bit数据产生一个颜色比特,那么24bit颜色将转换为24 / 2 =12字节。数据量大大减少。因此,我们这里采用SPI输出颜色bit的方式。

接线:我这里选用WS2812B全彩LED环形板(16个LED)。其背后焊盘如图:

ws2812 python ws2812 python音乐led_数据_08


可以看出,VCC, GND, IN, OUT引脚。由于环形板不再连接后续LED,因此,OUT脚不用管。我们只接VCC,GND,IN这3个脚。其中VCC和GND是LED的供电端,5V供电。少量LED时可使用uPYB板供电。这个环形板有16颗LED,靠PC机的USB口勉强可供电。

uPYB板上,我们使用SPI1的MOSI(X8)输出数据,因此将X8连接到LED板的IN。

ws2812 python ws2812 python音乐led_WS2812B_09


连接好后,就可以编程序了。WS2812B的驱动已经包含在HexPyBoard板中的固件中。其他板子是否包含未知。好像也有包含的。程序如下:

#引入WS2812库
from ws2812 import WS2812

ring = WS2812(spi_bus=1, led_count=16);#使用SPI1, 16个LED

#LED颜色表,可自行更改颜色
data = [
    (24, 0, 0),
    (0, 24, 0),
    (0, 0, 24),
    (12, 12, 0),
    (0, 12, 12),
    (12, 0, 12),
    (24, 0, 0),
    (21, 3, 0),
    (18, 6, 0),
    (15, 9, 0),
    (12, 12, 0),
    (9, 15, 0),
    (6, 18, 0),
    (3, 21, 0),
    (0, 24, 0),
    (80, 28, 68),
]

ring.show(data);#按照颜色表显示

效果:

ws2812 python ws2812 python音乐led_ws2812 python_10