Attention : 3,3 V, pas 5 V
Les GPIO de l’ESP32-S3 supportent 3,3 V maximum. Une broche mise en sortie produit 3,3 V - pas 5 V comme sur Arduino Uno. Un signal 5 V appliqué en entrée peut endommager la puce.
GPIO & monde numérique
Comprendre les GPIO numériques de l'ESP32-S3 - niveaux logiques, pull-up/pull-down et état flottant.
Pré-requis :
Jusqu’ici, le microcontrôleur réfléchissait dans son coin. Mais une puce qui ne fait que calculer ne sert à rien : pour être utile, elle doit agir sur le monde (allumer une LED, faire tourner un moteur) et le percevoir (savoir si tu appuies sur un bouton).
Ce contact avec le monde physique passe par les broches de la puce - ces petites pattes métalliques alignées sur les bords de la carte. Les plus polyvalentes s’appellent les GPIO, et ce concept est consacré aux plus simples d’entre elles : celles qui ne manipulent que du tout-ou-rien, comme un interrupteur mural qu’on bascule entre allumé et éteint. Pas de demi-mesure - et c’est justement ce qui rend le numérique si fiable.
À la fin de ce concept, tu sauras :
Le monde numérique ne connaît que deux états : 0 ou 1, LOW ou HIGH, 0 V ou 3,3 V. Tout signal intermédiaire est interprété selon un seuil.
Sur l’ESP32-S3 (logique 3,3 V) :
| État | Tension | Arduino |
|---|---|---|
| LOW | 0 V | 0 / false / LOW |
| HIGH | 3,3 V | 1 / true / HIGH |
Chaque broche GPIO (General Purpose Input/Output, broche d’entrée/sortie à usage général) peut être configurée en entrée ou en sortie par le logiciel.
pinMode(LED_PIN, OUTPUT); // broche configurée en sortie
pinMode(BTN_PIN, INPUT); // broche configurée en entrée
Une broche en sortie peut sourcer ou drainer du courant (le fournir ou l’absorber) pour piloter un composant.
digitalWrite(LED_PIN, HIGH); // LED allumée (3,3 V sur la broche)
digitalWrite(LED_PIN, LOW); // LED éteinte (0 V)
Courant maximal par broche ESP32-S3 : ~40 mA. En pratique, limiter à 12 mA avec une résistance série.
Calcul de la résistance pour une LED rouge (Vf, la tension de seuil de la LED, ≈ 2 V ; I = 10 mA) :
Valeur normalisée : 150 Ω (série E12).
Par défaut, OUTPUT configure la broche en push-pull : deux transistors internes permettent de tirer activement la broche à HIGH ou à LOW. C’est le mode utilisé jusqu’ici.
Il existe un second mode, open-drain : la broche ne peut que tirer vers LOW (un seul transistor, côté masse). Pour lire ou produire un HIGH, il faut une résistance de tirage (interne ou externe) qui « relâche » la broche vers HIGH quand personne ne la tire vers le bas.
pinMode(PIN, OUTPUT_OPEN_DRAIN); // la broche ne peut que tirer vers 0 V
digitalWrite(PIN, LOW); // tire activement à 0 V
digitalWrite(PIN, HIGH); // relâche la broche (haute impédance)
Push-pull (OUTPUT) |
Open-drain (OUTPUT_OPEN_DRAIN) |
|
|---|---|---|
| Peut tirer vers HIGH | Oui, activement | Non - nécessite un pull-up |
| Peut tirer vers LOW | Oui, activement | Oui, activement |
| Usage typique | LED, moteur, sortie numérique classique | Bus partagé (I2C), interfaçage avec un niveau logique différent |
Une broche en entrée mesure le niveau de tension présent sur la broche.
int etat = digitalRead(BTN_PIN); // retourne HIGH ou LOW
Une broche en entrée non connectée à rien est dans un état flottant : sa tension est indéterminée, elle peut lire HIGH ou LOW de façon aléatoire selon les interférences électromagnétiques.
flowchart TD
A["pinMode(PIN, INPUT)\nsans pull-up ni pull-down"] --> B["Broche en haute impédance\n(quasiment aucun courant ne peut y circuler)"]
B --> C{"Un signal externe\nimpose-t-il une tension ?"}
C -->|"Non - rien de branché"| D["Tension flottante\ncapte le moindre bruit ambiant"]
D --> E["digitalRead() imprévisible\nLOW, HIGH, ou oscille sans raison"]
C -->|"Oui - via une résistance de rappel"| F["Tension définie et stable\nLOW ou HIGH garanti au repos"]
Une broche en haute impédance n’a presque aucune résistance interne : la moindre interférence électromagnétique environnante (un câble voisin, le secteur 50 Hz, ta propre main qui s’approche) suffit à faire basculer sa lecture - d’où le terme « flottant » : rien ne fixe sa tension à une valeur précise.
Une résistance de rappel (pull) force la broche à un niveau défini quand aucun signal n’est appliqué.
La résistance relie la broche au +3,3 V. Au repos, la broche lit HIGH. Quand le bouton est pressé (connexion à GND), elle passe à LOW.
graph LR
V33["3,3 V"] -->|"R (10 kΩ)"| NODE(("Broche GPIO"))
NODE -->|"Bouton"| GND["GND"]
La résistance relie la broche au GND. Au repos, la broche lit LOW. Quand le bouton est pressé (connexion à +3,3 V), elle passe à HIGH.
graph LR
GND["GND"] -->|"R (10 kΩ)"| NODE(("Broche GPIO"))
NODE -->|"Bouton"| V33["3,3 V"]
L’ESP32-S3 intègre des résistances de pull-up (et pull-down) en interne, activables par logiciel - pas besoin de résistance externe dans la plupart des cas.
pinMode(BTN_PIN, INPUT_PULLUP); // pull-up interne activé (~45 kΩ)
// ou
pinMode(BTN_PIN, INPUT_PULLDOWN); // pull-down interne activé
Avec INPUT_PULLUP : le bouton doit connecter la broche à GND pour être détecté (logique inversée : LOW = pressé).
Quand tu presses un bouton mécanique, le contact ne s’établit pas net : les lamelles métalliques rebondissent pendant quelques millisecondes, générant une rafale de HIGH/LOW avant de se stabiliser. Un digitalRead() naïf voit alors plusieurs appuis là où tu n’en as fait qu’un.
La parade la plus simple est logicielle : après un changement d’état, on ignore les lectures pendant un court délai (20 à 50 ms), grâce à millis() (le nombre de millisecondes écoulées depuis le démarrage), le temps que le contact se stabilise.
const unsigned long ANTIREBOND = 30; // ms
int dernierEtat = HIGH;
unsigned long dernierChangement = 0;
void loop() {
int etat = digitalRead(BTN_PIN); // INPUT_PULLUP : LOW = pressé
if (etat != dernierEtat) {
dernierChangement = millis(); // le signal vient de bouger
dernierEtat = etat;
}
if (millis() - dernierChangement > ANTIREBOND && etat == LOW) {
// appui confirmé : stable depuis 30 ms
}
}
Scruter un bouton à chaque tour de loop() fonctionne, mais peut rater un appui si la boucle est occupée ailleurs. Une interruption exécute une petite fonction dès que la broche change, sans attendre (voir Architecture - interruptions).
volatile bool appui = false;
void IRAM_ATTR surAppui() { appui = true; } // ISR : la plus courte possible
void setup() {
pinMode(BTN_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(BTN_PIN), surAppui, FALLING);
}
L’ISR (Interrupt Service Routine) se contente de lever un drapeau ; le vrai traitement - et l’anti-rebond - se fait ensuite tranquillement dans loop().
Au-delà de digitalRead()/digitalWrite(), une broche peut être prise en charge par un périphérique - UART, SPI, I2C, PWM (LEDC)… Sur beaucoup de microcontrôleurs, chaque fonction est câblée en dur sur des broches précises (« fonction alternative » fixe).
L’ESP32-S3 est plus flexible : une GPIO matrix interne permet de router presque n’importe quel signal numérique de périphérique vers presque n’importe quelle broche, par logiciel.
Serial1.begin(115200, SERIAL_8N1, 16, 17); // UART1 routé sur GPIO16 (RX) / GPIO17 (TX)
// une autre paire de broches fonctionnerait tout aussi bien
Malgré la souplesse de la GPIO matrix, certaines broches ont un rôle réservé au démarrage ou au fonctionnement interne de l’ESP32-S3. Les détourner en GPIO ordinaire peut empêcher la carte de démarrer, de se flasher ou de communiquer en USB.
| Broches | Rôle réservé | Précaution |
|---|---|---|
| GPIO 0, 3, 45, 46 | Strapping - lues au reset pour choisir le mode de boot | Éviter, ou ne rien y imposer comme niveau au démarrage |
| GPIO 19, 20 | USB natif (D− / D+) | Éviter si tu utilises l’USB (flash, port série) |
| GPIO 43, 44 | UART0 par défaut (TX / RX du moniteur série) | Libres si le port série n’est pas utilisé, sinon à éviter |
| GPIO 26–32 | Reliées à la Flash SPI interne | Ne jamais utiliser |
| GPIO 33–37 | Utilisées par la PSRAM sur les modules « octal » | Éviter sur les modules équipés de PSRAM |
| Limite | Valeur ESP32-S3 |
|---|---|
| Courant max par broche | 40 mA (recommandé : ≤ 12 mA) |
| Tension max en entrée | 3,3 V |
Ne jamais connecter une charge inductive (moteur, relais - une charge qui stocke de l’énergie magnétique et renvoie des pics de tension à la coupure) directement sur un GPIO - toujours utiliser un transistor ou un driver (circuit de puissance intermédiaire).
Les GPIO de l’ESP32-S3 sont en logique 3,3 V : appliquer 5 V sur une entrée peut endommager la puce (voir l’avertissement plus haut). Pour dialoguer avec un composant 5 V, il faut adapter le niveau :
HIGH valide ; sinon, un level shifter s’impose.1. Une entrée non connectée lit des valeurs aléatoires. Comment y remédier ?
2. Avec INPUT_PULLUP, quel niveau lit-on quand le bouton est pressé ?
3. Pourquoi un digitalRead() compte-t-il parfois plusieurs appuis pour un seul ?
INPUT) ou sortie (OUTPUT).0 V (LOW) ou 3,3 V (HIGH) - maximum ~12 mA.INPUT_PULLUP / INPUT_PULLDOWN activent la résistance interne de l’ESP32-S3.LOW quand pressé.millis()) pour ne pas compter plusieurs appuis.attachInterrupt) réagit à un changement de broche sans scruter ; l’ISR reste minimale.