Using Interrupt to return to the Main loop

Hi Guys

Can someone please advise if it is possible to use an interrupt to return to the main loop in a program. I am using an Arduino Nano to control some RGB lighting. There are several scenes programmed into the system and when the user clicks a button the scene needs to change to the next one. The button is on digital Pin 2 with a interrupt attached. My issue is that each scene is a seperate function from the main and if i just use a return statement then the program goes back to the function it was in and not back to main to go to the next scene. Simplified code below:

define Red 3

define Green 5

define Blue 6

define White 9

define button 2

void ButtonPress(); void Scene1(); void Scene2();

void setup() { Serial.begin(9600);

attachInterrupt(digitalPinToInterrupt(2), ButtonPress, RISING); //enable interrupt on pin 2 }

void loop() {

switch (Scene) { case 1: Scene1(); break; case 2: Scene2(); break; default: Scene1(); } }

void ButtonPress() { if button pressed increment scene return to main loop }

void Scene1() { Stuff }

void Scene2() { Different stuff }

I understand the code is simplified but, is there a statement somewhere at the top to the effect of:
volatile byte Scene; ?

Can you post the actual code enclosed in </> code tags?

Unfortunately, the answer is yes. You can use longjmp to do this. But I really don't recommend it - the correct way to go about this sort of thing is with the usual "delay without millis" pattern. Or, if you must use delay, you could have the yeild() function check the button and use longjmp from there.

The thread title asks whether something is possible then you describe the problem. The question would be better posed by describing the problem not a possible (actually impossible) solution.

As suggested above, the best solution is to use millis() for timing so that loop() repeats very quickly. This enables you to read inputs each time through loop() and react to them rather than having a multitude if input checks in each function.

I would suggest that you restructure your code such that each of your Scene functions is a block of code that uses millis() to determine whether it is time to do something such as change an LED pattern. If so, then do it and return to loop(). If not then do nothing and return to loop().

Read inputs in loop(), perhaps at the start of the function, and react to changes by tidying up the LED pattern (turn them all off maybe) and start running the new Scene.

You may get some ideas from Using millis() for timing. A beginners guide and Several things at the same time

Unsaid, but implied, in all of the replies is that there is no reason to use interrupts to processes user button inputs. A well-written, non-blocking loop function and non-blocking LED scene functions can do it all and responses to user inputs will appear to be instantaneous.

To summarise the replies above.

Don't leave the loop() function for more than a very small fraction of a second. Then there is no need to return to it under particular circumstances.

@WolMat

The codes of the attached file (slight modification of your codes) may help you to solve your problem in a way you have wanted – return from ISR strategy. I have tested the program having two LEDs: DPin-7 for Scene1(); and DPin-6 for Scene2();. You might need to interface the Button by strong hardware or software debouncer to prevent multiple triggering. I have tested using 74LS123 based debouncer.

ProgrammingOct31.ino (911 Bytes)

@GolamMostafa

How about a short version of the program ? (Errors corrected and with minimum memory and cycle times)

byte Scene=0;

void setup() 
{ DDRB |= B00100000; DDRD = B11111011 & (DDRD | B11000000);
  attachInterrupt(digitalPinToInterrupt(2), ButtonPress, FALLING);
}
void loop() { PORTB ^= B00100000; delay(200); }

void ButtonPress()
{ cli();
     if(Scene) { Scene1(); }
     else      { Scene2(); }
     delay(1000);
  sei();
}   
void Scene1() { PORTD = B01111111 & (PORTD | B01000000); Scene=0; }
void Scene2() { PORTD = B10111111 & (PORTD | B10000000); Scene=1; }