Un esempio con Arduino: un classico semaforo con un pulsante per il passaggio pedonale.

In questo esempio didattico vediamo come si puo' pensare un classico semaforo con Arduino con un pulsante per il passaggio pedonale.

Si vuole programmare un semaforo con Arduino con i seguenti cicli:

  • Rosso 40 secondi
  • Verde 40 secondi
  • Giallo 5 secondi

Inoltre il progetto deve avere un pulsante per il passaggio pedonale.

Solo se viene premuto il pulsante per almeno un secondo deve attivarsi la funzione custom chiamata

  • pedestrian_crossing()

entro cinque secondi dalla pressione del pulsante.

Quando si attiva tale funzione il semaforo deve diventare

  • Giallo per 5 secondi

eppoi

  • Rosso per 20 secondi (per consentire ai pedoni il passaggio sulle strisce pedonali).

per poi riprendere il ciclo normale.

.

Si puo' usare la piattaforma 123d.circuits.io per simulare il progetto, oppure, come in questo caso, il software Fritzing per disegnare lo schema elettrico e il circuito disposto su breadboard.

Ecco lo schema elettrico:

Schema Elettrico
Schema Elettrico

Ecco la vista breadboard:

BreadBoard
Vista Breadboard

Ecco lo sketch:

/*
Prof. Fausto Mariani
25.01.2016
Just another Traffic light with pedestrian crossing button
This code is public domain - "dominio pubblico "
*/

int LedR = 10; // LedR connected to digital pin numer 10
int LedY = 11; // LedYconnected to digital pin numer 11
int LedG = 12; // LedG connected to digital pin numer 12


int BUTTON = 13; // Input button connected to digital pin number 13


int val = 0; // to store the state of input button
unsigned long time_elapsed = millis();
unsigned long time_elapsed_with_button_pressed = millis();
unsigned long duration_pressed;
void setup() {
    Serial.begin(9600); // to enable Serial monitor to PC
    pinMode(LedR, OUTPUT); // to set the output
    pinMode(LedY, OUTPUT); // to set the output
    pinMode(LedG, OUTPUT); // to set the output
    pinMode(BUTTON, INPUT); //  To set the pedestrian crossing input button
}
void loop() {
    
    val = digitalRead(BUTTON); // To read the current input value and store it

    // check if the button has been pressed
    if (val == HIGH) {
        time_elapsed_with_button_pressed = millis();
        duration_pressed = time_elapsed_with_button_pressed - time_elapsed;
        // duration_pressed store the time for which the button is pressed
        if (duration_pressed > 1000)
            // in order to check if the button has been pressed for at least 1 second
            {
        		Serial.println("Button High, duration_pressed:" || duration_pressed);
                Serial.println("We are waiting 4 seconds...");
                delay(4000);
                pedestrian_crossing(); // we call the pedestrian_crossing() function
                time_elapsed = millis(); // to restart time pressed count
            }  
    }
    else {
        digitalWrite(LedR, LOW);   // switched off the Red
        digitalWrite(LedY, LOW);    // switched off the Yellow
        digitalWrite(LedG, HIGH);  // fire the Green
        delay(40000);
        digitalWrite(LedR, LOW);   // switched off the Red
        digitalWrite(LedG, LOW);    // switched off the Green
        digitalWrite(LedY, HIGH);  // fire the Yellow
        delay(5000);
        digitalWrite(LedY, LOW);  // switched off the Yellow
        digitalWrite(LedG, LOW);    // switched off the Green
        digitalWrite(LedR, HIGH);   // fire the Red
        delay(40000);
   //     time_elapsed = millis(); // to restart time pressed count
    }
}
void pedestrian_crossing() {
    Serial.println("Pedestrian may go ahead...");
    digitalWrite(LedR, LOW);   // switched off the Red
    digitalWrite(LedG, LOW);    // switched off the Green
    digitalWrite(LedY, HIGH);  // fire the Yellow
    delay(5000);
    digitalWrite(LedY, LOW);  // switched off the Yellow
    digitalWrite(LedG, LOW);    // switched off the Green
    digitalWrite(LedR, HIGH);   // fire the Red
    delay(20000);
}

 

In allegato il file di Fritzing che si puo' ulteriormente migliorare.

Problema: questo esempio non funziona bene e richiede una correzione.

Cosa accade se l'utente preme il pulsante durante la lunga delay(40000) del verde o del rosso?

 

See this example:

https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay

 

 

Si fornisce una seconda versione dello stesso programma. Questa versione dovrebbe funzionare. ;-)

/*
Prof. Fausto Mariani
Release 1.0 - 25.01.2016
Release 2.1 - 16-02-2016 To solve a problem with long delay time
Just another Traffic light with pedestrian crossing button
This code is public domain - "dominio pubblico "
*/
// set some Parameters
// Please change the value of this constants before Start the simulation
// with the value you agree.
const long durationRedOnSeconds = 40;
const int durationYellowOnSeconds = 4;
const long durationGreenOnSeconds = 40;
// end of Parameters


int LedR = 10; // LedR connected to digital pin numer 10
int LedY = 11; // LedYconnected to digital pin numer 11
int LedG = 12; // LedG connected to digital pin numer 12


int BUTTON = 13; // Input button connected to digital pin number 13


int val = 0; // to store the state of input button

