Ignorer et passer au contenu

Livraison offerte à partir de 50€ d'achats, livrée sous 48h !

Livraison à partir de seulement 2.50€ !

Contents Menu Expand Light mode Dark mode Auto light/dark mode

Générer des tensions variables grâce au PWM en MicroPython

(Mis à jour le 28/05/2023)

Le PWM, une astuce pour générer des tensions variables sur des broches numériques

Le PWM est une technique qui permet de générer une tension comprise entre 0 et 3.3V en utilisant uniquement des sorties numériques . PWM est l’acronyme de Pulse Width Modulation , en français c’est appelé MLI pour Modulation de Largeur d’Impulsion . En effet, cette astuce repose sur la proportion temporelle d’un signal logique à son état haut (3.3V) et à son état bas (0V) : le PWM consiste à faire varier la largeur d’une impulsion électrique.

Note

Le PWM permet de générer des tensions constantes dont on peut faire varier la valeur. Il ne génère pas des tensions alternatives comme pourrait le faire un DAC.

fonctionnement pwm micropython

Principe du PWM

La succession d’impulsions avec une largeur donnée est vue en moyenne comme une tension constante comprise entre 0V et 3.3V dont la valeur est déterminée par :

\[V_{sortie} = V_{entree} \times \alpha\]

avec α la largeur d’impulsion (duty cycle en anglais)

Un signal PWM se configure via la largeur d’impulsion et la fréquence de l’impulsion. On pourra modifier ces 2 paramètres en MicroPython.

En pratique, le PWM est utilisé pour :

  • Contrôler la vitesse d’un moteur

  • Contrôler la luminosité de LED

  • Générer des signaux carrés (avec α=0.5)

  • Générer des notes de musique (son similaire à celui des consoles rétro)

Performance du PWM sur l’ESP32

Les signaux PWM ne sont pas générés en permanence par le microprocesseur mais par des blocs matériels dédiés. Il suffit ainsi de configurer une seule fois les blocs PWM dans le script pour que le signal soit généré en continu en tâche de fond. On associe une sortie d’un bloc PWM à une broche de notre carte. Les ressources du processeur seront libres pour exécuter d’autres tâches.

Chaque bloc PWM peut avoir une fréquence indépendante.

Caractéristiques du PWM de l’

ESP32

Plage de fréquence du signal PWM

1Hz à 40 Mhz

Fréquence PWM indépendante

8

Sortie PWM

16

Résolution de la largeur d’impulsion

10 bits

Note

En pratique, dans la majorité des cas, une fréquence PWM autour de 1000 Hz sera suffisante.

Le PWM sur MicroPython

L’utilisation du PWM avec MicroPython est très simple. MicroPython se charge de sélectionner automatiquement un bloc PWM disponible : il n’est pas nécessaire d’indiquer celui que l’on compte utiliser. La partie hardware décrite au-dessus est complètement masquée.

La configuration consiste à associer un objet PWM à un objet Pin et de choisir la fréquence PWM.

from machine import Pin, PWM

pin = Pin(25, mode=Pin.OUT)
pin_with_pwm = PWM(pin) # Attach PWM object on a pin

Note

Puisque l’objet PWM est aussi dans le module machine, on peut réunir les 2 imports sur une seule ligne :

from machine import Pin
from machine import PWM

est équivalent à

from machine import Pin, PWM

Une fois que l’on a lié une broche de la carte à notre objet PWM, toutes les fonctions se font directement sur l’objet PWM (Contrairement au code Arduino ou l’on précise le numéro de pin avec la fonction analogWrite(pin_number) .

Note

En python, on peut insérer des underscores _ pour lire plus facilement les nombres (et ainsi éviter de compter les zéros sur des grands nombres). Par exemple, pour écrire 1 MHz , au lieu d’avoir 1000000 on peut mettre 1_000_000 .

On utilise la fonction .duty_() pour choisir la largeur d’impulsion avec une valeur comprise entre 0 et \(2^{10}\)  (0-1024). La tension est imposée directement en sortie du pin sélectionné précédemment.

Pour se rendre compte de la variation de la tension, on peut utiliser la LED intégrée de votre carte avec le script suivant :

from machine import Pin, PWM

LED_BUITLTIN = 2 # For ESP32

pwm_led = PWM(Pin(LED_BUITLTIN, mode=Pin.OUT)) # Attach PWM object on the LED pin

# Settings
pwm_led.freq(1_000)

while True:
    for duty in range(0,1024):
        pwm_led.duty(duty) # For ESP32

Pour que ce soit plus parlant, on pourrait préciser juste le pourcentage du duty cycle puis appliquer une formule.

from machine import Pin, PWM

LED_BUITLTIN = 2 # For ESP32

pwm_led = PWM(Pin(LED_BUITLTIN, mode=Pin.OUT)) # Attach PWM object on the LED pin
pwm_led.freq(1_000)

duty_cycle = 50 # Between 0 - 100 %
pwm_led.duty(int((duty_cycle/100)*1024))

On peut fait varier la luminosité de le LED en faisant varier entre 0 et 100% la largeur d’impulsion.

from machine import Pin, PWM
import time

LED_BUITLTIN = 2 # For ESP32

pwm_led = PWM(Pin(LED_BUITLTIN, mode=Pin.OUT)) # Attach PWM object on the LED pin
pwm_led.freq(1_000)

while True:
    for duty in range(100): # Duty from 0 to 100 %
        pwm_led.duty(int((duty/100)*1024))
        time.sleep_ms(5)

Note

On rajoute un délai de 5ms avec time.sleep_ms(5) pour ralentir le code et voir ainsi à l’œil nu, la variation de la luminosité.

Mini-Projet : Faire dimmer la LED intégrée de l’ESP32

Avec tout ce que l’on a vu, le script est très facile à faire :

from machine import Pin, PWM
import time

LED_BUITLTIN = 2 # For ESP32
pwm_led = PWM(Pin(LED_BUITLTIN, mode=Pin.OUT)) # Attach PWM object on the LED pin

# Settings
pwm_led.freq(1_000)

while True:
    for duty in range(0,1024, 5):
        pwm_led.duty(duty)
        time.sleep_ms(5)
    for duty in range(1023,-1, -5):
        pwm_led.duty(duty)
        time.sleep_ms(5)

Note

Pour que la tension varie plus vite, on fait varier le duty de 5 en 5 avec range(0, 1024, 5) . Pour décrémenter une valeur, on met un pas de -5 : range(1023,-1, -5) .