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:
Ecco la 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);
}