char status = 'G';  // status=G mean normal Green, status=Y mean normal Yellow, status=R mean normal Red
				// normal mean without enable Pedestrian Crossing status

char previous_status = 'G'; // previous_status=0 mean normal Green, previous_status=1 mean normal Yellow, previous_status=2 mean normal Red
				// normal mean without enable Pedestrian Crossing status

unsigned long time_elapsed = millis();
// the variable time_elapsed measures the time from the start
unsigned long time_elapsed_with_button_pressed = millis();
// the variable time_elapsed_with_button_pressed
unsigned long time_elapsed_without_button_pressed = millis();
// measures the time in which the button is not pressed
long duration_pressed;
long duration_not_pressed;
void setup() {
    Serial.begin(9600); // to enable Serial monitor to PC
    pinMode(LedR, OUTPUT); // to set the output
    pinMode(LedY, OUTPUT); // to set the output
    pinMode(LedG, OUTPUT); // to set the output
    pinMode(BUTTON, INPUT); //  To set the pedestrian crossing input button
}


void loop() {
    
    val = digitalRead(BUTTON); // To read the current input value and store it

    // check if the button has been pressed
    if (val == HIGH) {
        time_elapsed_with_button_pressed = millis();
        duration_pressed = time_elapsed_with_button_pressed - time_elapsed;
        // duration_pressed store the time for which the button is pressed
        if (duration_pressed > 1000)
            // in order to check if the button has been pressed for at least 1 second
            {
        		Serial.print("Button High, duration_pressed:");
                Serial.println(duration_pressed);
                Serial.println("We are waiting 4 seconds...");
                delay(4000);
                pedestrian_crossing(durationYellowOnSeconds, 20); // we call the pedestrian_crossing() function
                time_elapsed = millis(); // to restart time pressed count
				status = 'G';
          		previous_status = 'G';
            }  
        delay(10);  // just to wait for 1ms
    }
    else {
        delay(30); // just to make fast the simulation portal
		time_elapsed_without_button_pressed  = millis();
        duration_not_pressed = time_elapsed_without_button_pressed - time_elapsed;
        Serial.println(duration_not_pressed);
        if (
          		(duration_not_pressed < durationGreenOnSeconds * 1000) && ( previous_status == 'G' )
        	)
            // in order to stay in this state until is passed less than Green light time
            {
        				digitalWrite(LedR, LOW);   // switched off the Red
        				digitalWrite(LedY, LOW);    // switched off the Yellow
       					digitalWrite(LedG, HIGH);  // fire the Green

			}
		else if ( previous_status == 'G' )
                {
                	if (duration_not_pressed > (durationGreenOnSeconds * 1000))
					{
								status= 'Y';	 // we would like pass to Yellow
                      			previous_status = status;
                     			time_elapsed = millis();
								time_elapsed_without_button_pressed = millis();
					}
                    else {
                      		
								status= 'G';	 // we don't change the status
								time_elapsed_without_button_pressed = millis();
                    }
                }
        // delay(40000);
        else if (
          		(duration_not_pressed < durationYellowOnSeconds * 1000) && ( previous_status == 'Y' )
        	)
            // in order to stay in this state until is passed less than Yellow light time
            {
        				digitalWrite(LedR, LOW);   // switched off the Red
        				digitalWrite(LedG, LOW);    // switched off the Green
       					digitalWrite(LedY, HIGH);  // fire the Yellow
			}
       // delay(5000);
		else if ( previous_status == 'Y' )
                {
                	if (duration_not_pressed > (durationYellowOnSeconds * 1000))
					{
								status = 'R';	 // we would like pass to Red
                      			previous_status = status;
                     			time_elapsed = millis();
								time_elapsed_without_button_pressed = millis();
					}
                    else {
                      		
								status = 'Y';	 // we don't change the status
								time_elapsed_without_button_pressed = millis();
                    }
                } 	
        else if (
          		(duration_not_pressed < durationRedOnSeconds * 1000) && ( previous_status == 'R' )
        	)
            // in order to stay in this state until is passed less than Red light time
            {
        				digitalWrite(LedY, LOW);  // switched off the Yellow
        				digitalWrite(LedG, LOW);    // switched off the Green
       					digitalWrite(LedR, HIGH);   // fire the Red
			} 
			else if ( previous_status == 'R' )
                {
                	if (duration_not_pressed > (durationRedOnSeconds * 1000))
					{
								status = 'G';	 // we would like pass to Green
                      			previous_status = status;
                     			time_elapsed = millis();
								time_elapsed_without_button_pressed = millis();
					}
                    else {
                      		
								status =  'R';	 // we don't change the status
								time_elapsed_without_button_pressed = millis();
                    }
                } 
      	
       //  delay(40000);
			
   //     time_elapsed = millis(); // to restart time pressed count
	}  // end if on val== HIGH
}
void pedestrian_crossing(int dY, int dR) {
    digitalWrite(LedR, LOW);   // switched off the Red
    digitalWrite(LedG, LOW);    // switched off the Green
    digitalWrite(LedY, HIGH);  // fire the Yellow
    delay(dY * 1000);
    Serial.println("Pedestrian may go ahead...");
    digitalWrite(LedY, LOW);  // switched off the Yellow
    digitalWrite(LedG, LOW);    // switched off the Green
    digitalWrite(LedR, HIGH);   // fire the Red
    delay(dR * 1000);
}