Pour ce projet, nous allons réaliser un feu tricolore et reproduire son fonctionnement. Nous allons voir étape par étape comment tester chacun des composants et comment développer le programme final.
C’est un projet simple pour bien commencer l’apprentissage de l’électronique et de la programmation avec Arduino.
Matériel
- Ordinateur
- Arduino UNO
- Câble USB A mâle vers USB B mâle
- Module feu tricolore (ou LEDs x3 + Résistances x3)
- Bouton poussoir (ou module bouton poussoir)
- Breadboard
- Câbles Dupont M/F
- Bouton poussoir x1
Objectif
Nous allons reproduire le fonctionnement d’un feu rouge. D’abord avec un mode automatique dans lequel les LEDs s’allume l’une après l’autre. Puis nous allons rajouter un bouton d’appel piéton pour forcer le passage au rouge.
Préparation et code de test de l’Arduino
Sans brancher les LEDs, nous pouvons déjà commencer à travailler sur l’algorithme de base pour tester la communication série et la programmation de l’Arduino. Vous pouvez suivre ce tutoriel pour configurer et programmer la carte Arduino.
int verte = 0; int orange = 1; int rouge = 2; void setup() { Serial.begin(9600); Serial.println("Feux rouge initialisé"); } void loop() { Serial.println("loop running"); delay(500); allumer(verte); delay(1000); eteindre(verte); allumer(orange); delay(1000); eteindre(orange); allumer(rouge); delay(1000); } void allumer(int color) { Serial.print("allumer led "); switch (color) { case 0: Serial.println("verte"); break; case 1: Serial.println("orange"); break; case 2: Serial.println("rouge"); break; } } void eteindre(int color) { Serial.print("eteindre led :"); switch (color) { case 0: Serial.println("verte"); break; case 1: Serial.println("orange"); break; case 2: Serial.println("rouge"); break; } }
Schéma de câblage
Le bouton est branché sur la pin 2, la LED1 sur la pin 9, lED2 sur la pin 10 et LED3 sur la pin 11. Notez bien la présence des résistances pour éviter d’endommager les composants. Avec le module feu tricolore, ces résistances ne sont pas nécessaires.
Code de gestion des LEDs
Une fois les LEDs branchées à l’Arduino, nous pouvons essayer de les allumer. La fonction utilisée pour contrôler une diode est digitalWrite() avec comme paramètre HIGH pour l’allumer, LOW pour l’éteindre. Il suffit de rajouter la fonction digitalWrite() à l’endroit désiré dans les fonctions allumer et éteindre.
L’objectif est de faire s’allumer la LED verte puis la orange puis la rouge après des intervalles de temps donnés.
Pour plus de lisibilité, nous plaçons les variables verte, orange, rouge dans un enum.
const int pinVerte = 9; const int pinOrange = 10; const int pinRouge = 11; enum couleur { VERTE, ORANGE, ROUGE }; int etatFeu = VERTE; void setup() { Serial.begin(9600); pinMode(pinVerte, OUTPUT); pinMode(pinRouge, OUTPUT); pinMode(pinOrange, OUTPUT); Serial.println("Feu tricolore initialisé"); } void loop() { Serial.println(F("Mode auto running")); eteindre (ROUGE); allumer (VERTE); delay (5000); eteindre (VERTE); allumer (ORANGE); delay (1000); eteindre (ORANGE); allumer (ROUGE); delay (3000); } void allumer(int color) { Serial.print("allumer led "); switch (color) { case VERTE: Serial.println("verte"); digitalWrite(pinVerte, HIGH); //analogWrite(pinVerte, 250); break; case ORANGE: Serial.println("orange"); digitalWrite(pinOrange, HIGH); //analogWrite(pinOrange, 250); break; case ROUGE: Serial.println("rouge"); digitalWrite(pinRouge, HIGH); //analogWrite(pinRouge, 250); break; default: digitalWrite(pinOrange, HIGH); //analogWrite(pinOrange, 250); break; } etatFeu = color; } void eteindre(int color) { Serial.print("eteindre led :"); switch (color) { case VERTE: Serial.println("verte"); digitalWrite(pinVerte, LOW); //analogWrite(pinVerte, 0); break; case ORANGE: Serial.println("orange"); digitalWrite(pinOrange, LOW); //analogWrite(pinOrange, 0); break; case ROUGE: Serial.println("rouge"); digitalWrite(pinRouge, LOW); //analogWrite(pinRouge, 0); break; default: digitalWrite(pinVerte, LOW); //analogWrite(pinVerte, 0); digitalWrite(pinOrange, LOW); //analogWrite(pinOrange, 0); // digitalWrite(pinRouge, LOW); //analogWrite(pinRouge, 0); // break; } }
Il est possible de moduler la luminosité de la LED en utilisant la fonction analogWrite() et une sortie PWM du microcontrôleur.
Code de gestion du bouton
Nous allons à présent tester le fonctionnement du bouton poussoir. L’objectif est que le feu tricolore change de couleur lorsqu’on appuie sur le bouton. Pour cela, il nous faut « écouter » l’état du bouton constamment. Une technique intéressante pour surveiller l’état d’un capteur est d’utiliser une interruption. Nous reprenons donc le code de ce tutoriel complet sur la gestion d’un bouton avec interruption.
const byte ledPin = 10; const byte interruptPin = 2; volatile byte state = LOW; void setup() { Serial.begin(9600); pinMode(ledPin, OUTPUT); pinMode(interruptPin, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(interruptPin), onEvent, FALLING); Serial.println(F("Système intialisé")); } void loop() { digitalWrite(ledPin, state); } void onEvent() { state = !state; Serial.print(F("Switch LED : ")); if (state) { Serial.println(F("ON")); } else { Serial.println(F("OFF")); } }
Pour d’autres façons de gérer le bouton poussoir, vous pouvez lire ce tutoriel.
Changement de la couleur du feu à l’aide du bouton
Nous allons combiner les deux codes précédents afin de modifier la couleur du feu tricolore lorsqu’on appuie sur le bouton.
const int pinVerte = 9; const int pinOrange = 10; const int pinRouge = 11; enum couleur { VERTE, ORANGE, ROUGE }; int etatFeu = VERTE; const byte btnPin = 2; int state = 0; void setup() { Serial.begin(9600); pinMode(pinVerte, OUTPUT); pinMode(pinRouge, OUTPUT); pinMode(pinOrange, OUTPUT); pinMode(btnPin, INPUT); attachInterrupt(digitalPinToInterrupt(btnPin), onEvent, FALLING); Serial.println("Feu tricolore initialisé"); } void loop() { switch (state) { case 0://mode automatique Serial.println(F("Mode auto")); eteindre (ROUGE); allumer (VERTE); delay (5000); eteindre (VERTE); allumer (ORANGE); delay (1000); eteindre (ORANGE); allumer (ROUGE); delay (3000); break; case 1:// mode manuel Serial.println(("Mode manuel")); delay (5000); eteindre (ROUGE); state = 0; break; } } void onEvent() { Serial.println("---> Bouton pressé"); eteindre(3);//eteindre tout allumer (ROUGE); state=1; } void allumer(int color) { Serial.print("allumer led "); switch (color) { case VERTE: Serial.println("verte"); digitalWrite(pinVerte, HIGH); //analogWrite(pinVerte, 250); break; case ORANGE: Serial.println("orange"); digitalWrite(pinOrange, HIGH); //analogWrite(pinOrange, 250); break; case ROUGE: Serial.println("rouge"); digitalWrite(pinRouge, HIGH); //analogWrite(pinRouge, 250); break; default: digitalWrite(pinOrange, HIGH); //analogWrite(pinOrange, 250); break; } } void eteindre(int color) { Serial.print("eteindre led : "); switch (color) { case VERTE: Serial.println("verte"); digitalWrite(pinVerte, LOW); //analogWrite(pinVerte, 0); break; case ORANGE: Serial.println("orange"); digitalWrite(pinOrange, LOW); //analogWrite(pinOrange, 0); break; case ROUGE: Serial.println("rouge"); digitalWrite(pinRouge, LOW); //analogWrite(pinRouge, 0); break; default: Serial.println(" tout"); digitalWrite(pinVerte, LOW); //analogWrite(pinVerte, 0); digitalWrite(pinOrange, LOW); //analogWrite(pinOrange, 0); // digitalWrite(pinRouge, LOW); //analogWrite(pinRouge, 0); // break; } }
Si vous testez ce code, vous allez vous rendre compte que le feu ne se comporte pas tout à fait comme prévu. Nous arrivons à forcer la couleur au rouge mais le fonctionnement automatique ne reprend pas son cours correctement. Cela est dû à la fonction delay() qui bloque le code. Pour pouvoir prendre en compte le bouton au moment où on appuie dessus, il va falloir modifier le code afin de se débarrasser de la fonction delay().
Modification du code
Pour supprimer la fonction delay(), nous pouvons utiliser un algorithme à l’aide de la fonction millis(). Nous allons reproduire la fonction delay à l’aide de la fonction millis sans bloquer le déroulement du code.
if((millis()-previousTime)>200){ previousTime=currentTime; Serial.println(F("action")); }
Pour cela, il faut aussi décomposer le fonctionnement du feu rouge en différents états et les intégrés dans les cas du switch. Un état pour le changement de couleur et un état pour le délai.
switch (state) { case 0: eteindre (ROUGE); allumer (VERTE); state++; previousMillis = millis(); break; case 1: if (millis() - previousMillis > 5000) { //delay (5000); state++; } break; case 2: eteindre (VERTE); allumer (ORANGE); state++; previousMillis = millis(); break; case 3: if (millis() - previousMillis > 1000) { //delay (1000); state++; } break; case 4: eteindre (ORANGE); allumer (ROUGE); state++; previousMillis = millis(); break; case 5: if (millis() - previousMillis > 3000) { //delay (3000); state = 0; } break; }
Code final complet
Une fois ces modifications faites, l’appui du bouton est pris en compte directement et le feu rouge peut reprendre son cours correctement.
const int pinVerte = 9; const int pinOrange = 10; const int pinRouge = 11; enum couleur { VERTE, ORANGE, ROUGE }; int etatFeu = VERTE; int state = 0; const byte btnPin = 2; int mode = 0; unsigned long previousMillis = 0; void setup() { Serial.begin(9600); pinMode(pinVerte, OUTPUT); pinMode(pinRouge, OUTPUT); pinMode(pinOrange, OUTPUT); pinMode(btnPin, INPUT); attachInterrupt(digitalPinToInterrupt(btnPin), onEvent, RISING); Serial.println("Feu tricolore initialisé"); } void loop() { switch (state) { case 0: eteindre (ROUGE); allumer (VERTE); state++; previousMillis = millis(); break; case 1: if (millis() - previousMillis > 5000) { //delay (5000); state++; } break; case 2: eteindre (VERTE); allumer (ORANGE); state++; previousMillis = millis(); break; case 3: if (millis() - previousMillis > 1000) { //delay (1000); state++; } break; case 4: eteindre (ORANGE); allumer (ROUGE); state++; previousMillis = millis(); break; case 5: if (millis() - previousMillis > 3000) { //delay (3000); state = 0; } break; } } void onEvent() { Serial.println("---> Bouton pressé"); if (etatFeu == VERTE) { Serial.println("Changement d'etat"); state = 2; } } void allumer(int color) { Serial.print("allumer led "); switch (color) { case VERTE: Serial.println("verte"); digitalWrite(pinVerte, HIGH); //analogWrite(pinVerte, 250); break; case ORANGE: Serial.println("orange"); digitalWrite(pinOrange, HIGH); //analogWrite(pinOrange, 250); break; case ROUGE: Serial.println("rouge"); digitalWrite(pinRouge, HIGH); //analogWrite(pinRouge, 250); break; default: digitalWrite(pinOrange, HIGH); //analogWrite(pinOrange, 250); break; } etatFeu = color; } void eteindre(int color) { Serial.print("eteindre led :"); switch (color) { case VERTE: Serial.println("verte"); digitalWrite(pinVerte, LOW); //analogWrite(pinVerte, 0); break; case ORANGE: Serial.println("orange"); digitalWrite(pinOrange, LOW); //analogWrite(pinOrange, 0); break; case ROUGE: Serial.println("rouge"); digitalWrite(pinRouge, LOW); //analogWrite(pinRouge, 0); break; default: digitalWrite(pinVerte, LOW); //analogWrite(pinVerte, 0); digitalWrite(pinOrange, LOW); //analogWrite(pinOrange, 0); // digitalWrite(pinRouge, LOW); //analogWrite(pinRouge, 0); // break; } }
N’hésitez pas à laisser un commentaire pour partager vos réalisations ou nous faire part de vos remarques. Vous pouvez aussi nous contacter pour toutes questions.
Application
- Reproduire un croisement de route avec 4 feux tricolores synchronisés
Source
- Reference Arduino
- Gestion d’un bouton poussoir
- Apprendre la programmation avec Arduino
- Gestion de 3 LEDs avec un bouton poussoir
- Gestion d’un bouton poussoir avec interruption
Retrouvez nos tutoriels et d’autres exemples dans notre générateur automatique de code
La Programmerie