Interrupt State Machine traffic light

Hi there.
I'm pretty new to the Arduino. I'm trying to put together a traffic light simulation.
I used states to go through the different phases. The simulation works fine inside the loop. Now I'm trying to integrate a button to interrupt the defined sequence. The button is wired with a pulldown resistor.
I have 3 traffic lights which simulate traffic North/South, East/West and pedestrians. The loop let's them also go in that order. (pins 13, 10 & 7 are red)
The idea: If the light is green for north/south I want to be able to hit the button for pedestrians and the program shall do following: switch the state to the curren one it's in (green N/S or state 2 in the code) and then apply the delay related to it. Then it should go to state 3 (switch N/S to yellow) apply the delay. Then I suppose it should switch to state 8 (all red before pedestrians green) and jump back into the loop.
How can I make that happen? I've tried the following but what happens is that it always jumps to the pedestrian even if I don't push the button. So somehow it's getting the signal HIGH anyway from that button...?

// C++ code
//
const int ledPins[9] = {13, 12, 11, 10, 9, 8, 7, 6, 5};

const int bNSPin = 4;
const int bEWPin = 1;
const int bPPin = 0;

int bNSState = 0;
int bEWState = 0;
int bPState = 0;

int test[2][11] = {
  {1, 1, 1, 1, 1, 1, 1, 1, 1}, // testate 0
  {0, 0, 0, 0, 0, 0, 0, 0, 0}, // testate 1
};

int mytestate = 0;

int phase[11][9] = {
  {1, 0, 0, 1, 0, 0, 1, 0, 0}, // state 0
  {1, 1, 0, 1, 0, 0, 1, 0, 0}, // state 1
  {0, 0, 1, 1, 0, 0, 1, 0, 0}, // state 2
  {0, 1, 0, 1, 0, 0, 1, 0, 0}, // state 3
  {1, 0, 0,	1, 0, 0, 1, 0, 0}, // state 4
  {1, 0, 0, 1, 1, 0, 1, 0, 0}, // state 5
  {1, 0, 0, 0, 0, 1, 1, 0, 0}, // state 6
  {1, 0, 0, 0, 1, 0, 1, 0, 0}, // state 7
  {1, 0, 0, 1, 0, 0, 1, 0, 0}, // state 8
  {1, 0, 0, 1, 0, 0, 0, 0, 1}, // state 9
  {1, 0, 0, 1, 0, 0, 0, 1, 0}, // state 10
};

int pause[11] = {3000, 1000, 10000, 4000, 3000, 1000, 10000, 4000, 3000, 10000, 5000};

int mystate = 0;



void setup() {
  for (int i = 0; i < 9; i++) {
    pinMode(ledPins[i], OUTPUT);
  }
  // Test-LED  
  	for (int i = 0; i < 9; i++) {
      digitalWrite(ledPins[i], HIGH);
    }
    delay(3000);
    mytestate++;
    for (int i = 0; i < 9; i++) {
      digitalWrite(ledPins[i], LOW);
    }
    delay(3000);
    pinMode(bNSPin, INPUT);
    pinMode(bEWPin, INPUT);
    pinMode(bPPin, INPUT);
}

void showphase() {
  for (int i = 0; i < 9; i++) {
    digitalWrite(ledPins[i], phase[mystate][i]);
  }
  delay(pause[mystate]);
}

void loop() {
  bPState = digitalRead(bPPin);
  showphase();
  mystate++;
  if (mystate >= 11) mystate = 0;

  if ((bPState == HIGH)&&(mystate == 2))  {
    mystate = 2;
    for (int i = 0; i < 9; i++) {
      digitalWrite(ledPins[i], phase[mystate][i]);
    }
    delay(pause[mystate]);
    mystate = 3;
    for (int i = 0; i < 9; i++) {
      digitalWrite(ledPins[i], phase[mystate][i]);
    }
    delay(pause[mystate]);
    mystate = 8;
    for (int i = 0; i < 9; i++) {
      digitalWrite(ledPins[i], phase[mystate][i]);
    }    
  }
}

Hi

Have a quick read of how to use the forum and then edit and post your code using code tags .
A sketch of your wiring diagram would help - you need to have either a pull-up/pull down resistor on digital inputs for use the “INPUT-PULLUP” , in your pinMode statement .Here

No need for interrupts. Don't use 'delay()'. Have each state check to see if it has been active long enough.

Check for the button outside the state machine and set a flag.

When you are done with the state after a light has turned red, check the flag. If the pedestrian has pressed the button, switch to the pedestrian state, otherwise switch to the green for the other direction.

