Traffic lights with maintenance button and interrupt

Hello, i am pretty new to arduino and is seeking assistance,
so i had a school project with trafficlights where the project was to make one function for a normal trafficlight sequence and another function for a "maintenance" sequence.

In the maintenance sequence the lights will always blink yellow if the button is low and then if the button is HIGH it will return with the value 1, if the value is 1 in that if statement, then it will return to the void loop.

I wanted to add in a interrupt to that code so that if the normal traffic light loop is running then i can interrupt it and start the yellow blinking instantly, and then with another push of the "Maintenance" button i want to stop the yellow blinking and go back to void loop.

i got the interrupt working but it seems to jump back to the while loop (Without completing it) so my question is if anyone could help me make this code work?

Code:

// Definerer utganger til konstante variabler
int const BUTTON_A = 8; // Trykknapp
int const BUTTON_B = 2; // Trykknapp

int const LED_ROD = 6; // Rødt lys
int const LED_GUL = 5; // Gult lys
int const LED_GRONN = 4; // Grønt lys
int const LED_ROD1 = 3; // Rødt lys
int const LED_GUL1 = 7; // Gult lys
int const LED_GRONN1 = 1; // Grønt lys

// Definerer verdi til variabler som vil endres når programmet kjører
int Button_State_A = 0;
volatile int Button_State_B = 0;
int last_state = LOW; // Viser knappen sin siste posisjon

void setup() 
{
  pinMode(13, OUTPUT);
  pinMode(LED_ROD, OUTPUT); // Sitter LED som utgang
  pinMode(LED_GUL, OUTPUT); // Sitter LED som utgang
  pinMode(LED_GRONN, OUTPUT); // Sitter LED som utgang
  pinMode(LED_ROD1, OUTPUT); // Sitter LED som utgang
  pinMode(LED_GUL1, OUTPUT); // Sitter LED som utgang
  pinMode(LED_GRONN1, OUTPUT); // Sitter LED som utgang
  pinMode(BUTTON_A, INPUT); // BUTTON_A (Knapp A) som inngang
  pinMode(BUTTON_B, INPUT); // BUTTON_B (Knapp B) som inngang
}

void loop() 
{
  digitalWrite(LED_GRONN1, HIGH);
  digitalWrite(LED_ROD, HIGH);
//Definerer at Button_State_X leser av verdien til BUTTON_X).
  Button_State_A = digitalRead(BUTTON_A);
  attachInterrupt(0, pin_mode, CHANGE);
  
  if  (Button_State_A == HIGH && last_state == LOW)
  {
  delay(50);
  digitalWrite(13, LOW);
  trafikklys();
  }
  
}

int pin_mode() {

  Button_State_B = digitalRead(BUTTON_B);
  int retur = gulelys();
  if (Button_State_B == HIGH)
  {
    gulelys();
  }
  if(retur == 1)
  {
  return;
  }
}

  void trafikklys() // kjører trafikklys sekvens når knapp A er trykket
  {
    delay(1000);
    digitalWrite(LED_GUL, LOW);
    digitalWrite(LED_GUL1, LOW);
    delay(50);
    digitalWrite(LED_GRONN1, LOW);
    digitalWrite(LED_GUL1, HIGH);
    delay(500);
    digitalWrite(LED_GUL1, LOW);
    digitalWrite(LED_ROD1, HIGH);
    delay(500);
    digitalWrite(LED_ROD, HIGH);
    digitalWrite(LED_GUL, HIGH);
    delay(500);
    digitalWrite(LED_ROD, LOW);
    digitalWrite(LED_GUL, LOW);
    digitalWrite(LED_GRONN, HIGH);
    delay(2000);
    digitalWrite(LED_GRONN, LOW);
    digitalWrite(LED_GUL, HIGH);
    delay(500);
    digitalWrite(LED_GUL, LOW);
    digitalWrite(LED_ROD, HIGH);
    delay(500);
    digitalWrite(LED_ROD1, HIGH);
    digitalWrite(LED_GUL1, HIGH);
    delay(500);
    digitalWrite(LED_ROD1, LOW);
    digitalWrite(LED_GUL1, LOW);
    digitalWrite(LED_GRONN1, HIGH);
    }
    

int gulelys() // Kjører gulelys sekvens når knapp B er trykket
{
  while (digitalRead(BUTTON_B) == LOW)
  {
    detachInterrupt(0);
    digitalWrite(13, HIGH);
    digitalWrite(LED_ROD, LOW);
    digitalWrite(LED_ROD1, LOW);
    digitalWrite(LED_GRONN, LOW);
    digitalWrite(LED_GRONN1, LOW);
    digitalWrite(LED_GUL, HIGH);
    digitalWrite(LED_GUL1, HIGH);
    delay(500);
    digitalWrite(13, LOW);
    digitalWrite(LED_ROD, LOW);
    digitalWrite(LED_ROD1, LOW);
    digitalWrite(LED_GRONN, LOW);
    digitalWrite(LED_GRONN1, LOW);
    digitalWrite(LED_GUL, LOW);
    digitalWrite(LED_GUL1, LOW);
    delay(50);
  }
  return 1;
  attachInterrupt(0, pin_mode, CHANGE);
}

