-1

I am trying to simulate a traffic signal with a provision of a pedestrian button, that when pressed, stops the traffic for a while. Here are the conditions I'm trying to meet,

One green LED (on pin 10) lit for 3 seconds (the first LED to light up). - Then one orange LED (on pin 11) lit for 1 second - Then finally one red LED (on pin 12) lit for 3 seconds.

Two-colour light (pedestrian) - The pedestrian light is constantly red (red LED on pin 9) and only turns green (LED on pin 8) once the button (on pin 2) is pressed.

On button press If the button is pressed while the car traffic light is green, the orange light is lit for 1 second, then the car lights turn red for 5 seconds during which the green pedestrian light is green.

After those 5 seconds, the pedestrian light turns red again and normal functioning resumes (car traffic light returns to green)

And here's my code for the same,

int status=0;    //mode:state of button pin
int buttonpin=2;//pin related to pushbutton
void setup(){
  pinMode(10,OUTPUT);   //Green LED to pin10
  pinMode(11,OUTPUT);   //Orange LED to pin11
  pinMode(12,OUTPUT);   //Red LED to pin12
  pinMode(9,OUTPUT);    //Pedestrian Red on pin 9
  pinMode(8,OUTPUT);    //Pedestrian Green on pin 8
}

void loop(){

  digitalWrite(9,HIGH);//Pedestrian Red is on
  status=digitalRead(buttonpin);

  if (status==HIGH){
    digitalWrite(9,LOW); //pedestrian red is off
    digitalWrite(8,HIGH); //Pedestrian Green is on
    digitalWrite(11,HIGH);//orange lights up
    delay(1000);//1second delay
    digitalWrite(11,LOW);//orange shut off);
    digitalWrite(12,HIGH);//red starts
    delay(5000);//5 second delay
    digitalWrite(12,LOW);
    digitalWrite(9,HIGH);
  }
  else{
    digitalWrite(10,HIGH);//green lights up
  delay(3000);//3 second delay 
  digitalWrite(10,LOW);//green shuts off
  digitalWrite(11,HIGH);//orange lights up
  delay(1000);//1second delay
  digitalWrite(11,LOW);//orange shut off);
  digitalWrite(12,HIGH);//red starts
  delay(3000);
  digitalWrite(12,LOW);//red shuts off
 }
}

The problem is, the pedestrian button only works when it is already pressed at the time of Traffic Green starting(because of the if loop right there in code), but once Traffic green has already been green for say 1.5 seconds, it won't work as the if loop condition check has been already passed. How can I mend my code to make the "On button Press" sequence explained above work at any time of the Green LED HIGH?

Attached is the circuit if the need be. Traffic Circuit

Edited code is:

#include <TimerOne.h>


int status=0;    //mode:state of button pin
int buttonpin=2;//pin related to pushbutton



void setup(){

  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT);
  pinMode(12,OUTPUT);
  pinMode(9,OUTPUT);
  pinMode(8,OUTPUT);

  Timer1.initialize(100000);
  Timer1.attachInterrupt( buttonCheck );

}

void loop(){

  digitalWrite(9,HIGH);
  status=digitalRead(buttonpin);


  digitalWrite(10,HIGH);//green lights up
  delay(3000);//3 second delay 
  digitalWrite(10,LOW);//green shuts off
  digitalWrite(11,HIGH);//orange lights up
  delay(1000);//1second delay
  digitalWrite(11,LOW);//orange shut off);
  digitalWrite(12,HIGH);//red starts
  delay(3000);
  digitalWrite(12,LOW);//red shuts off

}

void buttonCheck(){

   if (status==HIGH){
    digitalWrite(9,LOW);
    digitalWrite(8,HIGH);
    digitalWrite(11,HIGH);//orange lights up
    delay(1000);//1second delay
    digitalWrite(11,LOW);//orange shut off);
    digitalWrite(12,HIGH);//red starts
    delay(5000);//5 second delay
    digitalWrite(12,LOW);
    digitalWrite(9,HIGH);
    return;
  }
}

