I am making a realistic intersection with roads but I have a problem.

I am trying to make a real life intersection with roads. There are 2 streets that have consistently changing traffic lights (Street 1 and Street 2). The switch is for an emergency situation. Switch1 should turn the green light for street 1, and the red light light for street 2 on. When I run my code, everything except one thing works fine. Switch1 does it`s job, however the lights stay on for more time than I want them to (Ex. First the lights are changing. Then the button is clicked and the green light for street 1 and red light for street 2 is on for 5000 milliseconds. Then it continues on in the loop where ever you left it last). What I want is after the the switch is clicked and 5000 milliseconds have passed, the program to start over from loop. I have checked a few websites about interrupt vectors and some other stuff, but I am not sure how to start the program from loop after the interupt.

My code is below. I would appreciate some help.

volatile int red1 = 13;
volatile int yellow1 = 12;
volatile int green1 = 11;
volatile int red2 = 10;
volatile int yellow2 = 9;
volatile int green2 = 8;

int switch1 = 2;

void setup() {
  pinMode(red1, OUTPUT);
  pinMode(yellow1, OUTPUT);
  pinMode(green1, OUTPUT);
  pinMode(red2, OUTPUT);
  pinMode(yellow2, OUTPUT);
  pinMode(green2, OUTPUT);

  pinMode(switch1, INPUT);
  attachInterrupt(digitalPinToInterrupt(switch1), Lane1E, CHANGE);
}

void Lane1E () {

digitalWrite(green1, HIGH);
digitalWrite(red2, HIGH);
digitalWrite(green2, LOW);
digitalWrite(red1, LOW);
digitalWrite(yellow1, LOW);
digitalWrite(yellow2, LOW);
delay(5000);



}

void loop() {
  digitalWrite(green1, HIGH);
  digitalWrite(red2, HIGH); 
  delay(15000);  
  digitalWrite(green1, LOW);    
  digitalWrite(yellow1, HIGH);   
  delay(2500); 
  digitalWrite(yellow1, LOW);    
  digitalWrite(red1, HIGH);   
  delay(1500);  
  digitalWrite(red1, LOW);
  digitalWrite(red2, LOW);

  digitalWrite(green2, HIGH);
  digitalWrite(red1, HIGH);  
  delay(15000);  
  digitalWrite(green2, LOW);                  
  digitalWrite(yellow2, HIGH);   
  delay(2500); 
  digitalWrite(yellow2, LOW);     
  digitalWrite(red2, HIGH);   
  delay(1500);  
  digitalWrite(red2, LOW);
  digitalWrite(red1, LOW);
  
}

The method you chose to control your lights was difficult to proof without your circuit but this wasn't very hard to code it with a non blocking script to resolve this issue.

Try this out:

volatile byte red1 = 13;
volatile byte yellow1 = 12;
volatile byte green1 = 11;
volatile byte red2 = 10;
volatile byte yellow2 = 9;
volatile byte green2 = 8;

byte switch1 = 2;



//   1 = HIGH
//   0 = LOW
//                        { 6 is a gap}
//         {     Normal loop   }   { Emergency}
//            0   1   2    3   4   5  6    7   8   // Array Key
int Tm[] = {150, 25, 15, 150, 25, 15, 0,  15, 50}; // Time Delay in 10ths of a second
byte G1[] = { 1,  0,  0,   0,  0,  0, 0,   1,  1}; // Green1
byte Y1[] = { 0,  1,  0,   0,  0,  0, 0,   0,  0}; // Yellow1
byte R1[] = { 0,  0,  1,   1,  1,  1, 0,   0,  0}; // Red1
byte G2[] = { 0,  0,  0,   1,  0,  0, 0,   0,  0}; // Green2
byte Y2[] = { 0,  0,  0,   0,  1,  0, 0,   1,  0}; // Yellow2
byte R2[] = { 1,  1,  1,   0,  0,  1, 0,   0,  1}; // Red2

volatile byte Ctr = 0;

volatile byte Key =0;
void Lane1E () {
  Key = (digitalRead(red1)) ? 7 : 8; // if Light is red Do Yellow first then red
  Ctr = 0;// Start this timer over.
}

void setup() {
  pinMode(red1, OUTPUT);
  pinMode(yellow1, OUTPUT);
  pinMode(green1, OUTPUT);
  pinMode(red2, OUTPUT);
  pinMode(yellow2, OUTPUT);
  pinMode(green2, OUTPUT);

  pinMode(switch1, INPUT_PULLUP); // Connect switch to GND
  attachInterrupt(digitalPinToInterrupt(switch1), Lane1E, LOW); // closes of normally open contact shorts Pullup to ground
}

void loop() {
  static unsigned long Timer, T;
  if ( millis() - Timer >= (100)) {  //delay 10 times a second
    Timer += (100);
    if (Key == 6)Key = 0;
    if (Key >= 9)Key == 0; //Emergency Modes 7 and 8
    digitalWrite(green1, G1[Key]);
    digitalWrite(yellow1, Y1[Key]);
    digitalWrite(red1, R1[Key]);
    digitalWrite(green2, G2[Key]);
    digitalWrite(yellow2, Y2[Key]);
    digitalWrite(red2, R2[Key]);
    if (Ctr++ >= Tm[Key]) {
      Ctr = 0;
      Key++;

    }
  }

  // you have plenty of spare processor time do other **non blocking** code here (No delay(); )
}

Just to give another option, you could define program states of green, yellow and red lights. Each time through loop() look at the state and set the pins accordingly. Mark the start of each state using millis() and change it when it reaches the desired threshold. When the button is pressed set the state to red light and turn off all yellow or green lights. The code below demonstrates this strategy.

An interrupt service routine should never, ever, have a 5 second delay (note that delay() does not work anyway).

volatile int red1 = 13;
volatile int yellow1 = 12;
volatile int green1 = 11;
volatile int red2 = 10;
volatile int yellow2 = 9;
volatile int green2 = 8;

int switch1 = 2;

// possible states
const int GREEN_LIGHT = 1;
const int YELLOW_LIGHT = 2;
const int RED_LIGHT = 3;

// pins for moving street (green or yellow) and stopped (red) lights
int moveLightPin;
int stoppedLightPin;

// desired time for each state
const unsigned long GREEN_TIME = 15000UL;
const unsigned long YELLOW_TIME = 2500UL;
const unsigned long RED_TIME = 1500UL;
const unsigned long EMERGENCY_TIME = 5000UL;

volatile unsigned long stateStart;   // when we entered current state
volatile unsigned long steteLen;     // length of current state

volatile int currentState = GREEN_LIGHT;  // traffic light state

void setup() {
  pinMode(red1, OUTPUT);
  pinMode(yellow1, OUTPUT);
  pinMode(green1, OUTPUT);
  pinMode(red2, OUTPUT);
  pinMode(yellow2, OUTPUT);
  pinMode(green2, OUTPUT);

  pinMode(switch1, INPUT);
  attachInterrupt(digitalPinToInterrupt(switch1), Lane1E, CHANGE);

  // set up state start time, length
  stateStart = millis();
  steteLen = GREEN_TIME;
  moveLightPin = green1;
  stoppedLightPin = red2;;

}

void Lane1E () {


  digitalWrite(green1, LOW);
  digitalWrite(green2, LOW);
  digitalWrite(yellow1, LOW);
  digitalWrite(yellow2, LOW);

  // set state
  currentState = RED_LIGHT;

  // mark start time
  stateStart = millis();

  // set length
  steteLen = EMERGENCY_TIME;


}

void loop() {


  switch ( currentState)
  {
    case GREEN_LIGHT:
    case YELLOW_LIGHT:

      // if still in this state
      if ( (millis() - stateStart) < steteLen )
      {

        digitalWrite(moveLightPin, HIGH);
        digitalWrite(stoppedLightPin, HIGH);

      } else {

        // if advancing to yellow light
        if ( currentState == GREEN_LIGHT )
        {

          // set state
          currentState = YELLOW_LIGHT;

          // turn off green light
          digitalWrite(moveLightPin, LOW);

          // switch pin for moving street
          moveLightPin = (moveLightPin == green1) ? yellow1 : yellow2;

          // mark start time
          stateStart = millis();

          // set length
          steteLen = YELLOW_TIME;

        } else {

          // red light

          // swap moving and stopped lights, turn off yellow
          if ( moveLightPin == yellow1 )
          {

            moveLightPin = green2;
            stoppedLightPin = red1;
            digitalWrite(yellow1, LOW);

          } else {

            moveLightPin = green1;
            stoppedLightPin = red2;
            digitalWrite(yellow2, LOW);

          } // else

          // set state
          currentState = RED_LIGHT;

          // mark start time
          stateStart = millis();

          // set length
          steteLen = RED_TIME;


        } // else


      } // else


      break;


    case RED_LIGHT:

      // if still in this state
      if ( (millis() - stateStart) < steteLen )
      {

        digitalWrite(red1, HIGH);
        digitalWrite(red2, HIGH);

      } else {

        // set state
        currentState = GREEN_LIGHT;

        // mark start time
        stateStart = millis();

        // set length
        steteLen = GREEN_TIME;

      } // else

      break;

    default:

      break;


  }


}

I have been working around with Interrupts on my latest projects. After tinkering around with that, I have found that delay() does not work within a Interrupt function.

What I want to do is to call loop() when the Interrupt is triggered. So, if I were to just call loop() right in the Interrupt function, they would work but the delay() functions don't work (Everything is running without the delays).

I have 2 questions, first question: is there an alternative to an Interrupt in this situation, and my second question is: can you run loop() all again if the Interrupt is triggered?

If anyone has a solution, please provide an example. I would appreciate some help.

Thanks!

What I want to do is to call loop() when the Interrupt is triggered.

No you don't; loop() has already been called by main()

is there an alternative to an Interrupt in this situation

You haven't adequately described your situation.

Is there an alternative for the Interrupt function? What I want is loop() to run FROM THE BEGINNING!!!

What you want and what is sensible and achievable are probably not the same thing.

See reply #1

Rasbir16:
Is there an alternative for the Interrupt function? What I want is loop() to run FROM THE BEGINNING!!!

Just include the line

return;

anywhere in loop() and the control will go back to main() which will call loop() again.

loop() is just a normal C/C++ function.

...R

...but obviously, a return from an ISR, will simply ... return. To the next instruction.

I want the loop to restart through the Interrupt Function, so what should I put in the Interrupt Function?

Please see reply #3

Sorry, I did not understand you. I am a beginner and I would appreciate if you give an example.

Tell us what you are trying to do, not how you imagine the mechanism to achieve that would look.

An interrupt is exactly that - you don't know when it will come.

He's trying to point you to the part where he asked you to better describe what you are trying to do. How you envision doing it is nonsense, so maybe if we knew what you were actually trying to accomplish and what your code looked like we might could help you figure out a better way.

Rasbir16:
I want the loop to restart through the Interrupt Function, so what should I put in the Interrupt Function?

Rasbir16:
Is there an alternative for the Interrupt function? What I want is loop() to run FROM THE BEGINNING!!!

Interrupt returns to exactly where it was (unless you reboot the board), so you better give up interrupts.
Your code is blocking with delays. Without blocking code there is no need for interrupt. You can easily have the code to do exactly what you want after the emergency switch is triggered.

In reply #1 you have an example of millis based approach. It is not very newbie-friendly code, but you can always try it and come back and ask for explanation for the parts that is unknown.

AWOL:
...but obviously, a return from an ISR, will simply ... return. To the next instruction.

I meant that the OP should use return instead of using an ISR. As far as I can tell he only thought of using an ISR as piece of band-aid.

...R