LEDをPWM制御で明るさを変えてみよう

MicroPython

ラズパイピコ(Raspberry Pi Pico)で「Lチカ(LEDを点滅させる)」ができた人、次はもう一歩進んでLEDの明るさを自由にコントロールしてみましょう!

今回は「PWM(パルス幅変調)」という仕組みを使って、LEDの明るさを100%、50%、25%と段階的に変化させます。初心者でも大丈夫。コードをそのまま写して実行すれば、すぐに「光の変化」が体験できます。

しかも、PWMを理解しておくと、次に「モーターの回転数制御」や「LEDフェード効果」など応用にもつながります。この記事では、Raspberry Pi PicoとMicroPythonを使って、楽しく学べる実験を進めていきましょう!

完成イメージ

LEDの明るさが3段階で変化するよ。

この記事でできること(目的とゴール)

この記事では以下のことを学びます:

  • PWM(パルス幅変調)の基本的な考え方
  • Raspberry Pi PicoでLEDの明るさを制御する方法
  • 初心者向けコード → 中級者コード → リファクタリング済みコードへの流れ

PWMは「電気のON/OFFを高速で切り替えて、平均電力で明るさを調整する」技術なんだよ。電気を弱めてるわけじゃないの!

ピコさん
ピコさん
PWMは「電気のON/OFFを高速で切り替えて、平均電力で明るさを調整する」技術なんだよ!

準備:必要な道具と環境

パーツ一覧

品名役割代替案
Raspberry Pi Pico Wマイコン本体Pico(無印)でも可
Micro USBケーブルデータ通信・電源供給Type-A to Micro USB(データ通信対応)
ブレッドボード配線用の土台小型でもOK
ジャンパワイヤ(オス-オス)接続ケーブル色違いで用意すると便利
LED(赤・黄・緑など)点灯テスト用単色1つでも可
抵抗(220〜330Ω)電流制限470Ωでも可

動作環境(筆者の検証環境)

  • PC:MacBook Air (M1, macOS 15.5 arm64)
  • エディタ:Thonny 4.1.6(Python 3.10.11, Tk 8.6.13)
  • デバイス:Raspberry Pi Pico W(MicroPython)

もちろん、Windows や Linux 環境でも動作します。MicroPythonを導入していれば同じコードで実行可能です。

配線図

安全上の注意

  • LEDには極性(+と−)があります。長い脚が+側です。
  • 抵抗を必ず直列に入れましょう。入れ忘れるとLEDが焼ける危険があります。
  • 静電気が強い日や金属テーブル上では、手で基板を触る前に放電しておきましょう。

まずは動くだけのベタ打ちコード(初学者)

最初はPWMを使わず、LEDの点灯・消灯を高速に繰り返して明るさを「擬似的に」変える方法から始めます。

from machine import Pin
from time import sleep

# 定数定義
LED_PIN = 15
LED_ON = 1
LED_OFF = 0
PWM_STEP_TIME = 0.005

# 初期化
led = Pin(LED_PIN, Pin.OUT)

# メインループ
while True:
    # --- 通常点灯(100% duty) ---
    for i in range(20):
        led.value(LED_ON)
        sleep(PWM_STEP_TIME)
        led.value(LED_ON)
        sleep(PWM_STEP_TIME)
        led.value(LED_ON)
        sleep(PWM_STEP_TIME)
        led.value(LED_ON)
        sleep(PWM_STEP_TIME)

    # --- 50% duty(擬似) ---
    for i in range(20):
        led.value(LED_ON)
        sleep(PWM_STEP_TIME)
        led.value(LED_OFF)
        sleep(PWM_STEP_TIME)
        led.value(LED_ON)
        sleep(PWM_STEP_TIME)
        led.value(LED_OFF)
        sleep(PWM_STEP_TIME)

    # --- 25% duty(擬似) ---
    for i in range(20):
        led.value(LED_ON)
        sleep(PWM_STEP_TIME)
        led.value(LED_OFF)
        sleep(PWM_STEP_TIME)
        led.value(LED_OFF)
        sleep(PWM_STEP_TIME)
        led.value(LED_OFF)
        sleep(PWM_STEP_TIME)

単純ですが、これでもLEDの明るさが少しずつ変わって見えます。 この方法は「PWMっぽい」挙動を再現していますが、実際のPWM機能を使ったほうがシンプルで滑らかです。

ピコさん
ピコさん
  PWM_STEP_TIME = 0.005 の数値を変えてみるとPWMの仕組みがわかるよ

リファクタリング①:PWMを使ってシンプルに

MicroPythonには、PWM制御を簡単に扱えるクラスがあります。これを使うとコードが一気にすっきりします。

from machine import Pin, PWM
from time import sleep

# 定数定義
LED_PIN = 15
PWM_FREQ_HZ = 1000  # 周波数(1kHz)
HOLD_SECONDS = 1.0  # 各デューティ比の表示時間(秒)

# 初期化
pwm = PWM(Pin(LED_PIN))
pwm.freq(PWM_FREQ_HZ)

