M5StickC(ESP32)による「ELEGOO Arduino用UNO R3スターターキット」を利用したArduino入門 その3 RGB LED

現時点の情報です。最新情報はM5StickC非公式日本語リファレンスを確認してみてください。

概要

前回はLEDと抵抗を説明しました。今回は「Lesson 4 RGB LED」を説明したいと思います。

RGB LEDとは?

一つのLEDの中に、色の三原色である赤、緑、青が入っています。この3色を同時に点灯すると白になります。各色の光り方を調整することで、いろいろな色で光らせることができます。

秋月さんの商品だと上記みたいなものになります。5mmは普通のLEDとおなじで大きさですね。最後にカソードコモンとあります。

また、商品ページにはアノードコモンタイプはこちらとのリンクもあります。

見た目はほとんど変わりません。

カソードとアノードとは?

一般的なLED

まずは、前回使った一般的なLEDのデータシートを見てみます。

足の長い方がプラスで、短い方がマイナスに接続すると前回説明しました。データシートでは、プラス側の足がアノード(Anode)、マイナス側の足がカソード(Cathode)と表記されています。

半導体系はアノードと、カソードと呼ぶことが多いので余裕があれば覚えましょう。わからなくなったらデータシートで確認してください。

カソードコモンのRGB LED

次にカソードコモンタイプのRGB LEDのデータシートを見てみます。

RGB LEDは中に赤(Red)、緑(Green)、青(Blue)の3色のLEDが内蔵されているので、各色分+マイナス分の4本足があります。

このRGB LEDは左から3本目がカソードコモン(Common Cathode)となっており、上から見た図では右側の丸が削られています。

回路図を見ると、3色の足からカソードコモンに向かって三角形が描かれています。三角形の向きが電気の流れる向きになります。

LEDはアノードがプラス側で、カソードがマイナス側になっているので、図の通りに流れます。

さて、カソードコモンのコモンは共通のという意味でのコモンになります。3色分のアノードがありますが、カソードは共通の一本しかないので、カソードコモンと表現されます。

アノードコモンのRGB LED

アノードコモンのデータシートの図です。先程とはLEDの三角形の向きが逆になっています。

3番はアノードコモン(Common Anode)となっていますので、プラス側が共通で、3色分のカソードが独立しています。

使い分け

カソードコモンとアノードコモンは状況によって使い分けます。マイコンのピンをHIGHにして点灯させる場合にはカソードコモンになり、外部電源に接続してマイコンのピンをLOWにすることで点灯させる場合にはアノードコモンになります。

少量と使う場合にはどちらでも構いませんが、安定した外部電源がある場合にはアノードコモンを利用したほうがよいと思います。マイコンしか電源がない場合にはカソードコモンの方がシンプルです。

M5StickCのピン設定

GPIO出力
26
36×(入力専用)
0
32(Grove端子)
33(Grove端子)

RGB LEDを接続したいのですが、どのピンに接続するのかを決めたいと思います。M5StickCは自由に使えるピンが上記の5個しかありません。そしてGPIO34以上は入力専用のため、GPIO36を出力として接続することができません。

そして、GPIO32と33はGrove端子と呼ばれる特殊な端子になります。この端子はキットの中に入っているジャンパーワイヤだと接続することができないのです。

Groveケーブルを持っている場合には、ジャンパーワイヤで接続できるのですが持っていない人は接続したつもりになって試してみてください。

購入する場合には、上記などの中から、ケーブル付きのものを1つ購入しておくことをおすすめします。おすすめは「M5Stack用赤外線送受信ユニット」か「M5Stack用ミニプロトボードユニット」あたりですが、気になったもので構わないと思います。

上記ページにM5StickCのピンについての情報がまとまっています。

接続例

RGB LEDはデータシートと同じ向きになっています。左から緑アノード、青アノード、コモンカソード(GND)、赤アノードになっています。

M5StickCRGB LED
26(220Ωの抵抗を経由して)緑アノード
0(220Ωの抵抗を経由して)青アノード
GNDコモンカソード(一番長い足)
33(220Ωの抵抗を経由して)赤アノード

上記の対応になっています。GND以外には220Ωの抵抗が入っています。

