Traffic Light Program - Button Press

Hi,

I am trying to create a traffic light simulator, but I have become stuck. So far I have the traffic lights in a loop (see void loop) and they loop round like a standard traffic light.

I have added a pedestrian button in a separate program so that when pressed the lights change but I can't get the lights to loop and poll for a button press to change them inside the same program.

If someone could please help me to change this, I would be grateful.

Many thanks, Will

Your code is littered with delay()s which will make it very unresponsive to button presses. You need to change to millis() timing, as used already in parts of the program, to avid the delay()s blocking the reading of inputs. Reading up on state machines (sounds scary, but isn't) will probably be helpful too.

Ahh ok so I would have to change the delays.

I still don't understand how I could implement the button into the program so that I could poll inside the loop.

I want it so that I can test for the button to be pressed whilst the loop is going and then exit the loop once the button has been pressed.

The problem here (and elsewhere on the boards) is new programmers unfamiliar with the idea of a finite state machine. For arduino programming in particular, it's a key concept.

Have a look at several things at a time.

Imagine that your loop() is like this

void loop() {
   readButton();
   udpateLights();
}

...R

A gentle into to state machines that turns on a series of LEDs

enum states
{
  roadRed,
  roadYellow,
  roadGreen
};

byte roadRedPin = 12;
byte roadYellowPin = 11;
byte roadGreenPin = 10;

unsigned long stateStart;
unsigned long currentTime;
unsigned long redPeriod = 2000;
unsigned long yellowPeriod = 3000;
unsigned long greenPeriod = 5000;
byte state = roadRed;

void setup ()
{
  pinMode(roadRedPin, OUTPUT);
  pinMode(roadYellowPin, OUTPUT);
  pinMode(roadGreenPin, OUTPUT);
  digitalWrite(roadRedPin, LOW);
  digitalWrite(roadYellowPin, HIGH);
  digitalWrite(roadGreenPin, HIGH);

  stateStart = millis();
}

void loop()
{
  switch (state)
  {
    case roadRed:
      currentTime = millis();
      digitalWrite(roadRedPin, LOW);
      if (currentTime - stateStart >= redPeriod)  //? time to change state ?
      {
        digitalWrite(roadRedPin, HIGH);  //set up outputs for new state
        digitalWrite(roadYellowPin, LOW);
        state = roadYellow;
        stateStart = currentTime;
      }
      break;

    case roadYellow:
      currentTime = millis();
      digitalWrite(roadYellowPin, LOW);
      if (currentTime - stateStart >= greenPeriod)
      {
        digitalWrite(roadYellowPin, HIGH);
        digitalWrite(roadGreenPin, LOW);
        state = roadGreen;
        stateStart = currentTime;
      }
      break;

    case roadGreen:
      currentTime = millis();
      digitalWrite(roadGreenPin, LOW);
      if (currentTime - stateStart >= greenPeriod)
      {
        digitalWrite(roadGreenPin, HIGH);
        digitalWrite(roadRedPin, LOW);
        state = roadRed;
        stateStart = currentTime;
      }
      break;
  }
}

The code to read the pedestrian button should be added into the loop() function so that it is read each time through loop(). Once a press is detected, ie the button [u]becomes[/u] pressed rather than [u]is[/u] pressed the state needs to change to a new one added to the list in the enum and a new case added to the switch/case to deal with it.

Thank you all for responses and yes I am new to Arduino haha.

I have found that an interrupt function helps and I have managed to make it so that when the button is pressed the pedestrian lights function comes on. The problem that I have now is that the loop function is still running on top of the pedestrian (stateChange()) and also the stateChange function runs in about 1 second meaning that you would have to be pretty fast to cross the road.

I would like to know if there is a way to stop the loop once the button is pressed and the interrupt has been initiated?

Also how to slow down the function.

You are making things too complicated by using an interrupt. Try the state machine example that I posted and add in the button detection and code for the extra state that I suggested. By using a state machine you can ensure that only the code relevant relevant to the current state is executed whilst maintaining the responsiveness of the system to user input.

I really can’t seem to get my head around the programming of a state machine for some reason??

Robin2: Have a look at several things at a time.

Imagine that your loop() is like this

void loop() {
   readButton();
   udpateLights();
}

...R

Thanks Robin2, I actually came across your post whilst researching into state machines. I couldn't figure out how to implement it into my design though.

I gave up in the end as I struggled to code the state machine alongside my loop.

It didn't detect the button press and just kept calling the lights function.

WillH: I really can't seem to get my head around the programming of a state machine for some reason??

When it clicks how simple it is you will kick yourself.

Look at my example. It has 3 possible states namely red light on, yellow light on or green light on and will be in one of those states during program execution. I gave the states names using the enum to make the program easier to understand, but all it does is to allocate a number to each state.

The program start in state roadRed with the red LED turned on and the start time of the state in the stateStart variable. The switch/case executes only the code for the current state and will execute it each time through loop(). Once the red period has elapsed the program turns the LEDs on/off, saves the current time as the start of the next state and changes the state number.

Next time through loop() the code for the current state, which has now changed, is executed and the program and keeps going round loop() until the yellow period has elapsed then it moves to the green state, turns the LEDs on/off, saves the current time as the start of the next state and changes the state number.

The program would carry on like this unless something happens to alter the state such as a user input. As the execution program is not blocked by delay()s the user input could be read each time through loop() and could change to another state, perhaps pedGreen, change the LEDs appropriately and execute a new case to time the pedestrian phase of the program before setting the LEDs appropriately, saving the state start time, and changing the state number which will cause the program to execute the commands for the new state.

Note that the program as it stands does not read user input. That code needs adding once you have understood the principle of the state machine.

WillH: I gave up in the end as I struggled to code the state machine alongside my loop.

If you post the code we could try to help but without seeing it, how can we.

What you want to achieve is not complicated when you get your brain pointed in the correct direction. Have a look at planning and implementing a program which may give a slightly different view of the issues.

...R