ESP32用ヘルパーライブラリ その5 シリアルRGB LED

概要

前回は割り込みでした。今回はシリアル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を直接指定するのでもどちらでも可能です。

内部実装

EspEasyUtils/EspEasyLED.h at master · tanakamasayuki/EspEasyUtils
ESP32 Easy Utils. Contribute to tanakamasayuki/EspEasyUtils development by creating an account on GitHub.

上記になります。少し長いのでポイントだけ解説します。

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程度かかります。通常はこのような仕様で大丈夫だと思いますが、本当はタスク化したほうがきれいです。

でもこれぐらい単純な方が使いやすいことってありますよね?

コメント