3.14. Gradation de LED par PWM

La page Générer un signal analogique avec une PWM et un filtre RC utilisait un filtre passe-bas RC pour extraire une tension continue d’un signal PWM. Pour une LED, le filtre n’est pas nécessaire – l’œil humain lui-même effectue le moyennage.

Lorsqu’une LED est allumée et éteinte plus vite qu’environ 60 Hz, le système visuel cesse de distinguer les impulsions individuelles et perçoit une luminosité constante égale à la sortie lumineuse moyenne. Un rapport cyclique de 50 % se lit comme à peu près la moitié de la luminosité ; 25 % comme un quart ; 10 % comme faible.

Le câblage est le même que pour une LED externe statique sur Sortie GPIO – une résistance de limitation de courant en série avec la LED, dimensionnée selon les règles de Notions d’électronique. Le changement ne porte que sur le logiciel : la broche fonctionne en sortie PWM au lieu d’un simple Pin.OUT.

3.14.1. Choisir la fréquence

Pour la gradation de LED, la fréquence PWM doit seulement franchir le seuil de scintillement de l’œil :

  • En dessous d’environ 60 Hz, l’œil voit franchement les impulsions.

  • En dessous d’environ 200 Hz, la vision périphérique et les mouvements oculaires rapides peuvent encore révéler du scintillement.

  • 1 kHz est confortablement au-dessus de tout cela et constitue une valeur par défaut typique.

Il n’y a pas de limite supérieure significative pour une petite LED sur un GPIO ; de 1 kHz à 10 kHz, le comportement est identique pour l’œil.

3.14.2. Fondu

Une boucle de fondu en ouverture / fondu en fermeture balaie le rapport cyclique de l’arrêt jusqu’au plein régime puis retour, en s’attardant brièvement à chaque palier :

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 de PWM et des paliers de 5 ms, l’œil perçoit un fondu fluide dans les deux directions, la luminosité apparente suivant la valeur du rapport cyclique.

La luminosité perçue n’est pas strictement linéaire en fonction du rapport cyclique – la réponse de l’œil suit approximativement une loi quadratique ou cubique – de sorte qu’un balayage linéaire de duty_u16 ne ressemble pas à un balayage linéaire de luminosité. Pour un fondu perceptivement plus régulier, faites varier le rapport cyclique selon une courbe.

Une astuce pratique en nombres entiers consiste à incrémenter un compteur 8 bits et à utiliser son carré comme rapport cyclique. 255 × 255 = 65025 est à l’arrondi près de la pleine échelle, donc le balayage couvre toute la plage :

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)

Le fondu paraît désormais à peu près régulier en luminosité apparente, de l’arrêt au plein régime.