什么是RGB灯WS2812B?
之前用stm32点亮过这种灯感觉很好玩今天就试着用ESP32来点亮它
网上介绍这种灯的资料有很多,下面这个博客可以去了解一下。
https://blog.csdn.net/tangxing1212/article/details/42964417
其实如果要用stm32这些单片机直接用800KHZ的方波去驱动它还是需要研究一下的这个等我自己做的小彩灯回来了我再来写。今天来记录一下如何用ESP32来快速点灯。
ardunino开发环境搭建
这个如果已经完成那就成功一半了,如果没有搭建完成可以参考我上一篇博客(写的也不好,如果有更好的办法建议绕过)
其实点亮RGB彩灯有很多种方式,我知道的方式有直接IO口模拟产生需要的波形但是这个我没有实现过不清楚好像对单片机的速度要求挺高的。
第二种就是用SPI总线去驱动,这个以后可以研究一下。
第三种就是比较靠谱和成熟的方式网上也有很多人做个,写的有博客用stm32结合DMA来做的这个效果还不错,我后面有机会也会来记录一下自己的学习笔记。
当然我们今天用的方式以上的方式我们都不采用,因为既然我们使用了arduino那么它丰富的库函我们要学会使用,见天就研究一下如何利用Adafruit_NeoPixel.h这个库来实现小彩灯的控制。
安装库
这个作者应该是一家公司吧,我看有好多库都是他们的署名,这个先不讨论,由于我已经安装过了就显示变暗了。
分析源码
// Simple demonstration on using an input device to trigger changes on your
// NeoPixels. Wire a momentary push button to connect from ground to a
// digital IO pin. When the button is pressed it will change to a new pixel
// animation. Initial state has all pixels off -- press the button once to
// start the first animation. As written, the button does not interrupt an
// animation in-progress, it works only when idle.
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif
// Digital IO pin connected to the button. This will be driven with a
// pull-up resistor so the switch pulls the pin to ground momentarily.
// On a high -> low transition the button press logic will execute.
#define BUTTON_PIN 4
#define PIXEL_PIN 5 // Digital IO pin connected to the NeoPixels.
#define PIXEL_COUNT 9 // Number of NeoPixels
// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);
// Argument 1 = Number of pixels in NeoPixel strip
// Argument 2 = Arduino pin number (most are valid)
// Argument 3 = Pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
// NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products)
boolean oldState = HIGH;
int mode = 0; // Currently-active animation mode, 0-9
void setup()
{
pinMode(BUTTON_PIN, INPUT_PULLUP);
strip.begin(); // Initialize NeoPixel strip object (REQUIRED)
strip.show(); // Initialize all pixels to 'off'
Serial.begin(115200);
}
void loop()
{
boolean newState = digitalRead(BUTTON_PIN);// Get current button state.
if((newState == LOW) && (oldState == HIGH)) // Check if state changed from high to low (button press).
{
delay(20); // Short delay to debounce button.
newState = digitalRead(BUTTON_PIN);// Check if button is still low after debounce.
if(newState == LOW) // Yes, still low
{
mode++; Serial.println(mode);
if(mode >= 9) mode = 0; // Advance to next mode, wrap around after #8
switch(mode) // Start the new animation...
{
case 0:
colorWipe(strip.Color( 0, 0, 0), 200); // Black/off
break;
case 1:
colorWipe(strip.Color(255, 0, 0), 200); // Red
break;
case 2:
colorWipe(strip.Color( 0, 255, 0), 200); // Green
break;
case 3:
colorWipe(strip.Color( 0, 0, 255), 200); // Blue
break;
case 4:
theaterChase(strip.Color(255, 0, 255), 200); // Magenta
break;
case 5:
theaterChase(strip.Color(255, 255, 0), 200); // Yellow1
break;
case 6:
theaterChase(strip.Color(0, 255, 255), 200); // Chocolate
break;
case 7:
rainbow(10);
break;
case 8:
theaterChaseRainbow(200);
break;
}
}
}
oldState = newState; // Set the last-read button state to the old state.
}
// Fill strip pixels one after another with a color. Strip is NOT cleared
// first; anything there will be covered pixel by pixel. Pass in color
// (as a single 'packed' 32-bit value, which you can get by calling
// strip.Color(red, green, blue) as shown in the loop() function above),
// and a delay time (in milliseconds) between pixels.
void colorWipe(uint32_t color, int wait)
{
for(int i=0; i<strip.numPixels(); i++) // For each pixel in strip...
{
strip.setPixelColor(i, color); // Set pixel's color (in RAM)
strip.show(); // Update strip to match
delay(wait); // Pause for a moment
}
}
// Theater-marquee-style chasing lights. Pass in a color (32-bit value,
// a la strip.Color(r,g,b) as mentioned above), and a delay time (in ms)
// between frames.
void theaterChase(uint32_t color, int wait)
{
for(int a=0; a<10; a++)
{ // Repeat 10 times...
for(int b=0; b<3; b++)
{ // 'b' counts from 0 to 2...
strip.clear(); // Set all pixels in RAM to 0 (off)
// 'c' counts up from 'b' to end of strip in steps of 3...
for(int c=b; c<strip.numPixels(); c += 3)
{
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
}
}
}
// Rainbow cycle along whole strip. Pass delay time (in ms) between frames.
void rainbow(int wait)
{
// Hue of first pixel runs 3 complete loops through the color wheel.
// Color wheel has a range of 65536 but it's OK if we roll over, so
// just count from 0 to 3*65536. Adding 256 to firstPixelHue each time
// means we'll make 3*65536/256 = 768 passes through this outer loop:
for(long firstPixelHue = 0; firstPixelHue < 3*65536; firstPixelHue += 256)
{
for(int i=0; i<strip.numPixels(); i++)
{ // For each pixel in strip...
// Offset pixel hue by an amount to make one full revolution of the
// color wheel (range of 65536) along the length of the strip
// (strip.numPixels() steps):
int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());
// strip.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or
// optionally add saturation and value (brightness) (each 0 to 255).
// Here we're using just the single-argument hue variant. The result
// is passed through strip.gamma32() to provide 'truer' colors
// before assigning to each pixel:
strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
}
}
// Rainbow-enhanced theater marquee. Pass delay time (in ms) between frames.
void theaterChaseRainbow(int wait)
{
int firstPixelHue = 0; // First pixel starts at red (hue 0)
for(int a=0; a<30; a++) // Repeat 30 times...
{
for(int b=0; b<3; b++) // 'b' counts from 0 to 2...
{
strip.clear(); // Set all pixels in RAM to 0 (off)
for(int c=b; c<strip.numPixels(); c += 3) // 'c' counts up from 'b' to end of strip in increments of 3...
{
// hue of pixel 'c' is offset by an amount to make one full
// revolution of the color wheel (range 65536) along the length
// of the strip (strip.numPixels() steps):
int hue = firstPixelHue + c * 65536L / strip.numPixels();
uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames
}
}
}
我在例子里面做了一些简单的修改,感觉这个循环按键下降沿触发处理的比较好,我之前自己写的代码好像直接就是if延时消抖这些确实做了会好很多。
这里面掩盖了填充颜色函数的细节,其实这个我们不需要关心(当然这样确实很不爽,看不见底层的实现确实有点不适应)
现象其实就是按键按下会切换一种状态,状态可以来回切换。
例程里有两个函数的实现我还没有研究懂,但是现象感觉很炫酷的。等我把这个研究懂了我再来记录。
老是找不到对应的引脚我这里贴个网上抄的图。
这里有个修改的效果视频
https://www.bilibili.com/video/BV1yy4y1m7LX
圣诞节不能光吃苹果呀,用手里的ESP32点亮WS2812B灯条(不得不说arduino有库真香)