《Arduino》开发 之 深入理解 WS2812B 彩灯 (直接改变IO口电平点亮 + 用库点亮)

我的另一个项目中已经对WS2812点阵进行了应用,并可以显示字符串和常用图标:《项目》 之 ESP8266 心知天气 + 时钟 + WS2812点阵屏 + B站粉丝计数,这也非常感谢 我的舍友 帮助我移植驱动库。

目录

1.WS2812B灯珠简介

2.直接改变IO口电平来驱动WS2812灯珠

2.1.点亮一个灯

2.2.设置WS2812灯为任意颜色

2.3.点亮多个灯珠,并设置不同颜色

3.用Arduino的库去驱动(方便很多)

3.1.FastLED库

3.2.Adafruit_NeoPixel-master库


1.WS2812B灯珠简介

可以看到,WS2812灯珠支持级联,我们只需要一个引脚即可驱动 1024 个灯珠,这无疑给我们省了很多IO口,驱动方式也是异常的简单,只需要按照格式去改变IO口电平就可以了,这让任何一款单片机都可以使用这款灯珠;

接下来,让我带领大家从点亮一个灯开始吧~

2.直接改变IO口电平来驱动WS2812灯珠

本次使用的硬件ESP32 + 8*8 WS2812点阵

开发环境:Arduino IDE

2.1.点亮一个灯

我们看下 WS2812 要求的 0 和 1 是什么样的格式:

 用IO口电平改变去模拟 0码1码

//模拟的ns,不准确!!!
void delay_ns(float a)
{
  for(int j;j<a;j++)
    NOP();
}

//0码
void GPIO_0()
{
  digitalWrite(RGB_PIN,HIGH);
  delay_ns(300);
  digitalWrite(RGB_PIN,LOW);
  delayMicroseconds(1);
}
//1码
void GPIO_1()
{
  digitalWrite(RGB_PIN,HIGH);
  delayMicroseconds(1);
  digitalWrite(RGB_PIN,LOW);
  delay_ns(300);
}

 接下来,我们按照格式去改变IO口电平:

常用的 WS2812 灯珠有两种数据结构,一种为 RGB 顺序,一种为 GRB 顺序,我手中的便是 RGB 格式,接下来我就用RGB顺序来演示,如果你的是GRB格式,你只需要改变发送顺序即可,这并不难。

假如我们要让一个灯亮红色,即要发送11111111 00000000 00000000 ,前面的11111111 即对应了255亮度的红色,我们发送8个GPIO_1()和16个GPIO_0()即可:

颜色数据
颜色 二进制 16进制
红色 11111111 00000000 00000000 0xFF0000
绿色 00000000 11111111 00000000 0x00FF00
蓝色 00000000 00000000 11111111 0x0000FF
黑色 00000000 00000000 00000000 0x000000
白色 11111111 11111111 11111111 0xFFFFFF
for (int i = 0; i < 8; i++)
  GPIO_1();
for (int i = 0; i < 8; i++)
  GPIO_0();
for (int i = 0; i < 8; i++)
  GPIO_0();

 接下来,你便可以尝试点亮各种颜色:

#include <WiFi.h>

//定义WS2812B引脚
#define RGB_PIN 27

//模拟纳秒延时,不准确
void delay_ns(float a)
{
  for(int j;j<a;j++)
    NOP();
}
//0码
void GPIO_0()
{
  digitalWrite(RGB_PIN,HIGH);
  delay_ns(300);
  digitalWrite(RGB_PIN,LOW);
  delayMicroseconds(1);
}
//1码
void GPIO_1()
{
  digitalWrite(RGB_PIN,HIGH);
  delayMicroseconds(1);
  digitalWrite(RGB_PIN,LOW);
  delay_ns(300);
}
//红色
void RGB_RED()
{
  for (int i = 0; i < 8; i++)
    GPIO_1();
  for (int i = 0; i < 8; i++)
    GPIO_0();
  for (int i = 0; i < 8; i++)
    GPIO_0();
}
//绿色
void RGB_GREEN()
{
  for (int i = 0; i < 8; i++)
    GPIO_0();
  for (int i = 0; i < 8; i++)
    GPIO_1();
  for (int i = 0; i < 8; i++)
    GPIO_0();
}
//蓝色
void RGB_BLUE()
{
  for (int i = 0; i < 8; i++)
    GPIO_0();
  for (int i = 0; i < 8; i++)
    GPIO_0();
  for (int i = 0; i < 8; i++)
    GPIO_1();
}
//黑色,即熄灭
void RGB_BLACK()
{
  for (int i = 0; i < 8; i++)
    GPIO_0();
  for (int i = 0; i < 8; i++)
    GPIO_0();
  for (int i = 0; i < 8; i++)
    GPIO_0();
}

