《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


未完待續~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章