3.14. LED-dimning med PWM

Sidan Generera analoga signaler med PWM och ett RC-filter använde ett RC-lågpassfilter för att extrahera en DC-spänning ur en PWM-signal. För en lysdiod behövs inte filtret – det mänskliga ögat självt utför medelvärdesbildningen.

När en lysdiod slås på och av snabbare än omkring 60 Hz slutar synsystemet att urskilja enskilda pulser och uppfattar en jämn ljusstyrka som motsvarar det genomsnittliga ljusflödet. En pulskvot på 50 % uppfattas som ungefär halv ljusstyrka; 25 % som en fjärdedel; 10 % som svagt.

Kopplingen är densamma som för en statisk extern lysdiod på GPIO-utgång – ett strömbegränsande motstånd i serie med lysdioden, dimensionerat med reglerna från Elektronikgrunder. Ändringen sker bara i programvaran: stiftet körs som en PWM-utgång istället för en vanlig Pin.OUT.

3.14.1. Att välja frekvens

För LED-dimning behöver PWM-frekvensen bara klara ögats flimmertröskel:

  • Under ~60 Hz ser ögat pulserna rakt av.

  • Under ~200 Hz kan perifert seende och snabba ögonrörelser fortfarande avslöja flimmer.

  • 1 kHz ligger bekvämt över allt detta och är ett typiskt standardvärde.

Det finns ingen övre gräns som spelar roll för en liten lysdiod på en GPIO; allt från 1 kHz till 10 kHz beter sig likadant för ögat.

3.14.2. Toning

En in-/uttoningsslinga sveper pulskvoten från av till helt på och tillbaka, och dröjer kort vid varje steg:

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)

Vid 1 kHz PWM och 5 ms-steg ser ögat en mjuk toning i båda riktningarna, där den upplevda ljusstyrkan följer pulskvotsvärdet.

Upplevd ljusstyrka är inte strikt linjär med pulskvoten – ögats respons följer ungefär en kvadrat- eller kubiklag – så en linjär svepning av duty_u16 ser inte ut som en linjär svepning av ljusstyrka. För en perceptuellt mjukare toning, stega pulskvoten längs en kurva.

Ett bekvämt heltalsbaserat trick är att stega en 8-bitars räknare och använda dess kvadrat som pulskvot. 255 × 255 = 65025 ligger inom avrundning från full skala, så svepningen täcker hela intervallet:

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)

Toningen känns nu ungefär jämn i upplevd ljusstyrka från av till full.