💬 前言
从广告灯箱上面的彩灯到增添风情的氛围灯带,究其本质不过是一串 LED 灯珠,常见的如 WS2812B 等 RGB 灯珠,常常被发烧友拿来捣鼓。本文也会以 WS2812B 为例来做个简单的介绍。
WS2812B 的通讯协议实现起来其实非常简单,有兴趣的可以自信查阅数据手册,但是真正运用的时候,若都写在项目代码里,还是略复杂了些。况且,市面上不同的 LED 灯带有很多种,想要让一份代码支持多种灯带,还是得请 FastLED 这个库出场。
💡 FastLED
这是一个有这十年多历史的库了,支持很多常见的 LED 灯带。他还提供了很多在调用灯带时非常方便的方法,诸如对 HSV 的支持,快速设置灯带为渐变彩虹色,方便的色彩校正,色温调整,伽马矫正等等,详细的内容可以参见 Wiki 以及自带的 Example。
接下来简单描述一下这个库的工作原理。
首先需要指定一些基本的信息,比如灯珠数量,数据引脚,芯片型号等等。
然后我们需要定义一个数组,充当“帧缓冲区”,用来存放要显示的东西,数据类型为CRGB
,这是由 FastLED 提供的一个数据类型,提供了不少有用的关于色彩的功能。
然后把前面的基本信息和缓冲区交给 FastLED,通过调用LEDS.addLeds
方法来初始化灯带。
loop
里,我们只需要修改数组,然后调用FastLED.show()
即可刷新灯带。如果你觉得这么做不优雅,或者你希望程序逮着空就刷新,很推荐使用FastLED.delay()
代替delay()
,在程序等待的间隙执行刷新。
对于 3-Wire 的灯珠,比如 WS2812B,由于通信协议的限制,必须保证在传输信号的时候连续(间隙不得超过50 μs
,否则会被判定为传输完毕,从而新来的数据不会给后继 LED),所以在时钟频率较低的处理器上 FastLED 会暂时禁用中断,从而导致潜在的串口数据丢失,舵机失灵等问题。即使在时钟频率较高的处理器上,如若中断耗时过长,也会导致显示出问题,比如“怎么就前 xxx 个灯珠亮了?”之类的问题。
为了解决这个问题,一个办法是去使用那些 4-Wire 乃至更多的灯带(IIC,SPI 等协议的),或者在你确保不会产生问题的情况下,手动保持中断启用/禁用。当然最好的办法,还是提前进行思考,可以参考官方文档的这部分。
🧑💻 程序设计
这里简单写几个小功能,以供参考。
#include <FastLED.h>
#define NUM_LEDS 64
#define DATA_PIN 16
#define LED_TYPE WS2812
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];
void setup()
{
LEDS.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setBrightness(64);
}
void loop()
{
for (int i = 0; i < 64; ++i)
{
leds[i % NUM_LEDS] = CRGB::Green;
FastLED.delay(200);
leds[i % NUM_LEDS].setRGB(0, 0, 0);
}
fill_solid(leds, NUM_LEDS, CHSV(325 / 360 * 255, 100 / 360 * 255, 100 / 360 * 255)); // Everything is 0-255 here
FastLED.delay(1000);
for (int i = 0; i < 64; ++i)
{
fadeToBlackBy(leds, NUM_LEDS, 1);
FastLED.delay(100);
}
fill_rainbow(leds, NUM_LEDS, 0, 256 / 64);
// 3rd argument for beginning hue, 4th for delta hue between previous and next
FastLED.delay(1000);
}
Comments NOTHING