RGB LED
今回 扱うLEDは、NeoPixel(WS2812他)等のマイコン内蔵フルカラーLEDではありません。
(下の写真のような)Red、Green、Blue 各色のピンと共通ピンの合計4ピンあるRGBLEDです。

アノード(+)コモン と、カソード(-)コモンの2タイプがあります。


一番足の長いピンが共通ピンですが、R・G・Bピンの並びは、RGBLEDの製品により異なる場合があるので、データシートで確認します。
R・G・B のそれぞれのピンに電流制限抵抗を入れる必要があります。RGBLED製品の諸元をもとに必要な抵抗値を計算で求められますが、3.3V〜5Vで駆動する場合は 500Ω〜1KΩ 程度の抵抗を使えばほぼ問題ありません。
点灯させる論理のおさらい
これまでの説明の通り、R・G・B の各色は独立していることが分かります。
※折りたたんであります。「LEDを点灯させる論理」を確認したい方は、次の「ここに表示」をクリックしてください。
ここに表示
On/Off制御(デジタル制御)
各色を光る
、消す
で制御すると、次の8色の発光パターンが作れます。
(下表で、1:光る
、0:消す
を表す)
R | G | B | 色 |
---|---|---|---|
0 | 0 | 0 | (全消灯) |
0 | 0 | 1 | 青 |
0 | 1 | 0 | 緑 |
0 | 1 | 1 | 水 |
1 | 0 | 0 | 赤 |
1 | 0 | 1 | 紫 |
1 | 1 | 0 | 黄 |
1 | 1 | 1 | 白 |
これを実現するには、
-
アノードコモン の場合
-
1:光る
V-
(GND)に接続 -
0:消す
V+
(VDD)に接続
-
-
カソードコモン の場合
-
1:光る
V+
(VDD)に接続 -
0:消す
V-
(GND)に接続
-
と、なります。
アノードコモンとカソードコモンでは、逆の理論になっています。
(カソードコモンの方が、電気の流れと論理が一致していて、分かり易い気がします)
タイトルでいう「同じに扱う」にはなっていませんが、反転
するだけです。
整数の0
と1
で表すなら、カソードコモンを基準に0
か1
に決定した値をi
とすると、アノードコモンの場合の値は、(1-i)
です。
Boolean変数x
なら、(Not x)
で、言語により(!x)
かも知れません。
Arduino
におけるdigitalWrite()
がこれに当たります。R・G・B のそれぞれのピンに対して実行します。
- カソードコモンの場合
digitalWrite(pin#, i)
ordigitalWrite(pin#, x)
- アノードコモンの場合
digitalWrite(pin#, 1 - i)
ordigitalWrite(pin#, !x)
ただし、最初からdigitalWrite(pin#, 0)
がOn、digitalWrite(pin#, 1)
がOffを意味する負論理
のマイコンが存在します。今回の記事を負論理
のマイコンに適用する場合は、さらにNot
が必要になります。ややこしい・・・
PWM制御(アナログ制御)
他方、各R・G・BのOn・Off制御ではなく、各R・G・Bを16階調や256階調で制御することで、4096色($16^3$)や1677万色($256^3$)の発光パターンを作れます。
これは、各R・G・Bに印加する電圧を変化させることで実現します。この方法としては、PWM(Pulse Width Modulation)電圧変換が一般的です。
PWM電圧変換とは、一定電圧(VDD)の入力からパルス列のオンとオフの一定周期を作り(周期を周波数で示すことが多い)、オンの時間幅(デューティ比)を変化させ、出力電圧を制御することです。出力電圧はデューティ比に該当する平均化された大きさとなります。
例えば、デューティ比を50%とすれば、VDDの半分の電圧を出力することができます。
デューティ比の指定方法は、使用するマイコンと使用する言語によって異なりますが、どんなマイコンでもPWM制御は持っていますし、デューティ比も変えられます。
PWMの周波数は、数百Hzで十分です。高性能のマイコンなら数KHzでも可
例えば、関数PWM(0〜1023)
でデューティ比が指定できると仮定すると、256階調とするなら、$\bigl(\frac{1023}{255}\bigr)$≒4倍した値を引数に渡せばよいことになります。
スカイブルーという色のRGB値が(R:135, G:206, B:235)
だとすると、以下の擬似コードになります。
Red.PWM(135 * 1023 / 255)
Green.PWM(206 * 1023 / 255)
Blue.PWM(235 * 1023 / 255)
ただし、これは、カソードコモン での場合です。
アノードコモン の場合は、反転論理
ですから、値を反転する必要があります。
PWM関数の引数でカソードコモンでの値をi
とするなら、アノードコモン の場合は、(1023-i)
となります。
Red.PWM(1023 - 135 * 1023 / 255)
Green.PWM(1023 - 206 * 1023 / 255)
Blue.PWM(1023 - 235 * 1023 / 255)
今回は検証用に WOKWI版 Raspbery Pi Pico & Micropython を使いますが、どんなマイコンであれ、使える言語に差があっても、考え方はどれも同じです。

Picoは、どのGPIOピンでもPWMを使用できますが、全部で8チャネルしかありません。
GPIO0〜15とGPIO16以降でチャネルが重複しているので、PWMで使用するGPIOピンを選ぶときは注意が必要です。
参考サイト
https://www.denshi.club/parts/2021/07/raspberry-pi-pico-18-pwm.html
実際に試す
上の写真のように、カソードコモンとアノードコモンのRGBLEDを、Raspbery Pi Picoに接続します。
On/Off制御
アノードコモンとカソードコモンの差を吸収するために、クラス化しました。インスタンス生成時に、コモンタイプを指定します。
from machine import Pin
import utime
class RGBLED:
def __init__(self, red_pin, green_pin, blue_pin, anode_common=False):
self.red = Pin(red_pin, Pin.OUT)
self.green = Pin(green_pin, Pin.OUT)
self.blue = Pin(blue_pin, Pin.OUT)
self.anode_common = anode_common
def rgb(self, r, g, b):
if self.anode_common:
r = 1 - r
g = 1 - g
b = 1 - b
self.red.value(r)
self.green.value(g)
self.blue.value(b)
a_led = RGBLED(28, 27, 26, anode_common=True) #アノードコモン
c_led = RGBLED(3, 2, 1) #カソードコモン
Illumination = [
(0, 0, 1), #青
(0, 1, 0), #緑
(0, 1, 1), #水
(1, 0, 0), #赤
(1, 0, 1), #紫
(1, 1, 0), #黄
(1, 1, 1), #白
(0, 0, 0) #全消灯
]
while True:
for r, g, b in Illumination:
a_led.rgb(r, g, b)
c_led.rgb(r, g, b)
utime.sleep(1)
タネを明かすと、これが、タイトルに書いた『同じに扱う』ということでした。
下のURLをクリックすると、WOKWI シミュレータが開きます。 をクリックすると、コードを実行してRGBLEDが光る様子を見られます。
PWM制御
こちらも、アノードコモンとカソードコモンの差を吸収するために、クラス化しました。
MicroPythonでは、PWMのでデューティ比を0〜65535で指定するため、256階調にするために、$\bigl(\frac{65535}{255}\bigr)$≒256倍します。
from machine import Pin, PWM
import utime
class RGBLED:
def __init__(self, red_pin, green_pin, blue_pin, anode_common=False):
self.red = PWM(Pin(red_pin), freq=200)
self.green = PWM(Pin(green_pin), freq=200)
self.blue = PWM(Pin(blue_pin), freq=200)
self.anode_common = anode_common
def pwm(self, r, g, b):
r = int(r * 65535 / 255)
g = int(g * 65535 / 255)
b = int(b * 65535 / 255)
if self.anode_common:
r = 65535 - r
g = 65535 - g
b = 65535 - b
self.red.duty_u16(r)
self.green.duty_u16(g)
self.blue.duty_u16(b)
a_led = RGBLED(28, 27, 26, anode_common=True) #アノードコモン
c_led = RGBLED(3, 2, 1) #カソードコモン
Illumination = [
(64, 154, 227),
(128, 0, 128),
(50, 150, 50),
(255, 30, 30),
(0, 128, 255),
(99, 199, 0),
(128, 128, 128),
(255, 100, 0)
]
while True:
for r, g, b in Illumination:
a_led.pwm(r, g, b)
c_led.pwm(r, g, b)
utime.sleep(1)
下のURLをクリックすると、WOKWI シミュレータが開きます。
実は、MicroPythonのPWMには 論理反転
する引数invert
がはじめから用意されており、これを使うと、自力で論理反転
する処理が不要になります。
この場合は、以下のコードとなります。
from machine import Pin, PWM
import utime
class RGBLED:
def __init__(self, red_pin, green_pin, blue_pin, anode_common=False):
self.red = PWM(Pin(red_pin), freq=200, invert=anode_common)
self.green = PWM(Pin(green_pin), freq=200, invert=anode_common)
self.blue = PWM(Pin(blue_pin), freq=200, invert=anode_common)
self.anode_common = anode_common
def pwm(self, r, g, b):
r = int(r * 65535 / 255)
g = int(g * 65535 / 255)
b = int(b * 65535 / 255)
self.red.duty_u16(r)
self.green.duty_u16(g)
self.blue.duty_u16(b)
a_led = RGBLED(28, 27, 26, anode_common=True) #アノードコモン
c_led = RGBLED(3, 2, 1) #カソードコモン
Illumination = [
(64, 154, 227),
(128, 0, 128),
(50, 150, 50),
(255, 30, 30),
(0, 128, 255),
(99, 199, 0),
(128, 128, 128),
(255, 100, 0)
]
while True:
for r, g, b in Illumination:
a_led.pwm(r, g, b)
c_led.pwm(r, g, b)
utime.sleep(1)
下のURLをクリックすると、WOKWI シミュレータが開きます。
まとめ
自分が持っていないコモン
タイプの制作例を真似するときは、“反転”
するだけで使えるようになりました。