Overloaded word, trigger word.

The OP wants to interrupt the normal behaviour, no one said anything about the use of interrupts.

You may have inadvertently put the bad idea out there... :wink:

a7

Something like this eliminated the delays:

const int ledPins[9] = {13, 12, 11, 10, 9, 8, 7, 6, 5};

const byte bNSPin = 4;
const byte bEWPin = 3;
const byte bPPin = 2;

boolean bNSState = false;
boolean bEWState = false;
boolean bPState = false;

boolean phase[11][9] =
{
  {1, 0, 0, 1, 0, 0, 1, 0, 0}, // state 0 // All Red
  {1, 1, 0, 1, 0, 0, 1, 0, 0}, // state 1 // Red+Yellow?
  {0, 0, 1, 1, 0, 0, 1, 0, 0}, // state 2 // Green
  {0, 1, 0, 1, 0, 0, 1, 0, 0}, // state 3 // Yellow
  {1, 0, 0, 1, 0, 0, 1, 0, 0}, // state 4 // All Red
  {1, 0, 0, 1, 1, 0, 1, 0, 0}, // state 5 // Red+Yellow?
  {1, 0, 0, 0, 0, 1, 1, 0, 0}, // state 6 // Green
  {1, 0, 0, 0, 1, 0, 1, 0, 0}, // state 7 // Yellow
  {1, 0, 0, 1, 0, 0, 1, 0, 0}, // state 8 // All Red
  {1, 0, 0, 1, 0, 0, 0, 0, 1}, // state 9 // Green (Ped)
  {1, 0, 0, 1, 0, 0, 0, 1, 0}, // state 10 // Yellow
};

unsigned long pause[11] = {3000, 1000, 10000, 4000, 3000, 1000, 10000, 4000, 3000, 10000, 5000};

int myState = 0;

void setup()
{
  for (int i = 0; i < 9; i++)
  {
    pinMode(ledPins[i], OUTPUT);
  }

  // Test LEDs
  for (int i = 0; i < 9; i++)
  {
    digitalWrite(ledPins[i], HIGH);
  }
  delay(3000);
  for (int i = 0; i < 9; i++)
  {
    digitalWrite(ledPins[i], LOW);
  }

  delay(3000);
  pinMode(bNSPin, INPUT);
  pinMode(bEWPin, INPUT);
  pinMode(bPPin, INPUT);
}

void showphase(int state)
{
  for (int i = 0; i < 9; i++)
  {
    digitalWrite(ledPins[i], phase[state][i]);
  }
}

void loop()
{
  static unsigned long stateStartTime = 0;

  if (digitalRead(bPPin) == HIGH)
    bPState = true;

  showphase(myState);
  if (millis() - stateStartTime >= pause[myState])
  {
    // State done
    myState++; // Next state
    if (myState >= 11)
      myState = 0;
    stateStartTime = millis();

    // SPECIAL CASES HERE

    // When light is about to turn green, check the pedestrian
    // button.
    if (bPState & (myState == 2 || myState == 6))
    {
      myState = 9;  // Give the pedestrian a green light
      bPState = false;  // Reset the pedestrian button state
    }
  }
}
1 Like

Thanks a lot for the advice and input.

I tried it on tinkercad (which was offered to us from our school) and it always recognizes the bPPin as HIGH. No matter how I try to wire the button, it always jumps to green (State 9) without pushing the button.

I then uploaded the code to my arduino and tried it there.
I found that every time I pushed the button all the LEDs would go out except the LED (Pin 13) would light up and the program would start over.
My teacher's words, which were "the arduino will do what it does in tinkercad", are just rubbish and wrong.

So in conclusion: I did not manage to succeed in what I had planned to do for school and the project ended up in a simple loop of a traffic light system because I (for the love of god) could not get the system to do what I wanted when pushing the button.

There's two things that just did not play in my favour:

  1. Our school just did not give us the right programs and components to do this seriously and
  2. I just don't have the nerves anymore to play around with this thing.

Thanks to everybody else as well for trying to help !!
As far as I'm concerend the thread can be closed.

I hope by “thing” you mean a little set of traffic lights, not computer programming…

Sometimes you do gotta just walk away, but be assured that this stuff is hard until it is easy, and if you keep challenge yourself it will always be hard. Or at least not easy.

Don’t let one bad school/teacher/project/whatever deter you, just keep your head down, put in the work and you will progress.

a7

If you wire bPPin directly to Ground and it still reads HIGH then something is very wrong with your simulation.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.