ちょっとわかりにくい写真なのですが、上記のような接続になりました。Groveケーブルにジャンパーワイヤを指して接続しています。

ブレッドボードは上記のような配線です。

RGB LEDの部分的な回路図だと、上記のようになります。この接続で大切なことは、3色の独立した足に抵抗を接続することになります。

コモン側に抵抗をいれれば、個別に入れる必要がないのですが、その分1つの抵抗に3本分の電流が流れてしまいます。

再度、データシートをみてみます。実際にキットに入っているRGB LEDではないので、参考程度なのですが、DC Forward Currentが赤(Red)が50mA、青(Blue)と緑(Green)が30mAとなっています。この値は最大値なので、合計50+30+30で110mA(0.11A)まで流れることになります。

電源がESP32の場合3.3Vなので、電力を計算すると3.3V×0.11Aで0.363Wになります。いま使っている抵抗の定格が1/4W(0.25W)のため、最大値を流すと定格を超えてしまいます。

また、先程の下にある表が上記です。DC Forward Voltageが順方向電圧降下です。電流によって低下する電圧が変わりますので、Conditionの欄に標準的な電流が書いてあり、20mAとなっています。各色の順方向電圧降下を確認すると、赤はTypが2.1V、青と緑は3.1Vとなっています。

上記をつかって、20mAを流す場合の抵抗値を計算すると、赤が60Ω、青と緑が10Ωとなりました。つまり、色によって抵抗値を変える必要があることになります。そのため、コモン側ではなく独立した足に個別に抵抗を接続するほうが正しいことになります。

現在すべて220Ωを使っているので、20mA以下の電流しか流れていないことになります。推奨値より暗くなっていますが、暗い分には問題ありません。また、本来は赤とそれ以外で抵抗値を変える必要があります。同じ抵抗値を使っているので、赤のみ電流が多く流れています。

ただし、上記のLuminous Intensityの欄を見てもらうと、明るさの単位がミリカンデラで書いてあります。20mAのときに、赤が2000mcd、青が2500mcd、緑が7500mcdと圧倒的に緑が明るいです。

そのため、すべて同じ抵抗値の場合には、青のみ暗く見えると思います。

光らせてみる

// LEDが接続されているPINを指定する
int led_g = 26;
int led_b = 0;
int led_r = 33;

// リセットか電源を入れると一度だけ実行される初期化処理の関数です
void setup() {
  // LEDをデジタル出力モードに設定する
  pinMode(led_g, OUTPUT);
  pinMode(led_b, OUTPUT);
  pinMode(led_r, OUTPUT);

  // LEDをすべてOFFにします(LOWにすると消灯します)
  digitalWrite(led_g, LOW);     
  digitalWrite(led_b, LOW);
  digitalWrite(led_r, LOW);
}

// 常に繰り返し実行される処理の関数です
void loop() {
  digitalWrite(led_g, HIGH); // 緑LEDをONにします(HIGHにすると点灯します)
  delay(1000);               // 1000ミリ秒(=1秒)待機します
  digitalWrite(led_g, LOW);  // 緑LEDをOFFにします(LOWにすると消灯します)

  digitalWrite(led_b, HIGH); // 青LEDをONにします(HIGHにすると点灯します)
  delay(1000);               // 1000ミリ秒(=1秒)待機します
  digitalWrite(led_b, LOW);  // 青LEDをOFFにします(LOWにすると消灯します)

  digitalWrite(led_r, HIGH); // 赤LEDをONにします(HIGHにすると点灯します)
  delay(1000);               // 1000ミリ秒(=1秒)待機します
  digitalWrite(led_r, LOW);  // 赤LEDをOFFにします(LOWにすると消灯します)

  digitalWrite(led_g, HIGH); // 緑LEDをONにします(HIGHにすると点灯します)
  digitalWrite(led_b, HIGH); // 青LEDをONにします(HIGHにすると点灯します)
  digitalWrite(led_r, HIGH); // 赤LEDをONにします(HIGHにすると点灯します)
  delay(1000);               // 1000ミリ秒(=1秒)待機します
  digitalWrite(led_g, LOW);  // 緑LEDをOFFにします(LOWにすると消灯します)
  digitalWrite(led_b, LOW);  // 青LEDをOFFにします(LOWにすると消灯します)
  digitalWrite(led_r, LOW);  // 赤LEDをOFFにします(LOWにすると消灯します)
}

