3.14. PWMによるLED調光

PWM と RC フィルタでアナログ信号を生成する のページでは、RCローパスフィルターを使ってPWM信号から直流電圧を取り出しました。LEDの場合、このフィルターは不要です。人間の目自身が平均化を行うからです。

LEDを約60 Hzより速くオンオフすると、視覚系は個々のパルスを分解できなくなり、平均的な光出力に等しい一定の明るさとして知覚します。50 %のデューティサイクルはおよそ半分の明るさに、25 %は4分の1に、10 %は暗く見えます。

配線は GPIO出力 の静的な外付けLEDと同じです。すなわち、LEDと直列の電流制限抵抗で、電子工学の基礎 のルールを使ってサイズを決めます。変わるのはソフトウェアだけです。ピンは単純な Pin.OUT ではなく PWM 出力として動作します。

3.14.1. 周波数の選択

LED調光では、PWM周波数は目のちらつきしきい値を超えればよいだけです。

  • 約60 Hzより下では、目はパルスをそのまま見てしまいます。

  • 約200 Hzより下では、周辺視野や素早い眼球運動でなおもちらつきが見える場合があります。

  • 1 kHzはそのすべてを余裕で上回っており、典型的なデフォルト値です。

GPIO上の小さなLEDにとって意味のある上限はありません。1 kHzから10 kHzまでの範囲はどれも目には同じように見えます。

3.14.2. フェード

フェードイン/フェードアウトのループは、デューティサイクルをオフからフルオンまで、そして戻るようにスイープし、各ステップで少しだけ留まります。

import time
from machine import PWM, Pin

led = PWM(Pin("P7"), freq=1000, duty_u16=0)

while True:
    for d in range(0, 65535, 256):
        led.duty_u16(d)
        time.sleep_ms(5)
    for d in range(65535, 0, -256):
        led.duty_u16(d)
        time.sleep_ms(5)

1 kHzのPWMと5 msのステップでは、目には両方向への滑らかなフェードが見え、見かけの明るさがデューティ値に追従します。

知覚される明るさはデューティサイクルに対して厳密に線形ではなく、目の応答はおよそ2乗または3乗の法則に従います。そのため duty_u16 の線形なスイープは、明るさの線形なスイープには見えません。知覚的により滑らかなフェードのためには、デューティを曲線に沿ってステップさせます。

便利な整数のみのコツは、8ビットカウンターをステップさせ、その2乗をデューティサイクルとして使うことです。255 × 255 = 65025 は丸めの範囲内でフルスケールに達するため、スイープは全範囲をカバーします。

import time
from machine import PWM, Pin

led = PWM(Pin("P7"), freq=1000, duty_u16=0)

while True:
    for step in range(256):
        led.duty_u16(step * step)   # 0..65025, roughly quadratic
        time.sleep_ms(5)
    for step in range(255, -1, -1):
        led.duty_u16(step * step)
        time.sleep_ms(5)

これでフェードは、オフからフルまで見かけの明るさがおよそ均一に感じられるようになります。