ESP32でPWM(RGB LED編)
はじめに
この記事ではESP32とMicropythonを用いてRGB LEDを制御する方法について紹介します。
ESP32でLちかやESP32でPWM (圧電スピーカ編)の知識があるという前提で解説します。
In English
This article describes how to drive a RGB LED (Full Color LED) with PWM connected to ESP32 using Micropython in Japanese.
RGB LEDとは
RGB LEDは光の三原色である赤(R)、緑(G)、青(B)のLEDが一つのパッケージに入ったものです。
それぞれのLEDの明るさを組み合わせることによってフルカラー(コントロールするGPIOの分解能によります)で表示できます。
下図のように、RGBがそれぞれ100%と0%(ONとOFF)だと2×2×2=8通りの組み合わせの色(全てが消灯していることも含めて)が表現できます。
例えば、RとGがONでBがOFFだと黄色に光ります。BとRがONでGがOFFだとマゼンタ(ピンク)に光り、BとGがONでRがOFFだとシアン(水色)に光ります。
画像引用元: https://ezu-ken.com/three-primary-colors-of-light/
RGB LEDのそれぞれのLEDの明るさをPWMを使ってコントロールできると、さらに多くの色の組み合わせを表現することができます。
例えば、R、G、BそれぞれのLEDが0%から100%までの間を256通りずつ明るさを変えることができるとすると、
256×256×256=約1,677万色となります。
パソコンディスプレイなどで使用されているLEDディスプレイはごく小さなRGB LED(ピクセル)が縦横に並んでいて、それぞれが指定された色で発光しています。
画像引用元: https://akizukidenshi.com/catalog/g/g102476/
アノードコモンとカソードコモン
3つのLEDが一つのパッケージに入り、電極が4つあるので、RGBを除く電極はそれぞれのLEDのアノードもしくはカソードが内部で接続されています。
下の図に示すように、アノードが共通になっているものをアノードコモン、カソードが共通になっているものをカソードコモンと言います。
アノードコモンとカソードコモン
アノードコモンのLEDを使用するかカソードコモンのLEDを使用するかによって結線が異なります。
今回の記事では上図右側のアノードコモンのLEDを使用しています。
アノードは3.3Vの電源に直接接続し、それぞれのカソードは220Ωの電流制限抵抗を介してGPIOポートに接続するので、GPIOポートがLowになると点灯し、Highになると消灯します。
結線
回路図を下の図に示します。
RGB LEDの回路図
今回使用するRGB LEDのピン接続は下図のようになっています。
RGB LEDのピン接続(前述の秋月電子の画像を編集)
一番長い足がアノードです。上図のようにアノードが左から2番目に見えるように置くと、一番左がR、右から2番目がG、右端が青の電極になります。
RGB LEDのR、G、BそれぞれのピンをGPIO32、GPIO33、GPIO25に接続します。
実際に結線するブレッドボード図を下図に示します。
RGB LEDのブレッドボード図
結線例を以下に示します。
PWMを使用しない方法
最初にRGB LEDが接続されているGPIOポートをひとつだけONにするサンプルコードを紹介した後、光の三原色の図にあったように、二つもしくは三つのLEDも同時に点灯、消灯するプログラムを紹介します。
サンプルコード1
R、G、BそれぞれのLEDを単独に順次点灯、消灯するサンプルコードです。
# RGB LED controll
# Turn on each color every 1 second
# Jan.26th 2023 (C) iot101 at zenn.dev
from machine import Pin
import time
RGB_R = 32 # red
RGB_G = 33 # green
RGB_B = 25 # blue
# Make LED instance
rgb_r = Pin(RGB_R, Pin.OUT)
rgb_g = Pin(RGB_G, Pin.OUT)
rgb_b = Pin(RGB_B, Pin.OUT)
# Put instances into a list
rgb = [rgb_r, rgb_g, rgb_b]
# Turn OFF all color
# Low=ON, High=OFF as each cathod is connected to GPIO
def turnoff():
for led in rgb:
led.on() # turn off
# Turn off all LED first
turnoff()
try:
while True:
for led in rgb:
led.off() # turn on
time.sleep(1)
turnoff()
except KeyboardInterrupt:
turnoff()
実行動画
RGB3色が順次点灯している動画です(9秒、25.4MB)
サンプルコード2
RGBそれぞれのLEDにGPIOポートからHighもしくはLowの信号を与え、全消灯を含めて、8通りの色を表示する方法です。
今回使用したRGB LED(アノードコモン)の結線ではGPIOポートをLowにすると発光し、Highにすると消灯するので、下の表の0はHigh(led.on())を意味し、1はLow(led.off())を意味します。
B | G | R | 発光色 |
---|---|---|---|
0 | 0 | 0 | 消灯 |
0 | 0 | 1 | 赤色 |
0 | 1 | 0 | 緑色 |
0 | 1 | 1 | 黄色 |
1 | 0 | 0 | 青色 |
1 | 0 | 1 | ピンク色(マゼンタ) |
1 | 1 | 0 | 水色(シアン) |
1 | 1 | 1 | 白色 |
RGBに対応する3ビットについて、最下位ビットを &演算子 を使用して0x01とANDを取り、結果が0x01であればそのビットが立っている(1である)と判断して対応するLEDを点灯し、ANDの結果が0であれば消灯し、右にシフトを行うということを繰り返しています。
# RGB LED control
# Turn on 8 pattern color every 1 second
# Mar. 28th 2024 (C) iot101 at zenn.dev
from machine import Pin
import time
RGB_R = 32 # red is connected to GPIO32
RGB_G = 33 # green is connected to GPIO33
RGB_B = 25 # blue is connected to GPIO25
# Make LED instance
rgb_r = Pin(RGB_R, Pin.OUT)
rgb_g = Pin(RGB_G, Pin.OUT)
rgb_b = Pin(RGB_B, Pin.OUT)
# Put instances into a list
rgb = [rgb_r, rgb_g, rgb_b]
colors = ["消灯", "赤色", "緑色", "黄色", "青色",
"ピンク色(マゼンタ)", "水色(シアン)", "白色"]
'''
colors = ["Turn OFF", "red", "green", "yellow", "blue",
"magent", "cyaan", "white"]
'''
# Turn OFF all color
# Low=ON, High=OFF as each cathod is connected to GPIO
def turnoff():
for led in rgb:
led.on() # turn off
# Turn off all LED first
turnoff()
try:
while True:
# There are RGB 3 bits
for n in range(8):
# print decimal, hex([2:] removes '0b'), color
print(str(n), bin(n)[2:], colors[n])
# Checking each bit
for led in rgb:
# The right end bit is 1
if n & 0x01 == 0x01:
led.off() # turn on
# The right end bit is 0
else:
led.on() # turn off
# Next bit
n = n >> 1
time.sleep(2)
print("")
except KeyboardInterrupt:
turnoff()
実行動画
色が分かりにくいですが、RGB3色が消灯も含めて8通りに点灯している動画です。(9秒、25.4MB)
PWMを使用した方法
PWMを使用して赤色LEDのデューティー比を100%から0%まで変化させるサンプルコードです。
プログラムを実行させると分かりますが、アノードコモンのRGB LEDを使用しているので、デューティー比が100%が一番暗く、0%が一番明るくなります。
サンプルコード3
# RGB LED single color bright control by PWM
# Jan.26th 2023 (C) iot101 at zenn.dev
from machine import PWM, Pin
import time
# PWM frequency
FREQ = 50
RGB_R = 32 # red is connected to GPIO32 port
# Make LED instance
rgb_r = PWM(Pin(RGB_R), FREQ)
# Turn off the LED (duty 100%)
rgb_r.duty(1023)
time.sleep(3)
# LEd control function
# color is given as an instance, duty is given as persents(0 ~ 100)
def ledpwm(color, duty):
color.duty(int(duty / 100 * 1023))
try:
while True:
# Duty 0% is full power
for duty in range(100, -1, -1):
print(duty)
ledpwm(rgb_r, duty)
time.sleep(0.02)
time.sleep(1)
except KeyboardInterrupt:
ledpwm(rgb_r, 100)
演習問題
-
サンプルコード3を変更して、R、G、Bのそれぞれを順に100%から0%にLEDの明るさが変わるようにして下さい。(Rが100%から0%に徐々に変化し、次にGが100%から0%に徐々に変化し、最後にBが100%から0%に徐々に変化する。)
(ファイル名:rgbled-ex1.py) -
RGBそれぞれのデューティー比を100%から0%まで変化させ、100x100x100=1,000,000(100万)色の組み合わせででLEDが光るようにして下さい。
ヒント: それぞれのLEDを100%から0%まで変化させるネストにする。 組み合わせが多いので、range()の増分を大きくするか、発光後のtime.sleep()を極端に短くする。
(ファイル名:rgbled-ex2.py)
- キーボードから6桁の16進数をHTMLの色指定のように入力し、入力された色でLEDが発光するプログラムを作成して下さい。例えば、ff0000(#は不要)と入力すると赤色がフルパワーで発光する。
ヒント: duty()関数の引数をは0から1023の範囲で与えるので、それぞれの色を16進数で指定する場合、2桁の16進数の0から255を0から1023に変換する必要がある。 255 → 1023
3桁の16進数で与える場合の色についてはWebデザインセーフカラー & カラーネームなどを参照して下さい。
(ファイル名:rgbled-ex3.py)
Discussion