🐝

ESP32でPWM(RGB LED編)

2024/03/29に公開


はじめに

この記事では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だとシアン(水色)に光ります。

Alt光の三原色
画像引用元: 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(ピクセル)が縦横に並んでいて、それぞれが指定された色で発光しています。

AltRGB LEDの例
画像引用元: https://akizukidenshi.com/catalog/g/g102476/

アノードコモンとカソードコモン

3つのLEDが一つのパッケージに入り、電極が4つあるので、RGBを除く電極はそれぞれのLEDのアノードもしくはカソードが内部で接続されています。
下の図に示すように、アノードが共通になっているものをアノードコモン、カソードが共通になっているものをカソードコモンと言います。

Altアノードコモンとカソードコモン例
アノードコモンとカソードコモン

アノードコモンのLEDを使用するかカソードコモンのLEDを使用するかによって結線が異なります。
今回の記事では上図右側のアノードコモンのLEDを使用しています。

アノードは3.3Vの電源に直接接続し、それぞれのカソードは220Ωの電流制限抵抗を介してGPIOポートに接続するので、GPIOポートがLowになると点灯し、Highになると消灯します。

結線

回路図を下の図に示します。
AltRGB LEDの回路図
RGB LEDの回路図

今回使用するRGB LEDのピン接続は下図のようになっています。

AltRGB LEDのピン接続
RGB LEDのピン接続(前述の秋月電子の画像を編集)

一番長い足がアノードです。上図のようにアノードが左から2番目に見えるように置くと、一番左がR、右から2番目がG、右端が青の電極になります。
RGB LEDのRGBそれぞれのピンをGPIO32GPIO33GPIO25に接続します。

実際に結線するブレッドボード図を下図に示します。
AltRGB LEDのブレッドボード図
RGB LEDのブレッドボード図

結線例を以下に示します。
Alt結線例

PWMを使用しない方法

最初にRGB LEDが接続されているGPIOポートをひとつだけONにするサンプルコードを紹介した後、光の三原色の図にあったように、二つもしくは三つのLEDも同時に点灯、消灯するプログラムを紹介します。

サンプルコード1

R、G、BそれぞれのLEDを単独に順次点灯、消灯するサンプルコードです。

rgb_led1.py
# 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_led2.py
# 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_pwm1.py
# 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)

演習問題

  1. サンプルコード3を変更して、R、G、Bのそれぞれを順に100%から0%にLEDの明るさが変わるようにして下さい。(Rが100%から0%に徐々に変化し、次にGが100%から0%に徐々に変化し、最後にBが100%から0%に徐々に変化する。)
    (ファイル名:rgbled-ex1.py)

  2. RGBそれぞれのデューティー比を100%から0%まで変化させ、100x100x100=1,000,000(100万)色の組み合わせででLEDが光るようにして下さい。

ヒント: それぞれのLEDを100%から0%まで変化させるネストにする。 組み合わせが多いので、range()の増分を大きくするか、発光後のtime.sleep()を極端に短くする。
(ファイル名:rgbled-ex2.py)

  1. キーボードから6桁の16進数をHTMLの色指定のように入力し、入力された色でLEDが発光するプログラムを作成して下さい。例えば、ff0000(#は不要)と入力すると赤色がフルパワーで発光する。

ヒント: duty()関数の引数をは0から1023の範囲で与えるので、それぞれの色を16進数で指定する場合、2桁の16進数の0から255を0から1023に変換する必要がある。 255 → 1023
3桁の16進数で与える場合の色についてはWebデザインセーフカラー & カラーネームなどを参照して下さい。
(ファイル名:rgbled-ex3.py)

Discussion