前回はスイッチを使ったLED制御を学びました。
今回はLEDの光る明るさを変える制御について学んでゆきます。

PWMとは
PWM(Pulse Width Modulation)とは、「電気を点けたり消したりする時間の割合を調整することで、出力の強さを変える技術」です。
矩形波(方形波)において周期Tに占めるHの時間tの割合(デューティ比)を変化させることで、疑似的なアナログ出力を実現することができます(実際のアナログ出力ではないので注意してください)。

PWMは、DCモータの回転速度制御やLEDの明るさの制御(調光)などに利用されています。また、人型ロボットの関節などに利用されるRCサーボモータの制御にも利用されています。

「analog」という名称であるが、電圧が変化している訳ではなく、あくまで疑似アナログ出力なので注意してください。
たとえば…
- 点灯:消灯 = 1:1(50%) → 明るさ中くらい
- 点灯:消灯 = 9:1(90%) → 明るさ強め
- 点灯:消灯 = 1:9(10%) → 明るさ弱め
これを**とても速い速度(数千回/秒)**で繰り返すことで、LEDは「チカチカ」せず、明るさが変わったように見えます。
例題1
LEDの明るさを指定して点灯
以下のようなプログラムになります。
from machine import Pin, PWM
import time
led = PWM(Pin(15)) # GPIO15をPWM出力に設定
led.freq(1000) # PWMの周波数を1000Hzに設定
led.duty_u16(32768) # デューティ比50%(最大65535の半分)
PWM(Pin(15))
:GPIO15ピンにPWMを出力
freq(1000)
:1秒間に1000回の速さで点滅(チラつき防止)
duty_u16(x)
:PWMの強さを0〜65535の値で指定
例:65535 = 最大出力(明るさ100%)、0 = OFF
例題2
明るさをだんだん変える
from machine import Pin, PWM
import time
led = PWM(Pin(15))
led.freq(1000)
while True:
# 徐々に明るく
for i in range(0, 65536, 1024):
led.duty_u16(i)
time.sleep(0.01)
# 徐々に暗く
for i in range(65535, -1, -1024):
led.duty_u16(i)
time.sleep(0.01)
range(0, 65536, 1024)
:明るさを0→最大まで増やす
range(65535, -1, -1024)
:明るさを最大→0まで減らす
time.sleep(0.01)
:変化の速度(速くするとアニメーションも速くなる)
課題6
ボタンを押すごとに明るさを段階的に切り替わる回路を作成せよ。
ボタン(GPIO14)を押すたびに、LEDの明るさが
→「OFF → 弱 → 中 → 強 → OFF…」と繰り返し切り替わる
押しっぱなしでは反応せず、「押された瞬間」だけ反応

解答例はこちら
from machine import Pin, PWM
import time
led = PWM(Pin(15))
led.freq(1000)
button = Pin(14, Pin.IN, Pin.PULL_DOWN)
# 明るさの段階をリストで管理
levels = [0, 20000, 40000, 65535]
level_index = 0
prev = 0 # 前回のボタン状態
while True:
current = button.value()
# 押された瞬間だけ反応(エッジ検出)
if prev == 0 and current == 1:
level_index = (level_index + 1) % len(levels) # インデックスを循環
led.duty_u16(levels[level_index]) # 明るさを設定
prev = current
time.sleep(0.01)
課題7
2つのボタンを使ってLEDの明るさを手動調整する回路を作成せよ。
ボタンA(GPIO14)を押すたびに明るさを「+5000」
ボタンB(GPIO13)を押すたびに明るさを「−5000」
明るさは 0〜65535の範囲内に収める
解答例はこちら
from machine import Pin, PWM
import time
led = PWM(Pin(15))
led.freq(1000)
btn_up = Pin(14, Pin.IN, Pin.PULL_DOWN)
btn_down = Pin(13, Pin.IN, Pin.PULL_DOWN)
duty = 0
led.duty_u16(duty)
prev_up = 0
prev_down = 0
while True:
current_up = btn_up.value()
current_down = btn_down.value()
# 明るさを上げる
if prev_up == 0 and current_up == 1:
duty += 5000
if duty > 65535:
duty = 65535
led.duty_u16(duty)
# 明るさを下げる
if prev_down == 0 and current_down == 1:
duty -= 5000
if duty < 0:
duty = 0
led.duty_u16(duty)
prev_up = current_up
prev_down = current_down
time.sleep(0.01)
課題8
課題7のLEDに対する出力の変化(PWM)をオシロスコープを使って観察し、報告せよ。
オシロスコープは下記の記事を参考にしてください。
次回はこちら