2. パルス幅変調¶
パルス幅変調(PWM)は、デジタルピンから人工的なアナログ出力を得るための方法です。これは、ピンをローからハイに素早く切り替えることで実現しますこれには2つのパラメータがあります。切り替えの周波数とデューティ比です。デューティ比は、1周期(ロー + ハイの時間)の長さに比べて、ピンがハイになっている時間の長さと定義されています。デューティ比の最大値は、ピンが常にハイである場合であり、最小値はピンが常にローである場合です。
16個のPWMチャンネルと8個のタイマー を使った、より包括的な例を示します:
from time import sleep from machine import Pin, PWM try: F = 10000 # Hz D = 65536 // 16 # 6.25% pins = (2, 4, 12, 13, 14, 15, 16, 18, 19, 22, 23, 25, 26, 27, 32, 33) pwms = [] for i, pin in enumerate(pins): f = F * (i // 2 + 1) d = min(65535, D * (i + 1)) pwms.append(PWM(pin, freq=f, duty_u16=d)) sleep(2 / f) print(pwms[i]) finally: for pwm in pwms: try: pwm.deinit() except: pass
以下のような出力が得られます:
PWM(Pin(2), freq=10000, duty_u16=4096) PWM(Pin(4), freq=10000, duty_u16=8192) PWM(Pin(12), freq=20000, duty_u16=12288) PWM(Pin(13), freq=20000, duty_u16=16384) PWM(Pin(14), freq=30030, duty_u16=20480) PWM(Pin(15), freq=30030, duty_u16=24576) PWM(Pin(16), freq=40000, duty_u16=28672) PWM(Pin(18), freq=40000, duty_u16=32768) PWM(Pin(19), freq=50000, duty_u16=36864) PWM(Pin(22), freq=50000, duty_u16=40960) PWM(Pin(23), freq=60060, duty_u16=45056) PWM(Pin(25), freq=60060, duty_u16=49152) PWM(Pin(26), freq=69930, duty_u16=53248) PWM(Pin(27), freq=69930, duty_u16=57344) PWM(Pin(32), freq=80000, duty_u16=61440) PWM(Pin(33), freq=80000, duty_u16=65535)
スムーズな周波数変更 の例:
from time import sleep from machine import Pin, PWM F_MIN = 1000 F_MAX = 10000 f = F_MIN delta_f = F_MAX // 50 pwm = PWM(Pin(27), f) while True: pwm.freq(f) sleep(1 / f) sleep(0.1) print(pwm) f += delta_f if f > F_MAX or f < F_MIN: delta_f = -delta_f print() if f > F_MAX: f = F_MAX elif f < F_MIN: f = F_MIN
オシロスコープで Pin(27) の PWM 波形を見てみてください。
以下のような出力が得られます:
PWM(Pin(27), freq=998, duty_u16=32768) PWM(Pin(27), freq=1202, duty_u16=32768) PWM(Pin(27), freq=1401, duty_u16=32768) PWM(Pin(27), freq=1598, duty_u16=32768) ... PWM(Pin(27), freq=9398, duty_u16=32768) PWM(Pin(27), freq=9615, duty_u16=32768) PWM(Pin(27), freq=9804, duty_u16=32768) PWM(Pin(27), freq=10000, duty_u16=32768) PWM(Pin(27), freq=10000, duty_u16=32768) PWM(Pin(27), freq=9804, duty_u16=32768) PWM(Pin(27), freq=9615, duty_u16=32768) PWM(Pin(27), freq=9398, duty_u16=32768) ... PWM(Pin(27), freq=1598, duty_u16=32768) PWM(Pin(27), freq=1401, duty_u16=32768) PWM(Pin(27), freq=1202, duty_u16=32768) PWM(Pin(27), freq=998, duty_u16=32768)
スムーズなデューティ変更 の例:
from time import sleep from machine import Pin, PWM DUTY_MAX = 65535 duty_u16 = 0 delta_d = 256 pwm = PWM(Pin(27), freq=1000, duty_u16=duty_u16) while True: pwm.duty_u16(duty_u16) sleep(2 / pwm.freq()) print(pwm) if duty_u16 >= DUTY_MAX: print() sleep(2) elif duty_u16 <= 0: print() sleep(2) duty_u16 += delta_d if duty_u16 >= DUTY_MAX: duty_u16 = DUTY_MAX delta_d = -delta_d elif duty_u16 <= 0: duty_u16 = 0 delta_d = -delta_d
オシロスコープで Pin(27) の PWM 波形を見てみてください。
以下のような出力が得られます:
PWM(Pin(27), freq=998, duty_u16=0) PWM(Pin(27), freq=998, duty_u16=256) PWM(Pin(27), freq=998, duty_u16=512) PWM(Pin(27), freq=998, duty_u16=768) PWM(Pin(27), freq=998, duty_u16=1024) ... PWM(Pin(27), freq=998, duty_u16=64512) PWM(Pin(27), freq=998, duty_u16=64768) PWM(Pin(27), freq=998, duty_u16=65024) PWM(Pin(27), freq=998, duty_u16=65280) PWM(Pin(27), freq=998, duty_u16=65535) PWM(Pin(27), freq=998, duty_u16=65279) PWM(Pin(27), freq=998, duty_u16=65023) PWM(Pin(27), freq=998, duty_u16=64767) PWM(Pin(27), freq=998, duty_u16=64511) ... PWM(Pin(27), freq=998, duty_u16=1023) PWM(Pin(27), freq=998, duty_u16=767) PWM(Pin(27), freq=998, duty_u16=511) PWM(Pin(27), freq=998, duty_u16=255) PWM(Pin(27), freq=998, duty_u16=0)
スムーズなデューティ変更と PWM 出力反転 の例:
from utime import sleep from machine import Pin, PWM try: DUTY_MAX = 65535 duty_u16 = 0 delta_d = 65536 // 32 pwm = PWM(Pin(27)) pwmi = PWM(Pin(32), invert=1) while True: pwm.duty_u16(duty_u16) pwmi.duty_u16(duty_u16) duty_u16 += delta_d if duty_u16 >= DUTY_MAX: duty_u16 = DUTY_MAX delta_d = -delta_d elif duty_u16 <= 0: duty_u16 = 0 delta_d = -delta_d sleep(.01) print(pwm) print(pwmi) finally: try: pwm.deinit() except: pass try: pwmi.deinit() except: pass
以下のような出力が得られます:
PWM(Pin(27), freq=5000, duty_u16=0) PWM(Pin(32), freq=5000, duty_u16=32768, invert=1) PWM(Pin(27), freq=5000, duty_u16=2048) PWM(Pin(32), freq=5000, duty_u16=2048, invert=1) PWM(Pin(27), freq=5000, duty_u16=4096) PWM(Pin(32), freq=5000, duty_u16=4096, invert=1) PWM(Pin(27), freq=5000, duty_u16=6144) PWM(Pin(32), freq=5000, duty_u16=6144, invert=1) PWM(Pin(27), freq=5000, duty_u16=8192) PWM(Pin(32), freq=5000, duty_u16=8192, invert=1) ...
オシロスコープで Pin(27) と Pin(32) の PWM 波形を見てみてください。
注記: 新しい PWM パラメーターは次の PWM サイクルから有効になります。
pwm = PWM(2, duty=512) print(pwm) >>> PWM(Pin(2), freq=5000, duty=1023) # デューティの変更が有効になってない pwm.init(freq=2, duty=64) print(pwm) >>> PWM(Pin(2), freq=2, duty=16) # デューティの変更が有効になってない time.sleep(1 / 2) # PWM の1周期分だけ待機 print(pwm) >>> PWM(Pin(2), freq=2, duty=64) # デューティの変更が有効になった
注記: machine.freq(20_000_000) は PWM の最高周波数を 10 MHz に下げます。
注記: Pin.OUT モードを指定する必要はありません。チャネルは、PWM コンストラクターに渡されるピンごとに1回、内部的に PWM モードに初期化されます。
次のコードは間違いです:
pwm = PWM(Pin(5, Pin.OUT), freq=1000, duty=512) # ここで Pin(5) が PWM モードなるが...
pwm = PWM(Pin(5, Pin.OUT), freq=500, duty=256) # ここで Pin(5) が OUT モードになり、PWM が無効になる
代わりに次のコードのようにしてください:
pwm = PWM(Pin(5), freq=1000, duty=512)
pwm.init(freq=500, duty=256)