traffic light with mode button

hi guys,

i have been trying to figure this one out for a wile. i am trying to get a traffic light to have 4 different modes of operation and be able to switch through them with the click of a spst button. i would like to have mode 1) yellow flash 1 second intervals. mode 2) same as yellow only with red flashing mode 3)US 3 light traffic setup and mode 4) 4 light traffic with yellow overlap.

i have the light code all set but im having a problem with the delays as it stops polling the button. i would like at a later time to add a pot to control how long the red and green lights are on.
and a static delay for yellows.

here is what i have. currently mode 4 is a place holder .

its a arduino uno smd edition.

i hope some one can help me out.

thanks

int buttonPin = 2;
int ledGreenpin = 12;
int ledYellowpin = 11;
int ledRedpin = 10;
int val;
int buttonState;
int buttonPresses = 0;
void setup()
{
 pinMode(buttonPin, INPUT);
 pinMode(ledGreenpin, OUTPUT);
 pinMode(ledYellowpin, OUTPUT);
 pinMode(ledRedpin, OUTPUT);
}

void loop(){
  val = digitalRead(buttonPin);
  
  if (val != buttonState) {
    if (val ==LOW) {
      buttonPresses++;
    }
  }
  buttonState = val;
  
  if(buttonPresses == 0)
  {
    digitalWrite(ledRedpin, LOW);
    digitalWrite(ledYellowpin, HIGH);
    digitalWrite(ledGreenpin, LOW);
    delay(1000);
    digitalWrite(ledYellowpin, LOW);
    delay(1000);
}
  
  
  else if(buttonPresses == 1)
  {
  digitalWrite(ledRedpin, LOW); 
  digitalWrite(ledYellowpin, LOW); 
  digitalWrite(ledGreenpin, LOW); 
  delay(1000);
  digitalWrite(ledRedpin, HIGH); 
  delay(1000);
  }

  else if(buttonPresses == 2)
  {
   digitalWrite(ledRedpin, LOW); 
  digitalWrite(ledYellowpin, LOW); 
  digitalWrite(ledGreenpin, HIGH); 
  delay(5000);
  digitalWrite(ledRedpin, LOW); 
  digitalWrite(ledYellowpin, HIGH); 
  digitalWrite(ledGreenpin, LOW); 
  delay(1000);
  digitalWrite(ledRedpin, HIGH); 
  digitalWrite(ledYellowpin, LOW); 
  digitalWrite(ledGreenpin, LOW); 
  delay(5000);
  }
  else if(buttonPresses == 3)
  {
   digitalWrite(ledRedpin, HIGH);
   delay(50);
   digitalWrite(ledRedpin, LOW);
   digitalWrite(ledRedpin, HIGH);
   delay(50);
   digitalWrite(ledRedpin, LOW);
   digitalWrite(ledRedpin, HIGH);
   delay(50);
   digitalWrite(ledRedpin, LOW);
   delay(50);
  }
  else if(buttonPresses >= 4) buttonPresses =0; 
    
 }

Time to look at the "BlinkWithoutDelay" example (File->Examples->2.Digital->BlinkWithoutDelay) to see how you schedule things without using delays. That way your sketch can spend a lot more time checking for button presses since the only other thing it needs to do is: "Is it time to change the lights?".

thank you for you help i have it switching great on the yellow and red flash mode. now the challenge is getting it to do it with timed lights.

i would like to have the delay for the red, yellow and green independently set.
i have revised the code also i think i need to implement debounce it skips from yellow flash to 3 light with out doing red flash

#include <Button.h>

int Greenpin = 12;
int Yellowpin = 11;
int Redpin = 10;
int buttonPresses = 0;
unsigned long changeTime; 
Button button = Button(2,LOW);
int ledState = LOW;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated
long interval = 1000;  
void setup()
{
 pinMode(Greenpin, OUTPUT);
 pinMode(Yellowpin, OUTPUT);
 pinMode(Redpin, OUTPUT);
}

void loop(){
 if(button.isPressed()){
   buttonPresses++;
   mode();
 }
   else{
     mode();
 }
}
  
void mode(){
  if(buttonPresses == 0){
  yellowflash();
  }
  else if(buttonPresses == 1){
    redflash();
  }
  else if(buttonPresses == 2){
    threelight();
  }
  else if(buttonPresses <=3){
    buttonPresses =0;
  }
}




