Leçon 3 / 8
Leçon 03 · Arduino

Entrées et sorties numériques

Une carte Arduino communique avec le monde extérieur via ses broches (pins). Chaque broche peut être configurée en entrée ou en sortie, et elle ne connaît que deux états : HIGH (5 V) ou LOW (0 V). C'est le principe du numérique.

1. pinMode — configurer une broche

Avant d'utiliser une broche, tu dois lui dire ce qu'elle est. C'est le rôle de pinMode(), appelée dans setup().

Arduino C++
// Syntaxe
pinMode(numéroBroche, mode);

// Les trois modes disponibles
pinMode(13, OUTPUT);       // broche en sortie (LED, relais…)
pinMode(2,  INPUT);        // broche en entrée (bouton avec résistance externe)
pinMode(2,  INPUT_PULLUP); // entrée avec résistance pull-up interne (plus simple)

OUTPUT — la broche pilote une charge (LED, relais, buzzer).
INPUT — la broche écoute un signal extérieur.
INPUT_PULLUP — entrée avec résistance pull-up interne (~50 kΩ). La logique est inversée : LOW = bouton pressé.

2. Sortie numérique : allumer une LED

digitalWrite(broche, valeur) place la broche à HIGH (5 V) ou LOW (0 V). C'est la manière la plus simple de contrôler une LED.

⚠️

Toujours mettre une résistance en série avec une LED. Sans elle, la LED tire un courant excessif et brûle — et peut endommager la broche Arduino. Pour une LED standard alimentée en 5 V, utilise une résistance de 220 Ω à 470 Ω. Calcul : R = (Valim − Vf) / If → (5 − 2) / 0,02 = 150 Ω minimum. En pratique, 220 Ω est une valeur sûre et courante.

Arduino C++
// LED sur la broche 13 (avec résistance 220 Ω en série)
const int PIN_LED = 13;

void setup() {
  pinMode(PIN_LED, OUTPUT);
}

void loop() {
  digitalWrite(PIN_LED, HIGH); // LED allumée
  delay(1000);                 // attendre 1 seconde
  digitalWrite(PIN_LED, LOW);  // LED éteinte
  delay(1000);                 // attendre 1 seconde
}

