WS2812全彩LED简介

所谓基于WS2812B的LED灯珠,就是将一个控制芯片封装进全彩LED灯珠中,配合单独的通信协议可以实现对单个灯的全彩控制

WS2812 全彩LED灯珠封装实物图

如何区分ESP8266EX的引脚 esp826612f引脚图详细解释_引脚

WS2812 全彩LED灯珠封装尺寸及引脚图

如何区分ESP8266EX的引脚 esp826612f引脚图详细解释_数据_02

1. 电源和地引脚(VDD, VSS)

2. DIN 信号输入引脚

3. DOUT 级联信号输出引脚

故此只需要简单的将一个 LED 的 DOUT 引脚接到下一个LED的DIN引脚就可以将LED串接起来了。

WS2812 全彩LED灯珠级联(串联)电路示意图

如何区分ESP8266EX的引脚 esp826612f引脚图详细解释_单片机_03


如何区分ESP8266EX的引脚 esp826612f引脚图详细解释_数据_04

前提知识-三基色

三基色是指通过其他颜色的混合无法得到的“基本色”由于人的肉眼有感知RGB三种不同颜色的锥体细胞,因此色彩空间通常可以由RGB三种基本色来表达。

一般指光的三基色R(Red)、G(Green)、B(Blue)。(颜料的红、绿、蓝称为三基色,其实真正科学的讲法三原色应该是品红(M)、黄(Y)、青(C)。)

如何区分ESP8266EX的引脚 esp826612f引脚图详细解释_数据_05

WS2812 全彩LED灯 控制协议
  1. 使用1个字节(8bit)代表红绿蓝每种基色的值,用3个字节(24bit)就可以表示一种颜色了
  2. G7-G0 表示绿色的值,数值范围:0 - 255
  3. R7-R0 表示红色的值,数值范围:0 - 255
  4. B7-B0 表示蓝色的值,数值范围:0 - 255
  5. 如下图:
一根线,怎么控制串联的所有灯
  1. 将一种颜色的24bit数据按照上图从左至右的顺序,逐bit发送,先发送G7,接下来发G6,G5…直到B0。这样就发送完一个LED的颜色数据。此时这个LED不再接收后面的数据,并将后面的所有数据都从DOUT输出给下一个LED。如此,依次可将所有LED的颜色数据传输完毕。
  2. 一根数据线是如何表达0,1信号的?使用GPIO的方式直接输出0或1? 这样是不行的,直接输出0,1信号是无法完成同步的,特别是输出连续的0或1的时候,接收端是无法确认到底发送端发送了几个0或几个1。因此,WS2812B采用了成为NRZ的通讯方式(协议)。及每个bit数据都要求0,1反转一次,以高电平(1信号)的时长确定本bit到底是0还是1。同时,固定每bit数据的时间长度。这样接收端就可以辨认出每个bit数据了。波形如下:
基于Micropython WS2812 全彩LED灯 驱动库及电灯程序
一 基于内置的 neopixel 库
import neopixel

库文档连接: https://doc.bpi-steam.com/zh_CN/stable/mPython/docs/library/micropython/neopixel.html

基于内置的 neopixel 库 的示例代码

引脚连接说明

开发板接口

WS2812 引脚

GND

VSS

3V3

VCC

GPIO13

DIN

import neopixel                                                                                                                                                          
from machine import Pin 
from utime import sleep_ms

GBIO_IN = Pin(13)   # 控制信号输入引脚
LED_NUM = 64        # LED灯的数量


#class NeoPixel(pin, n, bpp=3, timing=0)
#    pin :输出引脚,可使用引脚见下文
#    n :LED灯的个数
#    bpp:
#        3:默认为3元组RGB
#        4:对于具有3种以上颜色的LED,例如RGBW像素或RGBY像素,采用4元组RGBY或RGBY像素
#    timing:默认等于0,为400KHz速率;等于1,为800KHz速率
#



# Setup the Neopixel strip on pin0 with a length of 8 pixels
LED = neopixel.NeoPixel(pin=GBIO_IN, n=LED_NUM, pp=3, timing=0) #创建控制对象
LED.fill((255, 0, 0)) #GRB填充数据(全部灯填充相同数据)
LED.write()           #写入数据
sleep_ms(500)
LED[index] = (255, 255, 255) # 设置第一个index 灯为白色
LED.write()           #写入数据
一 基于上述通信协议编写的WS2812 库
import gc
from machine import SPI

#---------------------------------------------
# WS2812驱动,调试已可以使用
#
#
#---------------------------------------------