void yellowflash(){

  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;  
    else
      ledState = LOW;
      digitalWrite(Greenpin, LOW);
      digitalWrite(Redpin,LOW);
      
    // set the LED with the ledState of the variable:
    digitalWrite(Yellowpin, ledState);
  }
}
void redflash(){
  
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;
      digitalWrite(Greenpin, LOW);
      digitalWrite(Yellowpin,LOW);
      
    // set the LED with the ledState of the variable:
    digitalWrite(Redpin, ledState);
  }
} 
void threelight(){
  digitalWrite(Redpin, LOW); 
  digitalWrite(Yellowpin, LOW); 
  digitalWrite(Greenpin, HIGH); 
  delay(5000);
  digitalWrite(Redpin, LOW); 
  digitalWrite(Yellowpin, HIGH); 
  digitalWrite(Greenpin, LOW); 
  delay(1000);
  digitalWrite(Redpin, HIGH); 
  digitalWrite(Yellowpin, LOW); 
  digitalWrite(Greenpin, LOW); 
  delay(5000);
}

Just a style note:

 if(button.isPressed()){
   buttonPresses++;
   mode();
 }
   else{
     mode();
  }

Is more complex than and functionally identical to:

 if(button.isPressed()){
   buttonPresses++;
 }
 mode();

For the timed lights, create a global "state variable" to keep track of which step you are at. Then you can act on the timer based on where you are in the sequence. It's a lot like the "buttonPresses" variable. Set the state to 0. Inside threeLight: if the state is 0 you set the light to GREEN, note the current time, and set the state to 1. If the state is 1 and the time that has passed is more than GreenInterval you set the light to YELLOW, note the current time, and set the state to 2. If the state is 2 and the time that has passed is more than YellowInterval you set the light to RED, note the current time, and set the state to 3. If the state is 3 and the time that has passed is more than RedInterval you set the state to 0 which causes the whole process to start again with GREEN. You can set GreenInteval, YellowInterval, and RedInterval whenever you want.

turn GREEN, set the state to 0, and store the current time.

Apparently, you misunderstood the purpose of the blink without delay example, or you would not have all those delay()s still in the code.

PaulS:
Apparently, you misunderstood the purpose of the blink without delay example, or you would not have all those delay()s still in the code.

He took the delays out of the simple ON/OF cases (yellow and red) but did not know about coding a state machine to produce more complex patterns: green for a while, then yellow for a short time, then red for a different while...

ok im completely stumped... :0

i have tried many different codes in the traffic sequence non of which worked.
i think i need the code set up like this http://fritzing.org/media/fritzing-repo/projects/a/arduino-variable-cycle-traffic-lights-wpush-button/code/traffic_lights.pde
but with out the walk signals.

the second problem i am having is the switch does not go to the redflashing when i press it. it jumps right to threelights. i think the debouncing is off.

#include <Bounce.h>

int Greenpin = 12;
int Yellowpin = 11;
int Redpin = 10;
int buttonPresses = 0;
int button = 2;
int ledState = LOW;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated
long interval = 1000;  
Bounce bouncer = Bounce(button,50); 
void setup()
{
 pinMode(button, INPUT);
 pinMode(Greenpin, OUTPUT);
 pinMode(Yellowpin, OUTPUT);
 pinMode(Redpin, OUTPUT);
 digitalWrite(button, HIGH);
 
}

void loop(){
   bouncer.update ( );
   int value = bouncer.read();
   if ( value == LOW){
       buttonPresses++;
 }
 mode();

 
}
void mode(){
  if(buttonPresses == 0){
  yellowflash();
 
  }
  else if(buttonPresses == 1){
    redflash();
    
  }
  else if(buttonPresses == 2){
    threelight();
  }
  
  else if(buttonPresses >= 3){
    buttonPresses = 0;     
  }
}




void yellowflash(){

  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;   
    if (ledState == LOW)
        ledState = HIGH;  
    else
      ledState = LOW;
      digitalWrite(Greenpin, LOW);
      digitalWrite(Redpin,LOW);
      digitalWrite(Yellowpin, ledState);
  }
}
void redflash(){
  
 unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;   
    if (ledState == LOW)
        ledState = HIGH;  
    else
      ledState = LOW;
      digitalWrite(Greenpin, LOW);
      digitalWrite(Yellowpin,LOW);
      digitalWrite(Redpin, ledState);
  }
} 
void threelight(){

 digitalWrite(Redpin, LOW); 
  digitalWrite(Yellowpin, LOW); 
  digitalWrite(Greenpin, HIGH); 
  delay(5000);
  digitalWrite(Redpin, LOW); 
  digitalWrite(Yellowpin, HIGH); 
  digitalWrite(Greenpin, LOW); 
  delay(1000);
  digitalWrite(Redpin, HIGH); 
  digitalWrite(Yellowpin, LOW); 
  digitalWrite(Greenpin, LOW); 
  delay(5000);
      }

