Que ce soit pour contrôler l'intensité lumineuse d'une LED, la vitesse de rotation d'un moteur ou la position angulaire d'un servomoteur, il est souvent utile de créer un signal modulé en largeur d'impulsion (MLI, ou PWM pour Pulse Width Modulation).
Un signal PWM alterne entre 0 V et 3,3 V. Son rapport cyclique est le pourcentage du temps total pendant lequel il se trouve à 3,3 V.
Voici donc un petit tuto sur la création et le contrôle d'un signal PWM avec l'EPS32.
Avant d'aller plus loin, rappelons que
j'utilise l'IDE Arduino pour programmer l'ESP32.
"analogWrite" ne fonctionne pas
Si vous avez l'habitude de produire des signaux PWM avec une carte Arduino, vous supposerez probablement que l'ESP32 se débrouillera avec une commande du genre "analogWrite(16,100)".
Hé bien non! Toute tentative d'utiliser la fonction analogWrite avec l'ESP32 cause une erreur de compilation: "'analogWrite' was not declared in this scope".
C'est peut-être une bonne chose, remarquez: puisque l'ESP32 comporte un DAC (convertisseur numérique/analogique), il est possible de générer un véritable signal de sortie analogique grâce à la fonction DACWrite, alors que le signal PWM généré par une carte Arduino avec la fonction analogWrite n'est pas, à proprement parler, un véritable signal analogique.
21 broches peuvent être utilisées pour du PWM
En ce qui concerne les broches GPIO, nous avons l'embarras du choix: n'importe quelle broche capable d'être configurée comme sortie peut être utilisée pour produire un signal PWM. Nous excluons les broches GPIO 34 à 39 (qui ne peuvent être configurées qu'en entrée), ce qui laisse tout de même, sur la carte que j'utilise, 21 broches pouvant produire un signal PWM.
16 canaux PWM
Doit-on en déduire qu'il est possible de générer 21 signaux PWM indépendants? Pas tout à fait: l'ESP32 comporte 16 canaux PWM.
Ces canaux sont numérotés de 0 à 15. Comme nous le verrons plus loin, lorsqu'on désire produire un signal PWM sur une broche, on doit associer cette broche à un des 16 canaux au moyen de la fonction ledcAttachPin().
3 fonctions essentielles
Pour générer et contrôler notre signal PWM, notre sketch dispose de 3 fonctions LEDc (pour "LED control" puisqu'elles sont prévues avant tout pour contrôler l'intensité lumineuse d'une LED): ledcAttachPin, ledcSetup et ledcWrite.
- ledcAttachPin(broche GPIO, canal)
Cette fonction sert à associer une broche GPIO à l'un des 16 canaux GPIO, qui sont numérotés de 0 à 15. Par exemple, si je désire produire un signal PWM sur la broche GPIO 18, "ledcAttachPin(18, 0)" fera en sorte que le signal généré par le canal 0 sera acheminé à la broche 18. Si j'ai besoin d'un deuxième signal PWM différent du premier, j'utilise pour ce deuxième signal un numéro de broche et un numéro de canal différents. En général, cette fonction est placée dans la partie setup() du programme, puisqu'il est rarement utile de modifier cette assignation en cours d'exécution.
- ledcSetup(canal, fréquence, résolution)
Cette fonction permet de régler la fréquence et la résolution d'un canal PWM. Le canal continue d'être un entier situé entre 0 et 15. La fréquence est en hertz; elle est typiquement de l'ordre du kilohertz lorsqu'on contrôle la luminosité d'une LED. La résolution, qui peut prendre n'importe quelle valeur entière située entre 1 et 13, détermine le nombre valeurs distinctes pouvant être prises par le rapport cyclique.
Par exemple: avec une résolution de 12 bits, le rapport cyclique pourra prendre 212 = 4096 valeurs différentes, alors qu'avec une résolution de 8 bits, le nombre de valeurs possibles ne sera que de 28= 256.
Par exemple, l'expression "ledcSetup(0, 5000, 12)" règle le canal PWM numéro 0 à une fréquence de 5000 Hz, avec une résolution de 12 bits. Si vous n'avez pas besoin de modifier la fréquence pendant l'exécution du programme, vous placerez probablement cette fonction dans la partie setup().
Quel est l'avantage d'utiliser une résolution plus faible que le maximum permis? Atteindre une fréquence plus élevée! La fréquence maximale permise pour un signal PWM généré par l'ESP32 est de 40 megaHertz! Mais à cette fréquence, la seule résolution possible est de 1 bit (permettant un rapport cyclique de 50% et rien d'autre). Plus la fréquence est grande, plus la résolution maximale possible est petite.
- ledcWrite(canal, rapport cyclique)
Cette fonction permet de régler le rapport cyclique du signal PWM du canal spécifié. Par exemple, "ledcWrite(0, 250)" règle à 250 le rapport cyclique du canal 0.
Attention: le résultat de cette commande dépend de la résolution préalablement réglée avec la fonction ledcSetup: si la résolution est de 12 bits, 250/2
12 correspond à un rapport cyclique d'environ 6%; si la résolution est de 10 bits, 250/2
10 correspond plutôt à un rapport cyclique de 24%, et le rapport cyclique sera de 98% (250/2
8 ) à une résolution de 8 bits.
Un sketch minimaliste
Le sketch ci-dessous constitue le strict minimum pour générer un signal PWM (qui, dans ce cas, demeure identique pendant toute l'exécution du programme).
Dans ce sketch, j'ai d'abord lié la broche GPIO 18 au canal PWM 0, puis j'ai réglé le canal 0 à une fréquence de 5000 Hz et une résolution de 12 bits. Finalement, j'ai réglé le rapport cyclique à 50% (2048 est la moitié de 2
12 ).
Observations
J'ai ensuite branché un oscilloscope à l'ESP32 afin d'observer le signal PWM généré.
Tout d'abord, le résultat de mon sketch sans modification: fréquence de 5000 Hz, résolution de 12 bits, rapport cyclique à 50%,
On obtient un signal dont le rapport cyclique est de 50%: la moitié du temps à 0 V, et la moitié du temps à 3,3 V:
La fonction statistique de mon oscilloscope confirme la fréquence de 5 kHz et le rapport cyclique de 50%.
Deuxième essai: cette fois, je modifie le rapport cyclique pour qu'il devienne 25%:
Résultat: la tension est de 3,3 V pendant un quart de cycle, et nulle ensuite.
J'ai ensuite doublé la fréquence (pour qu'elle soit de 10 kHz), et réglé le rapport cyclique à 75%.
Finalement, j'ai réglé la résolution à 8 bits. Pour un rapport cyclique de 50%, il faut maintenant utiliser 128.
Un potentiomètre pour régler le rapport cyclique
Terminons avec un sketch classique qui permet de modifier le rapport cyclique d'un signal PWM en tournant un potentiomètre. Ce sketch peut servir, par exemple, à varier la luminosité d'une LED.
Le circuit est constitué d'un potentiomètre relié à la broche GPIO 15, et d'une LED (accompagnée d'une résistance de protection) branchée à la broche GPIO 18.
Rien de bien compliqué ici: nous réglons le rapport cyclique de la broche GPIO 18 à la valeur lue par la broche GPIO 15. En tournant le potentiomètre, l'intensité lumineuse de la LED change. Puisque la résolution du canal PWM et celle de l'ADC sont toutes les deux de 12 bits, aucune conversion n'est nécessaire; les deux résultats prennent des valeurs situées entre 0 et 4095.
Yves Pelletier (Twitter, Facebook)