すべてのピンをOUTPUTモードに変更し、最初にすべて消灯させます。GPIO0は明示的にLOWにしない限り、HIGHになっている特殊なピンなので注意しましょう。

緑、青、赤、白と1秒ごとに色が変わりましたでしょうか? RGB LEDをよく見てみると光っている場所が色によって違っているのがわかります。これは3色のLEDが1つにまとまっているので、実際には光っている場所がちょっとだけ違っているのです。

明るさの調整をする

3色のLEDを使って、光らせることができました。任意の色にしたい場合には、明るさを調整する必要があります。

抵抗値を変えることで流れる電流がかわり、明るさを制御することができます。しかしながらプログラムからの制御ではないので、リアルタイムで色を変更することができません。

アナログ出力(DAC)

// LEDが接続されているPINを指定する
int led_g = 26;
int led_b = 0;
int led_r = 33;

// リセットか電源を入れると一度だけ実行される初期化処理の関数です
void setup() {
  // LEDをデジタル出力モードに設定する
  pinMode(led_g, OUTPUT);
  pinMode(led_b, OUTPUT);
  pinMode(led_r, OUTPUT);

  // LEDをすべてOFFにします(LOWにすると消灯します)
  digitalWrite(led_g, LOW);
  digitalWrite(led_b, LOW);
  digitalWrite(led_r, LOW);
}

// 常に繰り返し実行される処理の関数です
void loop() {
  for (int i = 0; i < 256; i++) {
    dacWrite(led_g, i);
    delay(10);
  }
}

初期化部分は共通で、loop()関数のみ変更しています。

dacWrite()関数を使うと、0(0V)から255(3.3V)までの間で、任意の電圧を出力することができます。

上記がオシロスコープで別の出力を計測したものですが、0、128、255を繰り返し変更している場合の出力になります。

サンプルスケッチでは0から255までカウントアップしていますので、緑が消えている状態から徐々に明るくなっているのがわかると思います。

ただし、ESP32ではアナログ出力はGPIO25と26の2つのピンでしか利用できません。Arduino UNOはもっとたくさん利用できるのRGB LEDをアナログ出力でも制御可能ですが、ESP32では他の方法を使う必要があります。

ESP32でのアナログ出力は、主にスピーカーなどのサウンドで使うことを想定しているようです。

詳しい使い方は上記にまとまっています。

PWM出力

// LEDが接続されているPINを指定する
int led_g = 26;
int led_b = 0;
int led_r = 33;

// PWMのチャンネル定義
int pwm_g = 0;

// リセットか電源を入れると一度だけ実行される初期化処理の関数です
void setup() {
  // LEDをデジタル出力モードに設定する
  pinMode(led_g, OUTPUT);
  pinMode(led_b, OUTPUT);
  pinMode(led_r, OUTPUT);

  // PWMの初期化
  ledcSetup(pwm_g, 12000, 8);
  ledcAttachPin(led_g, pwm_g);

  // LEDをすべてOFFにします(LOWにすると消灯します)
  digitalWrite(led_g, LOW);
  digitalWrite(led_b, LOW);
  digitalWrite(led_r, LOW);
}

// 常に繰り返し実行される処理の関数です
void loop() {
  for (int i = 0; i <= 256; i++) {
    ledcWrite(pwm_g, i);
    delay(10);
  }
}

PWMはちょっと初期化が増えています。PWMはONとOFFを高速で切り替えることで明るさを制御する方法です。詳しくは後ほど解説します。

// PWMのチャンネル定義
int pwm_g = 0;
(略)
  // PWMの初期化
  ledcSetup(pwm_g, 12000, 8);
  ledcAttachPin(led_g, pwm_g);

PWMは内部ではLED Controlともよばれているので、関数名がledcが頭についています。PWMは0から15までの16チャンネルが利用できます。通常は0チャンネルから順番に使っていくのがよいと思います。

ledcSetup()関数でPWMの設定を行っています。12000Hzで8ビット精度で初期化しています。ここの数値は基本変更する必要がないので、このまま使ってください。

詳しい使い方を知りたい場合には、上記記事にまとまっています。