Ce programme fait clignoter la LED intégrée (broche 13 sur l'Arduino Uno). delay(1000) bloque l'exécution pendant 1000 ms (1 seconde). On verra plus loin pourquoi c'est une mauvaise habitude à long terme.

3. Entrée numérique : lire un bouton

digitalRead(broche) renvoie HIGH (1) ou LOW (0) selon l'état de la broche. On l'utilise typiquement avec un bouton-poussoir.

Arduino C++
const int PIN_BTN = 2;
const int PIN_LED = 13;

void setup() {
  pinMode(PIN_BTN, INPUT_PULLUP); // pull-up interne activé
  pinMode(PIN_LED, OUTPUT);
}

void loop() {
  int etat = digitalRead(PIN_BTN);

  if (etat == LOW) {          // LOW = bouton pressé (logique inversée)
    digitalWrite(PIN_LED, HIGH);
  } else {
    digitalWrite(PIN_LED, LOW);
  }
}

Montage : une patte du bouton sur la broche 2, l'autre patte sur GND. Avec INPUT_PULLUP, pas besoin de résistance externe.

4. Résistances pull-up et pull-down

Quand un bouton est ouvert, la broche d'entrée n'est connectée à rien. Elle "flotte" et capte des parasites électriques : son état est aléatoire. Une résistance pull-up ou pull-down force un état stable par défaut.

Schéma (texte)
// PULL-DOWN (résistance externe vers GND)
// 5V ── Bouton ── Broche ── R (10 kΩ) ── GND
// État par défaut : LOW  |  Bouton pressé : HIGH

// PULL-UP (résistance externe vers 5V)
// 5V ── R (10 kΩ) ── Broche ── Bouton ── GND
// État par défaut : HIGH  |  Bouton pressé : LOW

// PULL-UP INTERNE Arduino (pas de résistance externe)
pinMode(broche, INPUT_PULLUP);
// Même logique : défaut HIGH, pressé LOW

La résistance interne de l'Arduino (~50 kΩ) est suffisante pour la plupart des boutons. Elle simplifie le montage : un seul fil relie le bouton à la broche, l'autre patte va au GND.

💡

Règle pratique : utilise toujours INPUT_PULLUP pour les boutons. Tu n'as besoin d'une résistance externe pull-down (10 kΩ vers GND) que si tu as absolument besoin de la logique "HIGH = pressé", par exemple pour être compatible avec d'autres composants.

5. Le rebond (debounce)

Quand tu appuies sur un bouton mécanique, les contacts rebondissent pendant quelques millisecondes avant de se stabiliser. L'Arduino est si rapide qu'il détecte des dizaines de pressions là où il n'y en a eu qu'une.

La solution logicielle classique : ignorer les changements d'état pendant un délai de stabilisation (~20 ms) grâce à millis().

Arduino C++
const int  PIN_BTN        = 2;
const int  PIN_LED        = 13;
const unsigned long DELAI_DEBOUNCE = 20; // ms

int           etatPrecedent  = HIGH;
int           etatLED        = LOW;
unsigned long dernierChangement = 0;

void setup() {
  pinMode(PIN_BTN, INPUT_PULLUP);
  pinMode(PIN_LED, OUTPUT);
}

void loop() {
  int lecture = digitalRead(PIN_BTN);

  // Si l'état a changé, mémoriser le moment
  if (lecture != etatPrecedent) {
    dernierChangement = millis();
  }

  // Si l'état est stable depuis DELAI_DEBOUNCE ms, le prendre en compte
  if ((millis() - dernierChangement) > DELAI_DEBOUNCE) {
    if (lecture == LOW) {         // bouton pressé, stable
      etatLED = !etatLED;         // basculer la LED
      digitalWrite(PIN_LED, etatLED);
    }
  }

  etatPrecedent = lecture;
}

Chaque fois que le bouton change d'état, on note le timestamp avec millis(). On ne prend la décision que si l'état est resté stable 20 ms — suffisant pour ignorer les rebonds.

6. Plusieurs LEDs : séquence et feux de circulation

On peut contrôler autant de LEDs que de broches disponibles. Exemple classique : simuler des feux de circulation (rouge → orange → vert).

Arduino C++
// Feux de circulation — broche 9 = rouge, 10 = orange, 11 = vert
const int ROUGE  = 9;
const int ORANGE = 10;
const int VERT   = 11;

void setup() {
  pinMode(ROUGE,  OUTPUT);
  pinMode(ORANGE, OUTPUT);
  pinMode(VERT,   OUTPUT);
}

void allumerSeul(int broche) {
  digitalWrite(ROUGE,  LOW);
  digitalWrite(ORANGE, LOW);
  digitalWrite(VERT,   LOW);
  digitalWrite(broche, HIGH);
}

void loop() {
  allumerSeul(ROUGE);   delay(3000); // rouge 3 s
  allumerSeul(ORANGE);  delay(1000); // orange 1 s
  allumerSeul(VERT);    delay(3000); // vert 3 s
}

La fonction allumerSeul() éteint toutes les LEDs puis allume la bonne. Ce schéma fonctionne bien ici car on n'a qu'une tâche à gérer. Dès qu'il y en a plusieurs, delay() devient un problème.

7. millis() vs delay() : le multi-tâche sans blocage

delay(n) bloque tout le programme pendant n millisecondes. Pendant ce temps, l'Arduino ne peut rien faire d'autre — ni lire un bouton, ni envoyer des données.

millis() renvoie le nombre de millisecondes écoulées depuis le démarrage (type unsigned long). Il n'arrête rien : il permet de mesurer le temps sans bloquer.

Arduino C++
// Blink sans delay() — pattern non-bloquant
const int          PIN_LED   = 13;
const unsigned long INTERVALLE = 500; // ms entre chaque bascule

unsigned long dernierBlink = 0;
int           etatLED      = LOW;

void setup() {
  pinMode(PIN_LED, OUTPUT);
}

void loop() {
  unsigned long maintenant = millis();

  if (maintenant - dernierBlink >= INTERVALLE) {
    dernierBlink = maintenant;
    etatLED = !etatLED;                  // basculer
    digitalWrite(PIN_LED, etatLED);
  }

  // Ici on peut faire autre chose pendant que la LED clignote !
  // Par exemple lire un bouton, envoyer une donnée série, etc.
}
⚠️

Attention au débordement de millis() : après environ 49 jours, le compteur revient à 0. Le calcul maintenant - dernierBlink reste correct même lors du débordement, tant que les deux variables sont de type unsigned long — ne jamais utiliser int pour stocker une valeur de millis().

Le principe : à chaque tour de loop(), on vérifie si assez de temps s'est écoulé. Si oui, on agit et on met à jour le timestamp. Sinon, on continue. La boucle tourne des milliers de fois par seconde, parfaitement disponible pour d'autres tâches.

// À retenir
  • pinMode(broche, OUTPUT / INPUT / INPUT_PULLUP) configure la broche dans setup().
  • digitalWrite(broche, HIGH/LOW) pilote une sortie numérique.
  • digitalRead(broche) lit une entrée numérique (0 ou 1).
  • Toujours une résistance de 220–470 Ω en série avec une LED pour limiter le courant.
  • INPUT_PULLUP active la résistance interne : logique inversée (LOW = pressé).
  • Le rebond mécanique s'élimine en filtrant les changements d'état sur ~20 ms avec millis().
  • millis() est non-bloquant ; delay() bloque tout — préférer millis() dès qu'on gère plusieurs choses à la fois.