Hello, so i had a school project with trafficlights where the project was to make one void for a normal trafficlight sequence and another void for a "maintenance" sequence.

I am ABSOLUTELY certain that THAT was NOT the project.

They are called FUNCTIONS! Not void. That applies to space between your ears.

I wanted to add in a interrupt to that code so that if the normal traffic light loop is running then i can interrupt it and start the yellow blinking instantly

No you don't. You want to delete all that code and start again, writing non-blocking code that does NOT use delay().

Well, the point of adding in the interrupt was to learn how to use interrupt in that code. does interrupt. i was told by the teacher that i can either do interrupt or Millis. And yeah i didn't think about the "void" when i just made this post.. i meant functions xD my bad

I suspect that if you decide to use an interrupt you will be going down a very deep rabbit hole. A state machine using millis() for timing will be easier to test and maintain.

Have you read and understood Using millis() for timing. A beginners guide, Several things at the same time and look at the BlinkWithoutDelay example in the IDE.

i was told by the teacher that i can either do interrupt or Millis.

Then use millis().

If you connect a switch to an external interrupt pin, and attach an interrupt handler, the interrupt handler will NOT be able to change what is happening. All that it can do is set a flag to indicate that the interrupt happened.

You would then have to check the flag everywhere in your code, and return when then flag was set, and then have loop() determine what to do if the flag is set. That won't immediately terminate a delay(), so you'd have to rewrite your code extensively anyway.

The trouble with the misguided attempt to use interrupts in such an application is that (as OP discovered) after the ISR runs, code execution continues at the place in the main code where the interrupt occurred.

You can’t direct the post-interrupt execution sequence from within the ISR. The best you can do is set a (volatile) flag in the ISR that you then need to poll for in the main code. If you’re going to do that, you might as well just poll for the condition directly in the main code and forget using interrupts / ISR all together.

Edit:
Looks like @PaulS beat me to the click by about 2 seconds.

UKHeliBob:
I suspect that if you decide to use an interrupt you will be going down a very deep rabbit hole. A state machine using millis() for timing will be easier to test and maintain.

Have you read and understood Using millis() for timing. A beginners guide, Several things at the same time and look at the BlinkWithoutDelay example in the IDE.

I Could also use millis and i understand it, but my teacher said that if we managed to use interrupt instead of millis then the code would look a lot better. so i'm looking for advice on using interrupt :stuck_out_tongue:

Darkredeemer:
I Could also use millis and i understand it, but my teacher said that if we managed to use interrupt instead of millis then the code would look a lot better.

That's a questionable assertion at best.

so i'm looking for advice on using interrupt :stuck_out_tongue:

So, use the techniques outlined in Reply 4 and Reply # 5.

my teacher said that if we managed to use interrupt instead of millis then the code would look a lot better.

Have it your, or your teacher's, way but using an interrupt will be much messier than using millis()

A well laid out state machine using an enum for the system states, millis() for timing and meaningful variable names or #defined values will look a lot better in my opinion.

If you do decide to use an interrupt then do not be suckered into implementing the maintenance mode in the ISR. ISRs should be short functions that do very little apart from flagging that the interrupt has occurred and maybe saving the time of the interrupt. Bear in mind that interrupts are disabled when in an ISR so that you cannot use any functions such as delay() that depend on them.

UKHeliBob:
Have it your, or your teacher's, way but using an interrupt will be much messier than using millis()

A well laid out state machine using an enum for the system states, millis() for timing and meaningful variable names or #defined values will look a lot better in my opinion.

If you do decide to use an interrupt then do not be suckered into implementing the maintenance mode in the ISR. ISRs should be short functions that do very little apart from flagging that the interrupt has occurred and maybe saving the time of the interrupt. Bear in mind that interrupts are disabled when in an ISR so that you cannot use any functions such as delay() that depend on them.

After reading all these advices, i think interrupt is way to advanced compared to millis, atleast i understand millis and i think i might just use that, and i believe my teacher was wrong about the interrupt being "nicer" than millis :o

i believe my teacher was wrong about the interrupt being "nicer" than millis

Teachers are never wrong. Some are misguided, but they are never wrong. Just ask them.

I thought I was wrong once, but I was mistaken.

evanmars:
I thought I was wrong once, but I was mistaken.

No, you weren't.