--- title: "Module 3 — Signaux analogiques : PWM & ADC" --- ## Objectifs du module - Comprendre le principe du PWM (modulation de largeur d'impulsion) et son usage sur ESP32-S3 via l'API LEDC. - Réaliser un variateur de luminosité et un contrôle de servomoteur. - Comprendre le fonctionnement du convertisseur analogique-numérique (ADC) et ses limites. - Lire un potentiomètre et convertir la valeur brute en unité physique. ## 1. Qu'est-ce que le PWM ? Le PWM (Pulse Width Modulation) simule une sortie analogique en faisant varier rapidement le rapport cyclique (duty cycle) d'un signal carré : plus la portion « HIGH » est longue par rapport à la période, plus la valeur moyenne perçue (tension, luminosité, vitesse) est élevée. C'est la technique utilisée pour faire varier la luminosité d'une LED ou piloter un servomoteur. ![Le rapport cyclique fixe la tension moyenne perçue par la charge (LED, moteur)](../schemas/svg/m03-pwm-rapport-cyclique.svg){#fig-m03-pwm-rapport-cyclique} ## 2. Le PWM sur ESP32-S3 : l'API LEDC Contrairement à un Arduino Uno où `analogWrite()` suffit, l'ESP32 utilise un contrôleur matériel dédié appelé LEDC (LED Control), plus flexible (fréquence et résolution configurables) mais nécessitant une configuration explicite. Depuis les versions récentes du core Arduino-ESP32, une API simplifiée `analogWrite()` est également disponible et gère LEDC en interne — nous verrons les deux approches. ### 2.1 Approche simplifiée : `analogWrite()` ```cpp #define LED_PIN 4 void setup() { // Rien de particulier a configurer avec l'API simplifiee } void loop() { for (int duty = 0; duty <= 255; duty++) { analogWrite(LED_PIN, duty); // 0 = eteint, 255 = pleine puissance delay(10); } for (int duty = 255; duty >= 0; duty--) { analogWrite(LED_PIN, duty); delay(10); } } ``` ### 2.2 Approche explicite : API LEDC (contrôle fin) Utile lorsqu'on a besoin d'une fréquence ou d'une résolution précise (par exemple pour piloter un servomoteur, qui attend une fréquence de 50 Hz). ![Commande d'un servomoteur : la largeur de l'impulsion (1 à 2 ms) fixe l'angle](../schemas/svg/m03-servo-50hz.svg){#fig-m03-servo-50hz} ```cpp #define LED_PIN 4 #define PWM_FREQ 5000 // 5 kHz #define PWM_RES 8 // resolution 8 bits (0-255) void setup() { ledcAttach(LED_PIN, PWM_FREQ, PWM_RES); } void loop() { for (int duty = 0; duty <= 255; duty++) { ledcWrite(LED_PIN, duty); delay(10); } } ``` ::: {.callout-note title="Version du core Arduino-ESP32"} L'API LEDC a changé entre les versions 2.x et 3.x du core Arduino-ESP32 (l'ancienne API utilisait des numéros de canal explicites via ledcSetup/ledcAttachPin). Vérifiez la version installée dans le gestionnaire de cartes si le code ci-dessus ne compile pas, et adaptez-vous à la documentation correspondante. ::: ## 3. Exercice : variateur de luminosité avec potentiomètre Nous allons combiner PWM et lecture analogique : la position d'un potentiomètre définit la luminosité d'une LED. ![Câblage de l'exercice : potentiomètre sur GPIO1 (ADC1), LED sur GPIO4 (PWM)](../schemas/svg/m03-montage-variateur.svg){#fig-m03-montage-variateur} ## 4. Le convertisseur analogique-numérique (ADC) L'ADC convertit une tension continue (0 à 3,3 V) en une valeur numérique. L'ESP32-S3 dispose d'un ADC 12 bits, soit une résolution de 4096 valeurs possibles (0 à 4095). ![Conversion analogique-numérique puis mise à l'échelle avec map()](../schemas/svg/m03-adc-quantification.svg){#fig-m03-adc-quantification} | Caractéristique | Valeur | |-----------------------------------|----------------------------------------| | Résolution native | 12 bits (0 à 4095) | | Plage de tension | 0 à 3,3 V (selon atténuation configurée) | | Unité ADC utilisable en Wi-Fi actif | ADC1 uniquement (ADC2 partagé avec le Wi-Fi) | | Fonction de lecture | `analogRead(pin)` | ::: {.callout-warning title="Limitation importante : ADC2 et Wi-Fi"} L'ADC2 de l'ESP32 partage des ressources internes avec le module Wi-Fi. Si le Wi-Fi est actif (voir Module 7), les lectures sur les broches ADC2 deviennent peu fiables voire impossibles. Pour tout projet connecté utilisant l'analogique, privilégiez les broches de l'ADC1 (généralement GPIO1 à GPIO10 sur l'ESP32-S3). ::: ### 4.1 Lire un potentiomètre ```cpp #define POT_PIN 1 // Broche ADC1 void setup() { Serial.begin(115200); } void loop() { int valeurBrute = analogRead(POT_PIN); // 0 a 4095 float tension = valeurBrute * (3.3 / 4095.0); // conversion en volts Serial.printf("Brut: %d Tension: %.2f V\n", valeurBrute, tension); delay(200); } ``` ### 4.2 Exercice combiné : variateur de LED par potentiomètre Utilisez la valeur lue sur le potentiomètre (0-4095) pour piloter la luminosité d'une LED en PWM (0-255) en convertissant l'échelle avec la fonction `map()`. ```cpp #define POT_PIN 1 #define LED_PIN 4 void setup() { ledcAttach(LED_PIN, 5000, 8); Serial.begin(115200); } void loop() { int brut = analogRead(POT_PIN); int duty = map(brut, 0, 4095, 0, 255); ledcWrite(LED_PIN, duty); Serial.printf("Potentiometre: %d -> PWM: %d\n", brut, duty); delay(50); } ``` ## 5. Aller plus loin : appliquer le PWM à la LED NeoPixel Pour rappel (Module 2), la LED NeoPixel ne se pilote pas avec analogWrite ou ledcWrite : elle utilise un protocole numérique dédié (WS2812) géré par la bibliothèque Adafruit_NeoPixel, dont la fonction `setBrightness()` joue un rôle équivalent à celui du PWM pour l'intensité globale. Reliez les deux notions : adaptez l'exercice du variateur pour que ce soit cette fois la luminosité de la LED NeoPixel qui varie selon le potentiomètre. ```cpp #include #define POT_PIN 1 #define NEOPIXEL_PIN 48 Adafruit_NeoPixel pixel(1, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800); void setup() { pixel.begin(); pixel.setPixelColor(0, pixel.Color(255, 255, 255)); } void loop() { int brut = analogRead(POT_PIN); int luminosite = map(brut, 0, 4095, 0, 255); pixel.setBrightness(luminosite); pixel.show(); delay(50); } ``` ## Checklist de fin de module - [ ] Je sais expliquer le principe du duty cycle en PWM. - [ ] Je sais configurer une sortie PWM avec analogWrite ou l'API LEDC. - [ ] Je connais la résolution et les limites de l'ADC de l'ESP32-S3 (notamment ADC2 + Wi-Fi). - [ ] J'ai réalisé le variateur de luminosité piloté par potentiomètre, sur LED classique et sur NeoPixel.