class   WS2812:
    """
    Driver for WS2812 RGB LEDs. May be used for controlling single LED or chain
    of LEDs.

    Example of use:
        chain = WS2812(spi_bus=1, led_count=4)
        data = [
            (255, 0, 0),    # red
            (0, 255, 0),    # green
            (0, 0, 255),    # blue
            (85, 85, 85),   # white
        ]
        chain.show(data)
    Version: 1.0
    """
    buf_bytes = (0x11, 0x13, 0x31, 0x33)

    def __init__(self, spi_bus=1, led_count=1, intensity=1):
        """
        Params:
        * spi_bus = SPI bus ID (1 or 2)
        * led_count = count of LEDs
        * intensity = light intensity (float up to 1)
        """
        self.led_count = led_count  #灯珠数量
        self.intensity = intensity  #颜色强度

        # prepare SPI data buffer (4 bytes  for each color)
        self.buf_length = self.led_count * 3 * 4 #3*4 表示三种颜色,每个颜色值占用4个字节 0~255, 所以每一次发送的数据大小是 灯数量*12个字节
        self.buf = bytearray(self.buf_length)

        # SPI init
        #self.spi = SPI(spi_bus, SPI.MASTER, baudrate=3200000, polarity=0, phase=1)
        self.spi = SPI(spi_bus, baudrate=3200000, polarity=0, phase=1)
        # turn LEDs off
        self.show([])

    def show(self, data):
        """
        Show RGB data on LEDs. Expected data   = [(R, G, B), ...] where R, G and B
        are intensities of colors in range   from 0 to 255. One RGB tuple for each
        LED. Count of tuples may be less than   count of connected LEDs.

        功能翻译:
                * 在LED上显示RGB数据。预期数据=[(R,G,B),…],其中R,G和B是范围从0到255的颜色强度。每个RGB元组带路
                * 元组的计数可能小于连接的LED的计数
        """
        self.fill_buf(data)
        self.send_buf()


    def send_buf(self):
        """
        Send buffer over SPI.

        功能翻译:
                    * 通过SPI发送缓冲区。
        """
        #self.spi.send(self.buf)
        self.spi.write(self.buf)
        gc.collect()


    def update_buf(self, data, start=0):
        """
        Fill a part of the buffer with RGB   data.
        Order of colors in buffer is changed   from RGB to GRB because WS2812 LED
        has GRB order of colors. Each color   is represented by 4 bytes in buffer
        (1 byte for each 2 bits).
        Returns the index of the first unfilled   LED
        Note: If you find this function ugly,   it's because speed optimisations
        beated purity of code.

        功能翻译:
                    *  用RGB数据填充缓冲区的一部分
                    * 由于WS2812 LED,缓冲区中的颜色顺序从RGB更改为GRB 具有GRB颜色顺序。每个颜色由缓冲区中的4个字节表示(每2位1字节)
                    * 返回第一个未填充LED的索引
                * 注意:如果你觉得这个函数很难看,那是因为速度优化击败了代码的纯洁性
        """
        buf = self.buf
        buf_bytes = self.buf_bytes
        intensity = self.intensity
        mask = 0x03
        index = start * 12
        for red, green, blue in data:
            red = int(red * intensity)
            green = int(green * intensity)
            blue = int(blue * intensity)
            buf[index] = buf_bytes[green   >> 6 & mask]
            buf[index+1] = buf_bytes[green   >> 4 & mask]
            buf[index+2] = buf_bytes[green   >> 2 & mask]
            buf[index+3] = buf_bytes[green   & mask]

            buf[index+4] = buf_bytes[red   >> 6 & mask]
            buf[index+5] = buf_bytes[red   >> 4 & mask]
            buf[index+6] = buf_bytes[red   >> 2 & mask]
            buf[index+7] = buf_bytes[red   & mask]

            buf[index+8] = buf_bytes[blue   >> 6 & mask]
            buf[index+9] = buf_bytes[blue   >> 4 & mask]
            buf[index+10] = buf_bytes[blue   >> 2 & mask]
            buf[index+11] = buf_bytes[blue   & mask]
            index += 12
        return index // 12

    def fill_buf(self, data):
        """
        Fill buffer with RGB data.
        All LEDs after the data are turned off.

        功能翻译:
                * 用RGB数据填充缓冲区
                * 数据后的所有LED均关闭
        """
        end = self.update_buf(data)
        # turn off the rest of the LEDs
        # 关闭其余的LED
        buf = self.buf
        off = self.buf_bytes[0]
        for index in range(end * 12, self.buf_length):
            buf[index] = off
            index += 1

使用例子

import utime                                                                                                                                                             
import math
from ws2812 import WS2812


#---------------------------------------------
#  Params:
#  * spi_bus = SPI bus ID (1 or 2)
#  * led_count = count of LEDs
#  * intensity = light intensity (float   up to 1)
#---------------------------------------------

ring = WS2812(spi_bus=1, led_count=64, intensity=0.1)

led_count = 64

data = [(0, 100, 0) for i in range(led_count)]
ring.show(data)
总结,推荐使用内置的 neopixel 库 操作简单