我的另一個項目中已經對WS2812點陣進行了應用,並可以顯示字符串和常用圖標:《項目》 之 ESP8266 心知天氣 + 時鐘 + WS2812點陣屏 + B站粉絲計數,這也非常感謝 我的舍友 幫助我移植驅動庫。
目錄
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
未完待續~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~