# メインループ
while True:
    # --- 100% duty ---
    pwm.duty_u16(65535)  # 最大値(明るさMAX)
    sleep(HOLD_SECONDS)

    # --- 50% duty ---
    pwm.duty_u16(32768)  # 約半分
    sleep(HOLD_SECONDS)

    # --- 25% duty ---
    pwm.duty_u16(16384)  # 約1/4
    sleep(HOLD_SECONDS)

このように、pwm.duty_u16() に値(0〜65535)を渡すだけで、LEDの明るさを自由に制御できます。 数字が大きいほどLEDが明るくなります。

リファクタリング②:きれいで再利用しやすい形に

もう少しプログラムを整理して、見やすく・保守しやすくしてみましょう。 関数を定義してデューティ比をリスト化することで、追加や変更も簡単になります。

from machine import Pin, PWM
from time import sleep

# ==========================
# 定数定義
# ==========================
LED_PIN = 15          # LED接続ピン
PWM_FREQ_HZ = 1000    # PWM周波数(Hz)
HOLD_SECONDS = 1.0    # 各デューティ比の表示時間(秒)

# デューティ比リスト(比率で指定)
DUTY_RATIOS = [1.0, 0.5, 0.25]

# ==========================
# 関数定義
# ==========================
def set_brightness(pwm, ratio):
    """LEDの明るさをデューティ比で設定"""
    duty_value = int(65535 * ratio)
    pwm.duty_u16(duty_value)
    sleep(HOLD_SECONDS)

# ==========================
# メイン処理
# ==========================
def main():
    pwm = PWM(Pin(LED_PIN))
    pwm.freq(PWM_FREQ_HZ)

    while True:
        for ratio in DUTY_RATIOS:
            set_brightness(pwm, ratio)

# ==========================
# 実行部
# ==========================
if __name__ == "__main__":
    main()

関数化することで「明るさを設定する」という目的が明確になり、コード全体が読みやすくなりました。 また、デューティ比を増やすだけでステップ数を簡単に変更できます。

詳細解説

ここでは、次のコードがどのような動きをしているのかを初心者向けに解説します。

for ratio in DUTY_RATIOS:
    set_brightness(pwm, ratio)

この2行は、LED の明るさを順番に切り替えていく「メインの制御部分」です。

① for ratio in DUTY_RATIOS の意味

DUTY_RATIOS は、LED の明るさの割合(デューティ比)をまとめたリストです。

DUTY_RATIOS = [1.0, 0.5, 0.25]

このリストの先頭から順番に、「1.0 → 0.5 → 0.25」という値が ratio に入っていきます。

つまり、このループは LED の明るさを次のように変えていく仕組みです。

  • 1.0 → 明るさ100%
  • 0.5 → 明るさ50%
  • 0.25 → 明るさ25%

このループにより「LED の明るさを順番に変化させる」という動きが実現されています。

② set_brightness(pwm, ratio) の役割

set_brightness() 関数は「LED の明るさをセットして、その状態を少し保持する」ための関数です。

関数の中では以下が行われています。

  • ratio(0〜1.0)を PWM 用の 0〜65535 の値へ変換
  • pwm.duty_u16() に数値を渡して LED の明るさを設定
  • sleep() でその明るさをキープ

これにより、メインループ側は「明るさを変えてほしい」という指示だけを書けばよく、コードがスッキリします。

③ この構造のメリット

このように関数化してループで呼び出す構造には、次のメリットがあります。

  • コードが読みやすい:明るさ切り替え処理が整理される
  • 変更に強い:DUTY_RATIOS を書き換えるだけで明るさパターンを増減できる
  • 再利用しやすい:他のPWMプロジェクトでも同じ関数が活躍する

    🔹なぜ周期を1msにしたのか

    人間の目は0.02秒(=20ms)より速い点滅を「点滅」として認識できません。
    つまり、1ms周期(1kHz)なら目には「チラチラ」せず滑らかな光に見えるのです。

    トラブルシューティング

    もしうまく動かない場合は、以下を確認しましょう。

    症状原因対処法
    LEDが光らない極性ミスまたはピン番号間違いLEDの向き(長い脚が+)を確認
    常に点灯しているGPIOが常にHIGHになっているプログラムを再実行、またはリセットボタンを押す
    明るさが変わらないPWM周波数やデューティ設定ミスpwm.freq()とduty_u16()の値を見直す
    LEDが焼けた抵抗未使用220〜330Ωの抵抗を必ず直列に挟む

    まとめ/次回予告

    今回は、PWM制御を使ってLEDの明るさを変化させる方法を学びました。

    • PWMはON/OFFの割合で明るさを制御する技術
    • MicroPythonではPWMクラスを使えば簡単に扱える
    • 関数化することで再利用性も向上

    次回はこのPWMを応用して、LEDをなめらかにフェードイン・フェードアウトさせる方法に挑戦します。 ブックマークしておくと、次の記事もすぐに見つけられますよ!


    コメント