debouncing just is to delay reading a digital input to avoid noise, not to determine if its being held down or not, and without a bit of code every loop its going to look, see button is down and advance.

you need something to compare

if button != oldbutton THEN do something

if button == oldbutton THEN its being held and ignore it until its released again

This is how I would write it if I were writing it:

// Define the pins we are using
const int greenPin = 12;
const int yellowPin = 11;
const int redPin = 10;
const int buttonPin = 2;

enum color {
  GREEN, YELLOW, RED, OFF} 
lightState = OFF;  //  State of the three-light traffic light

int lightMode = 0;  // Blinking yellow, Blinking red, or full color

unsigned long lastButtonPressTime;
bool lastButtonState;
const unsigned long buttonDebounceInterval = 100;  // One peress per 1/10th second

bool blinkerOn = false;             // ledState used to set the LED
unsigned long previousMillis = 0;        // will store last time LED was updated

unsigned long blinkInterval = 1000;  
unsigned long greenInterval = 1000;  
unsigned long yellowInterval = 1000;  
unsigned long redInterval = 1000;  

void setup()
{
  pinMode(greenPin, OUTPUT);
  pinMode(yellowPin, OUTPUT);
  pinMode(redPin, OUTPUT);
  pinMode(buttonPin, INPUT);
}

// NOTE: The argument here would normally be 'enum color' but the way Arduino does things
// (it puts all function declarations at the top) it tries to declare the function before
// the declaration of the enum and gets and error.  Fortunately enums work a lot like 
// integers.
void setColor(int newColor)
{
  // Turn all colors off to start
  digitalWrite(greenPin, LOW);
  digitalWrite(yellowPin, LOW);
  digitalWrite(redPin, LOW);

  switch (newColor)
  {
  case GREEN:  
    digitalWrite(greenPin, HIGH); 
    break;
  case YELLOW: 
    digitalWrite(yellowPin, HIGH); 
    break;
  case RED: 
    digitalWrite(redPin, HIGH); 
    break;
  }
}

void loop(){
  bool buttonState = digitalRead(buttonPin);
  if (buttonState != lastButtonState && millis() - lastButtonPressTime > buttonDebounceInterval)
  {
    lastButtonState = buttonState;
    lastButtonPressTime = millis();
    if (buttonState == LOW)  //  Button is 'active low'?
      lightMode++;
  }

  switch (lightMode)
  {
  case 0: 
    lightState = OFF;  // Re-start at GREEN
    flash(YELLOW); 
    break;
  case 1: 
    lightState = OFF;  // Re-start at GREEN
    flash(RED); 
    break;
  case 2: 
    threelight(); 
    break;
  default: 
    lightMode = 0;
  }
}

// NOTE: The argument here would normally be 'enum color' but the way Arduino does things
// (it puts all function declarations at the top) it tries to declare the function before
// the declaration of the enum and gets and error.  Fortunately enums work a lot like 
// integers.
void flash(int flashColor){

  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > blinkInterval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    blinkerOn = !blinkerOn;  //  Toggle blinker

    if (blinkerOn)
      setColor(flashColor);
    else
      setColor(OFF);
  }
}

void threelight(){
  unsigned long currentMillis = millis();
  switch (lightState)
  {
  case GREEN: 
    if (currentMillis - previousMillis > greenInterval)
    {
      previousMillis = currentMillis; //Re-start timer
      lightState = YELLOW;
      setColor(YELLOW);
    }
    break;

  case YELLOW:
    if (currentMillis - previousMillis > yellowInterval)
    {
      previousMillis = currentMillis; //Re-start timer
      lightState = RED;
      setColor(RED);
    }
    break;

  case RED:
    if (currentMillis - previousMillis > redInterval)
    {
      previousMillis = currentMillis;  //Re-start timer
      lightState = GREEN;
      setColor(GREEN);
    }
    break;

  default: 
    lightState = GREEN;
    previousMillis = currentMillis;
    setColor(GREEN);
  }
}

@OP:
Notice how in John's code the { and } line up. Notice how everything in between is properly indented. Notice how much/little white space is used. Notice how much more readable his code is than yours.

The Tools + Auto format menu item is there for a reason. You should use it regularly.

this was my first attempt at a project, so im a little messy when i design things. once it works i go back and make it as short as possible.

thanks guys for helping :slight_smile:

my next project is to make it network aware and maybe put a pir on it too. but that's going to be alot later.