ledcAttachPin()関数によって、PWMチャンネルとピン番号を紐付けています。

  for (int i = 0; i <= 256; i++) {
    ledcWrite(pwm_g, i);
    delay(10);
  }

上記が明るさを調整している部分になります。ledcWrite()関数にて出力をしています。ピン番号ではなく、PWMチャンネルを指定して、0から256までの数値を指定します。dacWrite()関数は0から255まででしたが、PWMは0から256までなので注意して使いましょう。

上記がPWMを0、128、256と変更した場合の出力をオシロスコープで計測した結果です。dacWrite()関数では、実際の電圧が変化していましたが、PWMではONとOFFを高速で繰り返すことで、明るさの制御をしています。128の場合にはONとOFFが繰り返しているのがわかると思います。

上記が256段階ではなく8段階だった場合の概念図です。明るさ50%にしたい場合には、時間を8スロットに分割して、半分の4スロット分だけONすることで、明るさをコントロールできます。

もう少し暗くしたい場合には、8スロットの2スロット分だけONにすることで、25%の明るさになります。8スロットの場合に消灯は0になり、全灯は8になります。このように256スロットの場合、0から256までの明るさ調整になります。

色を変えてみる

// LEDが接続されているPINを指定する
int led_g = 26;
int led_b = 0;
int led_r = 33;

// PWMのチャンネル定義
int pwm_g = 0;
int pwm_b = 1;
int pwm_r = 2;

// 色の明るさ
int value_g;
int value_b;
int value_r;

// リセットか電源を入れると一度だけ実行される初期化処理の関数です
void setup() {
  // LEDをデジタル出力モードに設定する
  pinMode(led_g, OUTPUT);
  pinMode(led_b, OUTPUT);
  pinMode(led_r, OUTPUT);

  // PWMの初期化
  ledcSetup(pwm_g, 12000, 8);
  ledcAttachPin(led_g, pwm_g);
  ledcSetup(pwm_b, 12000, 8);
  ledcAttachPin(led_b, pwm_b);
  ledcSetup(pwm_r, 12000, 8);
  ledcAttachPin(led_r, pwm_r);

  // LEDをすべてOFFにします(LOWにすると消灯します)
  digitalWrite(led_g, LOW);
  digitalWrite(led_b, LOW);
  digitalWrite(led_r, LOW);
}

// 常に繰り返し実行される処理の関数です
void loop() {
  int delayTime = 10;

  // 赤から緑
  value_r = 256;
  value_g = 0;
  value_b = 0;
  for (int i = 0; i <= 256; i++) {
    ledcWrite(pwm_r, value_r);
    ledcWrite(pwm_g, value_g);
    value_r--;
    value_g++;
    delay(delayTime);
  }

  // 緑から青
  value_r = 0;
  value_g = 256;
  value_b = 0;
  for (int i = 0; i <= 256; i++) {
    ledcWrite(pwm_g, value_g);
    ledcWrite(pwm_b, value_b);
    value_g--;
    value_b++;
    delay(delayTime);
  }

  // 青から赤
  value_r = 0;
  value_g = 0;
  value_b = 256;
  for (int i = 0; i <= 256; i++) {
    ledcWrite(pwm_b, value_b);
    ledcWrite(pwm_r, value_r);
    value_b--;
    value_r++;
    delay(delayTime);
  }
}

赤から緑、青と色が変わっていくスケッチ例です。キットではArduino UNOですので、複数あるアナログ出力を利用していましたがESP32の場合にはPWM制御にする必要があります。

  // 赤から緑
  value_r = 256;
  value_g = 0;
  value_b = 0;
  for (int i = 0; i <= 256; i++) {
    ledcWrite(pwm_r, value_r);
    ledcWrite(pwm_g, value_g);
    value_r--;
    value_g++;
    delay(delayTime);
  }

処理的には、赤から緑の場合には、赤が256の全灯している状態から徐々に暗くしていき、その分緑を明るくしています。

PWMの場合には0から256で257段階あるので注意してください。とはいっても肉眼では0から255までの256段階になっていても区別はできないと思います。

まとめ

RGB LEDは楽しいですね。中身は複数のLEDが入っているだけですので、大量のLEDを接続した液晶っぽいパネルなども販売されています。

続編

コメント