Semaforo pedonale
Il circuito già realizzato può essere scaricato da https://www.tinkercad.com/things/8XXacsc0DwU
Si vuole gestire un semaforo pedonale per l'attraversamento di una strada. Sono presenti:
-
un semaforo per le auto (luci rossa, gialla e verde)
-
un semaforo per i pedoni con insegna luminosa “ALT” (rossa) e “AVANTI” (verde)
-
due pulsanti ai lati della strada per la chiamata pedoni
Partendo da semaforo verde per le auto e ALT per i pedoni il funzionamento è questo:
-
la pressione di uno dei due pulsanti prenota l'attraversamento pedonale
-
dopo 10 secondi si spegne il verde e si accende il giallo
-
trascorsi 5 secondi si spegne il giallo e si accende il rosso, per i pedoni si accende AVANTI e si spegne ALT
-
trascorsi 10 secondi si spegne il rosso e si accende il verde, per i pedoni si spegne AVANTI e si accende ALT
Diagramma temporale:
Diagramma SFC:
Realizzazione con Arduino UNO R3
Lo schema del circuito è qui sotto riportato, Quando lo si realizza, sia che si tratti di una simulazione, sia che si tratti di un circuito reale, conviene operare nella seguente sequenza:
- Si posizionano le 2 breadborad, NON si inserisce l'Arduino
- Si collegano tra loro massa e Vcc nelle breadboard
- Si realizza il circuito di comando dei due semafori automobilistici, le resistenze dei led sono da 330 Ohm
- Si realizza il circuito di comando dei due semafori pedonali, le resistenze dei led sono da 330 Ohm
- Si realizza il circuito di pulsanti di chiamata, le resistenze dei pulsanti sono da 1 KOhm
- Si inserisce l'Arduino e si collegano le uscite ai vari circuiti precedentemente realizzati
Durante la realizzazione è importante prestare attenzione:
- Al collegamento della massa e della Vcc tra le due breadboard
- Ai due pulsanti. In fatti due piedini per ogni pulsante NON sono inseriti, ma appoggiano sulla plastica della breadboard
- Ai led che sono tutti orientati con il catodo a sinistra, quindi il collegamento della massa deve essere fatto accuratamente
Lo schema già pronto può essere copiato da Thinkercad all'indirizzo https://www.tinkercad.com/things/8XXacsc0DwU-schema-semaforo-con-chiamata-pedonale
Soluzione 1 (blocking mode):
Un diagramma SFC, e quindi un controllo sequenziale può essere facilmente implementato in un microcontrollore grazie ad un ciclo infinito, già presente di default in Arduino (è la funzione loop() ) e ad un'istruzione switch() per distinguere le azioni che devono essere effettuate a seconda dello stato.
Nel caso sia possibile arrestare l'esecuzione del programma tra uno stato e l'altro una soluzione è qui sotto riporata:
#define autoRosso 10
#define autoGiallo 11
#define autoVerde 12
#define pedoniRosso 9
#define pedoniVerde 8
#define pulsantePedonale 2
#define verde 0
#define chiamata 1
#define giallo 2
#define rosso 3
int stato; // Stato del semaforo
void setup()
{
pinMode(autoRosso, OUTPUT);
pinMode(autoGiallo, OUTPUT);
pinMode(autoVerde, OUTPUT);
pinMode(pedoniRosso, OUTPUT);
pinMode(pedoniVerde, OUTPUT);
pinMode(pulsantePedonale, INPUT);
Serial.begin(9600);
stato = verde;
Serial.println("Verde");
}
void loop()
{
switch(stato)
{
case verde:
digitalWrite(autoRosso, LOW);
digitalWrite(autoGiallo, LOW);
digitalWrite(autoVerde, HIGH);
digitalWrite(pedoniVerde, LOW);
digitalWrite(pedoniRosso, HIGH);
while( digitalRead(pulsantePedonale) == 0);
stato = chiamata;
Serial.println("Chiamata");
break;
case chiamata:
delay(10000);
stato = giallo;
Serial.println("Giallo");
break;
case giallo:
digitalWrite(autoVerde, LOW);
digitalWrite(autoGiallo, HIGH);
delay(5000);
stato = rosso;
Serial.println("Rosso");
break;
case rosso:
digitalWrite(autoGiallo, LOW);
digitalWrite(autoRosso, HIGH);
digitalWrite(pedoniRosso, LOW);
digitalWrite(pedoniVerde, HIGH);
delay(10000);
stato = verde;
Serial.println("Verde");
break;
}
}
Soluzione 2 (non-blocking mode):
Il codice riportato precedentemente ha il difetto di non essere in grado di essere sensibile alla pressione del pulsante se non quando il semaforo per le auto è verde (cioè quando il sistema è nello stato 0). Nel caso specifico la funzionalità del sistema non viene a meno, però come vedremo nel prossimo esercizio, questo non accade sempre.
Qui sotto viene riportato un codice che realizza lo stesso controllo in modalità non-blocking mode:
#define autoRosso 10
#define autoGiallo 11
#define autoVerde 12
#define pedoniRosso 9
#define pedoniVerde 8
#define pulsantePedonale 2
#define verde 0
#define chiamata 1
#define giallo 2
#define rosso 3
int stato; // Stato del semaforo
bool Azione; // Se HIGH bisogna eseguire l'azione relativa allo stato
unsigned long timenow; // variabile di appoggio per il conteggio dei microsecondi
unsigned long lastUpdate = 0; // variabile di appoggio per il controllo del timer
unsigned long interval = 0;
void setup()
{
pinMode(autoRosso, OUTPUT);
pinMode(autoGiallo, OUTPUT);
pinMode(autoVerde, OUTPUT);
pinMode(pedoniRosso, OUTPUT);
pinMode(pedoniVerde, OUTPUT);
pinMode(pulsantePedonale, INPUT);
Serial.begin(9600);
stato = verde;
Azione = HIGH; // è necessario eseguire l'azione relativa allo stato 0 (verde)
}
void loop()
{
switch (stato)
{
case verde:
// Controllo se è necessrio svolgere l'azione
if (Azione == HIGH){
digitalWrite(autoRosso, LOW);
digitalWrite(autoGiallo, LOW);
digitalWrite(autoVerde, HIGH);
digitalWrite(pedoniVerde, LOW);
digitalWrite(pedoniRosso, HIGH);
Serial.println("Verde");
Azione = LOW;
}
// Il controllo della transizione è sempre necessario
if ( digitalRead(pulsantePedonale) == 1)
{
stato = chiamata;
Azione = HIGH;
}
break;
case chiamata:
if (Azione == HIGH){
lastUpdate = millis();
interval = 10000;
Serial.println("Chiamata");
Azione = LOW;
}
timenow = millis();
if (timenow >= lastUpdate + interval){
stato = giallo;
Azione = HIGH;
}
break;
case giallo:
if (Azione == HIGH){
digitalWrite(autoVerde, LOW);
digitalWrite(autoGiallo, HIGH);
lastUpdate = millis();
interval = 5000;
Serial.println("Giallo");
Azione = LOW;
}
timenow = millis();
if (timenow >= lastUpdate + interval){
stato = rosso;
Azione = HIGH;
}
break;
case rosso:
if (Azione == HIGH){
digitalWrite(autoGiallo, LOW);
digitalWrite(autoRosso, HIGH);
digitalWrite(pedoniRosso, LOW);
digitalWrite(pedoniVerde, HIGH);
lastUpdate = millis();
interval = 10000;
Serial.println("Rosso");
Azione = LOW;
}
timenow = millis();
if (timenow >= lastUpdate + interval){
stato = verde;
Azione = HIGH;
}
break;
}
/* Le righe di codice qui sotto riportate servono a far vedere
* che il codice è sensibile alla pressione del pulsante di
* chiamata anche se si è già avviato il ciclo
*/
if ( digitalRead(pulsantePedonale) == 1)
{
Serial.println("Pulsante premuto");
}
/* Questo delay serve solo per aumentare le prestazioni
* della SIMULAZIONE TINKERCAD e può essere tolto
*/
delay(100);
}