概要
前回は割り込みでした。今回はシリアルRGB LEDです。個人的にFastLEDは嫌いなので他の選択肢が欲しかった。。。あれは良いライブラリなのですがESP32以外のサポートの方が強いのでちょっと大きすぎるんですよね。
シリアルRGB LED
いわゆるNeoPixelと呼ばれるLEDです。NeoPixelはブランド名なので、実際にはいろいろな製品があります。数珠つなぎに接続可能で、8ビットのRGBで色の指定ができます。
構造的には各色が8ビットで3色あるので24ビット分のデータで1つのLEDを光らせることが可能です。それ以上のデータを受け取ったら後続に転送する処理がLED内部に入っており、240ビット分送信することで10個分のLEDが光るような処理が可能になっています。
ESP32標準関数
void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val);
上記の関数が新設されています。こちらは残念ながら1つのLEDにしか対応していません。これを複数個のLEDに対応させてみました。
過去上記で実験はしていたのですが、ちょっと面倒なのでEasyなライブラリにまとめなおしました。
EspEasyLED
#include "EspEasyLED.h"
EspEasyLED led(GPIO_NUM_27, 25, 40);
// gpio : 27
// led_num : 1-
// maxBrightness : 1(dark)-255(bright). If it is too bright, it will be damaged by heat.
void setup() {
Serial.begin(115200);
delay(500);
Serial.println("Task test");
}
void loop() {
// All RED
//led.showColor(EspEasyLED::RED);
led.showColor(255, 0, 0);
delay(1000);
// All GREEN
led.showColor(EspEasyLEDColor::GREEN);
delay(1000);
// All BLUE
led.showColor(EspEasyLEDColor::BLUE);
delay(1000);
// All WHITE
led.showColor(EspEasyLEDColor::WHITE);
delay(1000);
// fade out 100(MAX) to 0(MIN)
for (int i = 100; 0 <= i; i--) {
led.setBrightness(i);
led.show();
}
delay(1000);
// fade in 0(MIN) to 100(MAX)
for (int i = 0; i <= 100; i++) {
led.setBrightness(i);
led.show();
}
delay(1000);
// Num access
for (int i = 0; i < led.getLedNum(); i++) {
led.setColor(i, EspEasyLEDColor::BLACK);
led.show();
delay(50);
}
delay(1000);
}
上記がサンプルになります。
EspEasyLED led(GPIO_NUM_27, 25, 40);
// gpio : 27
// led_num : 1-
// maxBrightness : 1(dark)-255(bright). If it is too bright, it will be damaged by heat.
上記で接続しているGPIOと接続個数、そして明るさ上限を設定します。明るさ上限が重要なのですが、フルパワーで光らせると明るすぎるのと、排熱が追いつかないで壊れるボードがあります。ATOM Matrixなどが有名で、若干抑えた値にする必要があります。
個人的には上記の40ぐらいでも十分明るいと思っています。ただし、段階が減っていますので色の再現性は悪くなっています。
// Num access
for (int i = 0; i < led.getLedNum(); i++) {
led.setColor(i, EspEasyLEDColor::BLACK);
led.show();
delay(50);
}
通常はsetColor()関数を使って、全部のLEDに色を設定していきます。show()を呼び出すと色が反映されます。
// All RED
//led.showColor(EspEasyLED::RED);
led.showColor(255, 0, 0);
showColor()関数は全部のLEDに色をセットしてからshow()する関数も準備しています。色の指定はREDのような名前でも、RGBを直接指定するのでもどちらでも可能です。
内部実装
上記になります。少し長いのでポイントだけ解説します。
LED表示部分
void show() {
for (int i = 0; i < _ledNum; i++) {
neopixelWrite(_gpio,
_led[i].R * _brightness * _maxBrightness / 100 / 255,
_led[i].G * _brightness * _maxBrightness / 100 / 255,
_led[i].B * _brightness * _maxBrightness / 100 / 255);
delayMicroseconds(100);
}
delay(1);
};
なんとneopixelWrite()をそのまま呼び出しています。ポイントはdelayMicroseconds(100)でこれを入れることで、次の色も送信できました。50でも大丈夫だったのですが、なんとなく100にしています。本当はデータシートを確認して正しい値にしたほうが良いはずです。
最後のdelay(1)で確実にデータが連続しないリセット時間を確保しています。
各色は、指定数×明るさ(0-100)×最大明るさ(1-255)で送信する値を決めています。最大明るさが低いと全体的に小さい値になるので、色の段階が減ります。
色指定
namespace EspEasyLEDColor {
const EspEasyLED::color_t BLACK = { 0, 0, 0 };
const EspEasyLED::color_t NAVY = { 0, 0, 128 };
const EspEasyLED::color_t DARKGREEN = { 0, 128, 0 };
const EspEasyLED::color_t DARKCYAN = { 0, 128, 128 };
先頭だけですが、上記のような宣言になっています。通常は.cppでstatic const宣言をするのですが、今回クラスの.hファイルのみで.cppファイルがありません。そのため、namespaceで指定しています。色名を使わなければ、そのまま消しても大丈夫のはずです。
そしてこの色情報はLovyanGFXを参考にして同じものを入れています。
まとめ
このシリアルRGB LEDライブラリはブロック関数で25個のLEDを光らせるのに2ms程度かかります。通常はこのような仕様で大丈夫だと思いますが、本当はタスク化したほうがきれいです。
でもこれぐらい単純な方が使いやすいことってありますよね?
コメント