Will this work?

  • 1
    Reconstruct your code by ditching all those delay() calls (using delay isn't a good idea in almost all situations). Instead use non-blocking code with the millis() function. Refer to the BlinkWithoutDelay example of the Arduino IDE for this. Also it will be good to learn, how to code a finite state machine (sounds more complex than it is). There are plenty tutorials on the web for this. – chrisl Jun 25 '18 at 19:58
  • While I agree that completely non-blocking code is better, for this purpose you could say, you have a "flow" which you want to "interrupt", so have a look at "pin interrupts". – Paul Jun 25 '18 at 20:04
  • you need a state machine to manage this behavior model – dandavis Jun 25 '18 at 20:54
  • @Paul I have used interrupts in my code and edited the answer, will this work? – Kv07 Jun 27 '18 at 13:40
0

The cause of the issue, is the way you have implemented delay() in your sketch. It's true that delay() should be avoided 99.9% of the time, but it does have it's uses.

If you start with the BlinkWithoutDelay example that comes with the Arduino IDE, then add a counter variable and a switch statement, you can easily get the traffic lights "part" of your requirements working.

Adding the pedestrian button functionality using non-blocking code is more difficult (for me it's more difficult), but it's a problem easily solved using delay().

But what if you ever want your sketch to do more? What happens if you add another button to it? delay() is "blocking" code, so using it will probably "bite" you again if you try to add functionality to this sketch.

const byte buttonPin = 2;
byte secondsCounter = 0;
byte trafficLightState = 0;
unsigned long oneSecond = 1000;
unsigned long previousMillis = 0;

void setup(){
  pinMode(10, OUTPUT);   // Green LED to pin 10
  pinMode(11, OUTPUT);   // Orange LED to pin 11
  pinMode(12, OUTPUT);   // Red LED to pin 12
  pinMode(9, OUTPUT);    // Pedestrian Red on pin 9
  pinMode(8, OUTPUT);    // Pedestrian Green on pin 8
  // I used a wire from GND to "buttonPin" as a switch.
  pinMode(buttonPin, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop(){

  // Get the current time.
  unsigned long currentMillis = millis();

  // If the button is pressed while the car traffic light is green,
  // the orange light is lit for 1 second, then the car lights turn
  // red for 5 seconds during which the green pedestrian light is green.
  if(trafficLightState == 0 && digitalRead(buttonPin) == LOW){
    digitalWrite(10, LOW);
    digitalWrite(11, HIGH);
    digitalWrite(12, LOW);
    digitalWrite(9, HIGH);
    digitalWrite(8, LOW);
    Serial.println("Button Pressed. Orange light ON for 1 second, Pedestrian red ON.");
    delay(1000);
    digitalWrite(11, LOW);
    digitalWrite(12, HIGH);
    digitalWrite(9, LOW);
    digitalWrite(8, HIGH);
    Serial.println("Red light ON for 5 seconds, Pedestrian green ON.");
    delay(5000);
    digitalWrite(11, HIGH);
    digitalWrite(12, LOW);
    digitalWrite(9, HIGH);
    digitalWrite(8, LOW);
    Serial.println("Pedestrian red ON.");
    trafficLightState = 0;
    secondsCounter = 0;
    currentMillis = millis();
  }

  // Update the traffic light state every second.
  if(oneSecondTimer(oneSecond, currentMillis) == 1){

    secondsCounter += 1;
    if(secondsCounter > 7){secondsCounter = 1;}

    // Green traffic light.
    if(secondsCounter == 1){
      trafficLightState = 0;
      Serial.println("Green traffic light ON for 3 seconds");
    }
    // Orange traffic light.
    else if(secondsCounter == 4){
      trafficLightState = 1;
      Serial.println("Orange traffic light ON for 1 second");
    }
    // Red traffic light.
    else if(secondsCounter == 5){
      trafficLightState = 2;
      Serial.println("Red traffic light ON for 3 seconds");
    }
  }

  // Turn the traffic lights on/off as required.
  switch(trafficLightState){

    // Turn the green traffic light ON, pedestrian red ON.
    case 0:
      digitalWrite(10, HIGH);
      digitalWrite(11, LOW);
      digitalWrite(12, LOW);
      digitalWrite(9, HIGH);
      digitalWrite(8, LOW);
      break;

    // Turn the orange traffic light ON, pedestrian red ON.
    case 1:
      digitalWrite(10, LOW);
      digitalWrite(11, HIGH);
      digitalWrite(12, LOW);
      digitalWrite(9, HIGH);
      digitalWrite(8, LOW);
      break;

    // Turn the red traffic light ON, pedestrian red ON.  
    case 2:
      digitalWrite(10, LOW);
      digitalWrite(11, LOW);
      digitalWrite(12, HIGH);
      // Pedestrian green light ON ONLY if button was
      // pressed while the traffic light was green.
      // digitalWrite(9, LOW);
      // digitalWrite(8, HIGH);
      break;
  }
}

byte oneSecondTimer(unsigned long delayTime, unsigned long currentMillis){
  if(currentMillis - previousMillis >= delayTime){previousMillis = currentMillis;return 1;}
  else{return 0;}
}
  • this code doesn't work the way problem has been specified. – Kv07 Jun 27 '18 at 13:26
  • What's it doing differently? – VE7JRO Jun 27 '18 at 21:57
  • In your original sketch and the new one you've added using TimerOne, you turn the Pedestrian Green light on the first time the button is pressed and then you leave it on until the Arduino is re-booted. I didn't see that listed as one of your requirements. Are you sure that's what you want to do? Have the Pedestrian Green light on regardless of the traffic light color? – VE7JRO Jun 28 '18 at 2:46
  • What my aim is, when the traffic light is green, if the pedestrian button is pressed, it follows this sequence: On button press If the button is pressed while the car traffic light is green, the orange light is lit for 1 second, then the car lights turn red for 5 seconds during which the green pedestrian light is green. Then the pedestrian light turns red back again and traffic light resumes its normal functionality. This is the problem in my (and your) code. – Kv07 Jun 30 '18 at 12:06
  • What happens when you press the button when the traffic light is green using my sketch? Is the output in the serial monitor correct? One more thing to check would be to verify the button and LEDs are wired correctly. – VE7JRO Jun 30 '18 at 19:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.