← Retour au chapitre

Étape 3 / 3

Exo 9 : Feu tricolore complet

Fonctions personnalisées, machine à états et bouton piéton + buzzer.

Chapitres précédents non terminés
Pour un apprentissage optimal, termine d'abord : Boucles et tableaux

Exo 9 : Feu tricolore complet avec bouton piéton

C'est le projet de synthèse du chapitre ! Tu vas combiner tout ce que tu as appris : LEDs, digitalRead, toggle, debounce, et tu vas découvrir un nouveau concept puissant — la machine à états.

Analogie : un séquenceur d'états, c'est exactement comme le plan de vol d'un drone — décollage → croisière → approche → atterrissage. Chaque état a ses règles et déclenche le suivant quand les conditions sont remplies.

Simulation du feu tricolore

Observe le cycle du feu et demande le passage piéton :

🚶

État : VERT

La machine à états

Le feu tricolore est un exemple parfait de machine à états (state machine). L'idée : le système est toujours dans un état précis, et des conditions déclenchent les transitions.

VERTJAUNEROUGEPIÉTONbouton3s5s4s → retour

Le feu reste VERT jusqu'à ce qu'un piéton appuie. Ensuite : JAUNE (3s) → ROUGE (5s) → PIÉTON (4s + buzzer) → retour au VERT.

Schéma du circuit

3 LEDs (rouge D4, jaune D5, verte D6) + bouton piéton D2. Le buzzer (D8) est ajouté dans le montage.

D4→R→LED(R) | D5→R→LED(J) | D6→R→LED(V) | D2→BTN→GND

D4220ΩD5220ΩD6220ΩD2

Montage pas à pas

LED rouge en colonne 4, jaune en 8, verte en 12. Chacune avec résistance 220Ω verticale traversant le fossé. Câbles vers D4 (rouge), D5 (jaune), D6 (vert). GND partagé.

++151015202530abcdeabcdefghijfghij151015202530++
100%

Fonctions personnalisées

Au lieu de répéter du code, on crée des fonctions pour chaque action du feu :

void allumerVert() {
  digitalWrite(LED_R, LOW);
  digitalWrite(LED_J, LOW);
  digitalWrite(LED_V, HIGH);
}

void allumerJaune() {
  digitalWrite(LED_R, LOW);
  digitalWrite(LED_J, HIGH);
  digitalWrite(LED_V, LOW);
}

void allumerRouge() {
  digitalWrite(LED_R, HIGH);
  digitalWrite(LED_J, LOW);
  digitalWrite(LED_V, LOW);
}

Créer des fonctions rend le code lisible et réutilisable. Au lieu de 3 digitalWrite à chaque transition, on appelle simplement allumerVert().

Nouveau : switch / case

Tu connais déjà if / else pour tester une condition. Mais quand on a plusieurs valeurs possibles pour une même variable, on utilise switch — c'est plus lisible qu'une chaîne de if/else :

// Avec if/else (lourd) :
if (etat == 0) { ... }
else if (etat == 1) { ... }
else if (etat == 2) { ... }

// Avec switch (propre) :
switch (etat) {
  case 0:
    // Code pour état 0
    break;
  case 1:
    // Code pour état 1
    break;
  case 2:
    // Code pour état 2
    break;
}

N'oublie pas le break; à la fin de chaque case ! Sans lui, le code "tombe" dans le case suivant (fall-through).

Code : la machine à états

On utilise un enum (ici des constantes) pour nommer chaque état, et un switch dans loop() pour gérer les transitions :

const int VERT = 0;
const int JAUNE = 1;
const int ROUGE = 2;
const int PIETON = 3;

int etat = VERT;
unsigned long dernierChangement = 0;
bool demandeP = false;

void loop() {
  // Lire le bouton piéton
  if (digitalRead(BTN) == LOW && !demandeP) {
    demandeP = true;
  }

  unsigned long t = millis() - dernierChangement;

  switch (etat) {
    case VERT:
      allumerVert();
      if (demandeP) {
        etat = JAUNE;                // → transition !
        dernierChangement = millis();
      }
      break;

    case JAUNE:
      allumerJaune();
      if (t > 3000) {
        etat = ROUGE;
        dernierChangement = millis();
      }
      break;

    case ROUGE:
      allumerRouge();
      if (t > 5000) {
        etat = PIETON;
        dernierChangement = millis();
      }
      break;

    case PIETON:
      allumerRouge();
      tone(8, 1000, 100);  // Bip buzzer
      if (t > 4000) {
        demandeP = false;
        etat = VERT;
        dernierChangement = millis();
      }
      break;
  }
}

Exercice : complète les transitions

Remplis les trous pour compléter la machine à états. Quel est l'état suivant après chaque condition ?

1. Après VERT, quand le piéton appuie, on passe à quel état ?

case VERT: allumerVert(); if (demandeP) { = ; }

2. Après ROUGE (5 secondes), on passe à quel état ?

case ROUGE: allumerRouge(); if (t > 5000) { = ; }

Regarde le diagramme d'états ci-dessus : VERT → ??? → ROUGE → ???

Défis bonus

🚶 Défi : Feu piéton complet

Dans un vrai carrefour, les piétons ont leur propre feu avec deux LEDs :

  • LED rouge piéton (D9) : ne traverse PAS
  • LED verte piéton (D10) : tu peux traverser

À toi de coder ! Modifie la machine à états pour que :

  • • Quand les voitures ont le vert → piéton = rouge
  • • Pendant la phase PIÉTON → piéton = vert + buzzer bip-bip
  • • Ajoute un clignotement du vert piéton les 2 dernières secondes (prévient que ça va changer)

Indices pour le montage :

const int LED_P_R = 9;  // LED piéton rouge
const int LED_P_V = 10; // LED piéton verte

Buzzer mélodique

Remplace le simple bip par une vraie mélodie piéton avec tone(pin, fréquence, durée). Essaie d'alterner 880 Hz et 1320 Hz comme les vrais feux sonores.

Mode nuit

Ajoute un 2ème bouton (D3). Quand on l'appuie, le feu passe en mode jaune clignotant : delay(500) entre ON et OFF.

À retenir

  • Une machine à états organise le programme en états distincts avec des transitions claires.
  • Le switch/case est parfait pour coder une machine à états en C Arduino.
  • Les fonctions personnalisées (allumerVert()) rendent le code lisible et maintenable.
  • millis() permet de gérer des temporisations sans bloquer le programme (contrairement à delay()).
  • tone(pin, freq, durée) fait sonner un buzzer piézo.

Récapitulatif du chapitre 7

  • digitalRead() lit l'état d'un pin : HIGH ou LOW.
  • INPUT_PULLUP stabilise un bouton : HIGH au repos, LOW quand appuyé.
  • Le debounce avec millis() élimine les rebonds mécaniques.
  • Un toggle alterne ON/OFF grâce à une variable booléenne.
  • Une machine à états organise un programme complexe en états et transitions.
  • Les fonctions personnalisées rendent le code lisible et réutilisable.

Tu sais maintenant lire des entrées, gérer les rebonds et concevoir des programmes avec une logique d'états. Prêt pour les capteurs analogiques !

Valide cette étape quand tu as terminé la lecture et la manipulation.

← Exo 8 : Interrupteur intelligent Aller au quiz du chapitre →

Electro-Lab - support pédagogique Arduino (MVP).

IFOSUP Wavre - Cours Drones et Robotique.