void setup(){
  pinMode(RGB_PIN,OUTPUT);
  digitalWrite(RGB_PIN,LOW);
}

void loop(){
  RGB_RED();//红
  delay(1000);
  RGB_GREEN();//绿色
  delay(1000);
  RGB_BLUE();//蓝色
  delay(1000);
  RGB_BLACK();//黑色,即熄灭
  delay(1000);
}

2.2.设置WS2812灯为任意颜色

我们可以写个函数,形参为你想要发送的颜色,例如:你想要的发送红色(0xFF0000),你只需要调用WS2812_Send_Date(0xFF0000)即可,是不是简单了很多。

//获取的某一位的值
#define getbit(x,y)   ((x) >> (y)&1)

void WS2812_Send_Date(int32_t date)
{
  for(int i= 1;i<25;i++)
  {
    if(getbit(date,24-i))
      GPIO_1();
    else
      GPIO_0();
  }
}

接下来点亮各种颜色试试吧:

#include <WiFi.h>
#include <math.h>

//定义WS2812B引脚
#define RGB_PIN 27

//指定的某一位数置1
#define setbit(x,y)  x|=(1<<y)

//指定的某一位数置0
#define clrbit(x,y)  x&=~(1<<y)

//指定的某一位数取反
#define reversebit(x,y)  x^=(1<<y)

//获取的某一位的值
#define getbit(x,y)   ((x) >> (y)&1)

#define RED   0xFF0000
#define GREEN 0x00FF00
#define BLUE  0x0000FF
#define BLACK 0x000000
#define WHITE 0xFFFFFF

void delay_ns(float a)
{
  for(int j;j<(a/2);j++)
    NOP();
}

void GPIO_0()
{
  digitalWrite(RGB_PIN,HIGH);
  delay_ns(300);
  digitalWrite(RGB_PIN,LOW);
  delayMicroseconds(1);
}
void GPIO_1()
{
  digitalWrite(RGB_PIN,HIGH);
  delayMicroseconds(1);
  digitalWrite(RGB_PIN,LOW);
  delay_ns(300);
}

void WS2812_Send_Date(int32_t date)
{
  for(int i= 1;i<25;i++)
  {
    if(getbit(date,24-i))
      GPIO_1();
    else
      GPIO_0();
    Serial.print(getbit(date,24-i));
  }
  Serial.println("");
}

void setup(){
  Serial.begin(115200);
  pinMode(RGB_PIN,OUTPUT);
  digitalWrite(RGB_PIN,LOW);
}

void loop(){
  WS2812_Send_Date(RED);
  delay(1000);
  WS2812_Send_Date(GREEN);
  delay(1000);
  WS2812_Send_Date(BLUE);
  delay(1000);
  WS2812_Send_Date(BLACK);
  delay(1000);
  WS2812_Send_Date(WHITE);
  delay(1000);
}

2.3.点亮多个灯珠,并设置不同颜色

按照数据格式,有几个灯珠,我们只需要发送几次数据就行,注意多个灯珠数据发送不可以停顿,要一次性发送出去,不然灯珠会认为你发了多个帧的数据。

#include <WiFi.h>
#include <math.h>

//定义WS2812B引脚
#define RGB_PIN 27

//指定的某一位数置1
#define setbit(x,y)  x|=(1<<y)

//指定的某一位数置0
#define clrbit(x,y)  x&=~(1<<y)

//指定的某一位数取反
#define reversebit(x,y)  x^=(1<<y)

//获取的某一位的值
#define getbit(x,y)   ((x) >> (y)&1)

//定义一些常用的颜色
#define RED   0xFF0000
#define GREEN 0x00FF00
#define BLUE  0x0000FF
#define BLACK 0x000000
#define WHITE 0xFFFFFF

//WS2812B灯数目
#define RGB_NUM 64
//如果是-GRB-格式
//#define R 1
//#define G 0
//#define B 2
//#define BRIGHT 4
//如果是-RGB-格式
#define R 0         //红色
#define G 1         //绿色
#define B 2         //蓝色
#define BRIGHT 4    //亮度
uint8_t WS2812[RGB_NUM][4];//灯状态数组

