skip to Main Content
+86-181-2377-5520 sales@nvled.com Inquiry 中文 | English

ARDUINO开发之深入理解 WS2812B 彩灯 (直接程序点亮 + FASTLED库点亮)

标签: Arduino 开发教程  ESP32 学习笔记
版权声明:本文为qq_41868901原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

目录

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 000000000xFF0000
绿色00000000 11111111 000000000x00FF00
蓝色00000000 00000000 111111110x0000FF
黑色00000000 00000000 000000000x000000
白色11111111 11111111 111111110xFFFFFF
颜色数据
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

#define RGB_NUM 64//灯珠数目
//如果是GRB格式
//#define R 1
//#define G 0
//#define B 2
//如果是RGB格式
#define R 0
#define G 1
#define B 2
uint8_t WS2812[RGB_NUM][4];

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()
{
	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))
          GPIO_1();
        else
          GPIO_0();	
			}
		}
	}
}

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;
}

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

void loop(){
  //Serial.print("红色:");
  for(int i = 0;i<RGB_NUM;i++)
    WS2812_colour_set(RED,i);
  WS2812_send_date();
  //Serial.printf("R = %d ; G = %d ; B = %d\n",WS2812[0][R],WS2812[0][G],WS2812[0][B]);
  delay(1000);
  //Serial.print("绿色:");
  for(int i = 0;i<RGB_NUM;i++)
    WS2812_colour_set(GREEN,i);
  WS2812_send_date();
  //Serial.printf("R = %d ; G = %d ; B = %d\n",WS2812[0][R],WS2812[0][G],WS2812[0][B]);
  delay(1000);
  //Serial.print("蓝色:");
  for(int i = 0;i<RGB_NUM;i++)
    WS2812_colour_set(BLUE,i);
  WS2812_send_date();
  //Serial.printf("R = %d ; G = %d ; B = %d\n",WS2812[0][R],WS2812[0][G],WS2812[0][B]);
  delay(1000);
}

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

3.1.FASTLED库
3.2. ADAFRUIT_NEOPIXEL-MASTER库

转载自: 灰信网

Back To Top