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:

  1. Si posizionano le 2 breadborad, NON si inserisce l'Arduino
  2. Si collegano tra loro massa e Vcc nelle breadboard
  3. Si realizza il circuito di comando dei due semafori automobilistici, le resistenze dei led sono da 330 Ohm
  4. Si realizza il circuito di comando dei due semafori pedonali, le resistenze dei led sono da 330 Ohm
  5. Si realizza il circuito di pulsanti di chiamata, le resistenze dei pulsanti sono da 1 KOhm
  6. 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); 
                 
Ultime modifiche: mercoledì, 10 gennaio 2024, 18:21