//模拟的ns,并不准确!!!
void delay_ns(float a)
{
  for(int j;j<a;j++)
    NOP();
}

//将所有灯的状态发送出去
void WS2812_send_date()
{
  uint8_t i,j,k,a;
  for(k=0;k<RGB_NUM;k++)
  {
    for(j=0;j<3;j++)
    {
      switch(j)
      {
        case R:a=WS2812[k][R];break;
        case G:a=WS2812[k][G];break;
        case B:a=WS2812[k][B];break;
      }
      for(i=1;i<9;i++)
      {
        if(getbit(a,8-i))//发送1码
        {
          digitalWrite(RGB_PIN,HIGH);
          delayMicroseconds(1);
          digitalWrite(RGB_PIN,LOW);
          delay_ns(300);
        }
        else//发送0码
        {
          digitalWrite(RGB_PIN,HIGH);
          delay_ns(300);
          digitalWrite(RGB_PIN,LOW);
          delayMicroseconds(1);
        }
      }
    }
  }
  delayMicroseconds(600);//每帧数据相隔400us
}

//设置灯RGB颜色,格式为0~0xFFFFFF
void WS2812_colour_set(int32_t colour,uint8_t num)
{
  int32_t colour_buff = colour;
  WS2812[num][R] = (colour>>16)&0xFF;colour = colour_buff;
  WS2812[num][G] = (colour>>8)&0xFF;colour = colour_buff;
  WS2812[num][B] = colour&0xFF;
}

//设置灯R颜色,格式为0~255
void WS2812_RED_set(int8_t r_colour,int8_t num)
{
  WS2812[num][R] = r_colour;
}

//设置灯G颜色,格式为0~255
void WS2812_GREEN_set(int8_t g_colour,int8_t num)
{
  WS2812[num][G] = g_colour;
}

//设置灯B颜色,格式为0~255
void WS2812_BLUE_set(int8_t b_colour,int8_t num)
{
  WS2812[num][B] = b_colour;
}

void setup(){
  Serial.begin(115200);
  pinMode(RGB_PIN,OUTPUT);
  digitalWrite(RGB_PIN,LOW);
}

void loop(){
  //红色测试
  for(int i = 0;i<RGB_NUM;i++)
    WS2812_colour_set(RED,i);
  WS2812_send_date();
  delay(1000);

  //绿色测试
  for(int i = 0;i<RGB_NUM;i++)
    WS2812_colour_set(GREEN,i);
  WS2812_send_date();
  delay(1000);

  //蓝色测试
  for(int i = 0;i<RGB_NUM;i++)
    WS2812_colour_set(BLUE,i);
  WS2812_send_date();
  delay(1000);

  //红色渐变
  for(int i = 0;i<RGB_NUM;i++)
    WS2812_colour_set(0x000000,i);
  for(int j = 0;j<255;j++)
  {
    for(int i = 0;i<RGB_NUM;i++)
    {
      WS2812_RED_set((j*i)/RGB_NUM,i);
    }
    WS2812_send_date();
    delay(100);
  }

  //绿色渐变
  for(int i = 0;i<RGB_NUM;i++)
    WS2812_colour_set(0x000000,i);
  for(int k = 0;k<255;k++)
  {
    for(int i = 0;i<RGB_NUM;i++)
    {
      WS2812_GREEN_set((k*i)/RGB_NUM,i);
    }
    WS2812_send_date();
    delay(100);
  }

  //蓝色渐变
  for(int i = 0;i<RGB_NUM;i++)
    WS2812_colour_set(0x000000,i);
  for(int h = 0;h<255;h++)
  {
    for(int i = 0;i<RGB_NUM;i++)
    {
      WS2812_BLUE_set((h*i)/RGB_NUM,i);
    }
    WS2812_send_date();
    delay(100);
  }
  delay(200);

}

3.用Arduino的库去驱动(方便很多)

3.1.FastLED库

FsatLED 库下载地址https://github.com/FastLED/FastLED

3.2.Adafruit_NeoPixel-master库

Adafruit_NeoPixel 库下载地址https://github.com/adafruit/Adafruit_NeoPixel


未完待续~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

猜你喜欢

转载自blog.csdn.net/qq_41868901/article/details/105869263