par broche, en pratique. Soit une LED correctement calibrée.
40 mA
le maximum de la datasheet. Plus, et la broche grille.
Pour piloter plus de courant (un moteur, un ruban de LED, un relais), la broche ne fournit pas la puissance : elle commande un transistor, qui lui la fournit.
La broche n’impose qu’une tension sur la grille : le courant du moteur vient de sa propre alimentation. La 10 kΩ garde le moteur arrêté au démarrage ; la diode, deux slides plus loin.
Moteur, relais, électro-aimant : une bobine s’oppose à toute variation brutale de courant. Quand le MOSFET coupe, elle produit une pointe de plusieurs dizaines de volts, qui détruit le transistor.
La parade : une diode aux bornes de la charge, cathode côté +. Elle offre un chemin au courant le temps qu’il s’éteigne.
Charge inductive : une diode en parallèle, sans exception.
1N4007 pour un relais, une Schottky (1N5819) pour un moteur en PWM rapide.
Le mode par défaut d’OUTPUT. Deux transistors tirent activement la broche vers HIGHet vers LOW.
Open-drain
La broche ne peut que tirer vers LOW, ou relâcher. Indispensable sur un bus partagé comme l’I2C.
Deux composants en push-pull sur le même fil, l’un imposant 0 et l’autre 1 : c’est un court-circuit. L’open-drain règle ce problème, on le retrouvera au CM3 avec l’I2C.
Une broche en entrée non connectée est en haute impédance : presque aucun courant ne la traverse, et rien ne fixe sa tension.
Elle capte alors le bruit ambiant (un câble voisin, le secteur à 50 Hz, votre main qui s’approche) et sa lecture devient aléatoire. C’est l’état flottant.
Le symptôme est reconnaissable : le programme « détecte des appuis » que personne ne fait.
Les lamelles métalliques d’un bouton mécanique rebondissent pendant quelques millisecondes : une rafale de HIGH/LOW avant stabilisation, parfaitement visible à l’oscilloscope.
Un digitalRead() naïf compte alors plusieurs appuis là où vous n’en avez fait qu’un. Dans un menu de jeu, cela se traduit par une sélection qui saute deux lignes.
La parade : après un changement d’état, ignorer les lectures pendant 20 à 50 ms.
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) { // le signal vient de bouger
dernierChangement = millis();
dernierEtat = etat;
}
if (millis() - dernierChangement > ANTIREBOND && etat == LOW) {
// enfoncé et stable depuis 30 ms (vrai tant qu'il reste enfoncé)
}
}
Même motif qu’au CM1 : comparer millis() à une date mémorisée.
On le voit souvent : attendre 20 ms après la première lecture. Il fige tout le programme pendant 20 ms à chaque appui, et ne règle pas la répétition quand le bouton reste enfoncé. Avec un écran à rafraîchir 60 fois par seconde, ces 20 ms se voient : prenez tout de suite l’habitude de la version millis().
volatileboolappui=false;// écrite par l'ISR, lue par loop()voidIRAM_ATTRsurAppui(){// la routine d'interruption (ISR)appui=true;// lever le drapeau, rien de plus}voidsetup(){pinMode(BTN_PIN,INPUT_PULLUP);attachInterrupt(digitalPinToInterrupt(BTN_PIN),surAppui,FALLING);}voidloop(){if(appui){appui=false;/* traiter l'appui */}}
FALLING : front descendant, donc l’appui en INPUT_PULLUP (RISING et CHANGE existent aussi). IRAM_ATTR range l’ISR en RAM, toujours accessible.
SDA et SCL sur D3 et D4, SCK et MOSI sur D9 et D10 : un choix de routage, pas une obligation. La GPIO matrix permet de déplacer ces signaux ; seul le code change, comme SPI.begin(D9, -1, D10).
C’est le brochage de la future carte (TD3), plus le buzzer, présent seulement sur breadboard. Un programme écrit au TD2 tournera tel quel sur la carte soudée.
Une température, une position de joystick, une luminosité produisent des tensions qui varient en continu entre 0 et 3,3 V. Le microcontrôleur, lui, ne manipule que des entiers.
Le convertisseur analogique-numérique (ADC) fait la traduction.
intvaleur=analogRead(PIN_JOYSTICK_X);// 0 à 4095
Pas besoin de pinMode : analogRead() configure la broche lui-même.
intbrut=analogRead(PIN);// 0 à 4095, courbe imparfaiteintmv=analogReadMilliVolts(PIN);// tension corrigée, en mV
La réponse de l’ADC n’est pas une droite parfaite : elle s’écrase près de 0 V et près de la saturation, et varie d’une puce à l’autre. Chaque ESP32-S3 sort d’usine avec des coefficients de calibration gravés dans la puce : analogReadMilliVolts() les applique.
Joystick : analogRead() suffit, on calibre le centre soi-même. Tension d’une batterie ou d’un capteur : analogReadMilliVolts().
Sur ESP32, le bloc ADC2 partage du matériel avec la radio : dès que le Wi-Fi est actif, ses lectures échouent. Utilisez uniquement les broches ADC1, GPIO1 à GPIO10 : sur la XIAO, toutes les broches analogiques le sont. Le symptôme est déroutant : le montage marche parfaitement pendant des semaines, jusqu’au jour où vous activez le Wi-Fi pour le projet.
Le centre n’est jamais à 2048 : les seuils laissent une large zone morte.
enum crée un type qui ne peut prendre que les valeurs listées : plus lisible et plus sûr qu’un entier de 0 à 4. Il revient au CM3 avec la machine à états.
calibrateJoystick();// au démarrage, stick relâché : moyenne de 16 lecturesfloatnormalizeJoystick(intraw,intcenter){intoffset=raw-center;if(abs(offset)<JOYSTICK_DEADZONE)return0.0f;// zone morte (300)intrange=(offset>0)?(4095-center):center;returnconstrain((float)offset/range,-1.0f,1.0f);}
De -1 à +1, 0 au repos : la raquette avance d’autant plus vite que le stick est incliné.
map(x, a, b, c, d) passe x de [a, b] à [c, d] par une règle de trois :
$$
\text{résultat} = c + (x - a) \times \frac{d - c}{b - a}
$$
intlecture=analogRead(POT_PIN);// 0 à 4095intangle=map(lecture,0,4095,0,180);// servo : 0 à 180°intpwm=map(lecture,0,4095,0,255);// analogWrite : 0 à 255
Deux pièges : map() calcule en entiers (les décimales sont perdues), et ne borne pas son résultat. map(3800, 500, 3500, 0, 255) donne 280, hors de la plage d’analogWrite : constrain(pwm, 0, 255) le ramène à 255.
Exemple : potentiomètre à mi-course, lecture 2048, donc angle 90° et pwm 127.
Derrière, Arduino-ESP32 utilise le périphérique LEDC : 8 canaux matériels indépendants, fréquence et résolution configurables (jusqu’à 14 bits).
Le CPU n’intervient pas. Une fois le canal réglé, le signal est généré par le matériel, même si la loop() est occupée ailleurs. C’est tout l’intérêt d’un périphérique dédié.