0

I am curious if the following scenario is possible.

EICRB |= (0<<ISC60)|(0<<ISC61);
EIMSK |= (1<<INT6);    

ISR(INT6_vect) {
  myISR();
}

void myISR() {
     digitalWrite(led_off, OFF); 
     // Please break my main for loop :)
}

void loop()
{
      for (i=100; i>=0; i--)
             {               

            /* STOP button */
              if (read_switch() == 1) {
                      break;
               }     
           .. delays and other logic ...          
}

As you see the following code is not complete but quite understandable. I have a heating process done in the main program, each loop temp adjustments, printing, delay etc takes about 2-3 seconds to complete. When somebody pushes a switch read_switch will return 1 and that breaks up this function ending the heating process. This works just fine except the user have to hold the button for the time it finishes looping and get to this point again. I have fortunately realized that the switch pin (Arduino promicro pin7) also an interrupt pin so I could do interrupt in real time, as I doing it in other code already.

However what you can do in this ISR routine is limited (eg you cannot print to serial etc). I could setup a global volatile bool variable here of course which would immediately get flipped as the interrupt triggered but it would not solve anything since in the main loop I would have to wait for the next round again.

So is it possible with some hack to tell the ISR to break that for loop (not the whole program with an exit(0)) and continue execution afterwards?

  • 2
    Post a short, self contained, correct (Compilable) sketch (//sscce.org) that show the problem. – user31481 Oct 6 '17 at 9:41
1

No, it's not possible, nor desirable. It's complicated and unnecessary.

What you have to do is:

  1. Declare a volatile global variable (a switch).
  2. Inside ISR, change that switch to signal that a break is needed.
  3. Inside your loop (for, while, ...) test for that global variable and proceed.

This example print "This is the end" each time a button connected to pin 2 is pressed.

volatile bool fin = false; // The switch for ISR-loop communication.

void setup()
{
    Serial.begin(9600);
    pinMode(2, INPUT);  // Read a button or other signal.
    attachInterrupt(0, buttonISR, RISING);
}

void loop()
{
    if(fin) {
        Serial.println("This is the end");
        fin = false; // Reset the switch.
    }
}

void buttonISR()
{
    fin = true;  // Just raise the signal for the main loop.
}

This method keeps ISR ultra-short and there is no mixing between ISR's instructions and loop's instructions. All of your logic reside in the main loop.

0

Turn the loop into a state machine instead.

Wrap the entire loop body in a switch.

Every time you have a delay(t); make it a target for a case label and replace it with

startTimeout = millis(); 
currentState = N;
case N: if(millis() - startTimeout < t) return;

Every for(init; condition; inc) loop that has delays inside them can be replaced with

<init>
state = N;
case N: if(!condition) state = N1;
<body>
<inc>
state = N;
return; //return from loop() and let it restart
case N1;

Then any delay inside body can be adjusted like above.

Make sure that every state case is unique and make any state that needs to persist across states global.

0

Fairly easy to do. In your heater code, tests the state of the switch periodically and exits if the right state is detected.

As to how periodically you should test, it will depend on your requirement for response time.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.