Interrupt does not switch between ISR's properly

I am using an Interrupt to switch between two ISR’s when a switch is pressed. Both ISR’s contain the "millis’ function (but not the delay function).

My problem is that when the switch is pressed the Arduino leisurely finishes whatever ISR it is currently running before switching to the new one. Instead I would like it to quit the current routine immediately and begin the other routine.

This problem has me puzzled for several days. Is there a solution?

Here is my code (first an explanation of what I’m trying to do):
For this project I need a cart to drive back and forth on a track. The cart is powered by a stepper motor.
Based on the location on the track, the Arduino has to execute two different routines. If the cart is in the middle section it has to execute the DriveRoutine. If the cart is on one of the end sections it has to execute the ReverseRoutine. A switch is activated at the transition point between middle and end sections.

Here is a paraphrase of the ReverseRoutine:
//Drive at Speed 50 for 1 second
//Stop for 1 second
//Reverse direction
//Drive at Speed 50 until the switch is activated

 const int DIR_PIN = 3;
 const int STEP_PIN = 4;
 const int interruptSW = 0;
 const int LED1 = 12; 
 int currentDirection = 1;
 int currentLocation = 1;  
 int var;
 long previousTime = 0;
///SETUP///////////////////////////////////////////////////////////////////////////////////
 void setup (){
 pinMode (interruptSW, INPUT);
 pinMode (DIR_PIN, OUTPUT);
 pinMode (STEP_PIN, OUTPUT);
 pinMode (LED1, OUTPUT);
 attachInterrupt(interruptSW, locationChange, FALLING);}
///LOOP////////////////////////////////////////////////////////////////////////////////////
 void loop (){
 if (currentLocation == 1)
 {driveRoutine(400, 5000);
 var = 0;}
 else
 {reverseRoutine();};
 digitalWrite(LED1, currentLocation);}
///DRIVE ROUTINE////////////////////////////////////////////////////////////////////////////
 void driveRoutine(long Speed, int Steps){
 while(var < Steps)
 {digitalWrite(DIR_PIN, currentDirection);                             // 1 = Forward; 0 = Backward
 unsigned long timeSinceStartup = micros();
 if (timeSinceStartup - previousTime > Speed){
 digitalWrite(STEP_PIN, HIGH);};
 if (timeSinceStartup - previousTime > (Speed * 2)){
 digitalWrite(STEP_PIN, LOW);
 previousTime = timeSinceStartup;
 var++;};};}
///REVERSE ROUTINE//////////////////////////////////////////////////////////////////////////
 void reverseRoutine (){
 driveRoutine(800,2000);
 var = 0;
 driveRoutine(500000,3);
 var = 0;
 currentDirection =! currentDirection;
 driveRoutine(800,2000);
 var = 0;
 }
///INTERRUPT (including debounce)///////////////////////////////////////////////////////////
 void locationChange (){                                        // 1 = middle; 0 = end
 static unsigned long last_interrupt_time = 0;
 unsigned long interrupt_time = millis();
 if (interrupt_time - last_interrupt_time > 100)                // If interrupts come faster than 100ms, assume it's a bounce and ignore
 {if (currentLocation == 1)                                     // 1 = middle; 0 = end
 {currentLocation = 0;}                                     // 1 = middle; 0 = end                           
 else 
 {currentLocation = 1;};}                                           // 1 = middle; 0 = end
 last_interrupt_time = interrupt_time;}

I can’t see anything in your ISR that tells the rest of the code to exit early - change this while(var < Steps) statement to test an exit early flag which is set in your interrupt routine

while((var < Steps) && bExitEarly == false)
{
...
}

A little comment on your code -

 {if (currentLocation == 1)                                     // 1 = middle; 0 = end
 {currentLocation = 0;}                                     // 1 = middle; 0 = end                           
 else 
 {currentLocation = 1;};}

Your comments are a bit pointless, you should use a few defines instead -

// put these at the top of your sketch
#define LOCATION_END 0
#define LOCATION_MIDDLE 1

// then write code like this 

  // toggle location - this comment just says what the code does, and does not need to explain magic numbers like 0 and 1
  if (currentLocation == LOCATION_MIDDLE)
  {
    currentLocation = LOCATION_END;
  } 
 else 
 {
  currentLocation = LOCATION_MIDDLE;
 }
 bExitEarly = true; // tell our drive routine to exit, we need to do something else

Duane B

rcarduino.blogspot.com

My problem is that when the switch is pressed the Arduino leisurely finishes whatever ISR it is currently running before switching to the new one.

Leisurely? locationChange looks like about 200 machine instructions. Which is about 200/16000000*1000000 = 12 milliseconds. Are you honestly going to try to convince us that you have a stepper motor + cart that responds to a signal change within 12 milliseconds?

Instead I would like it to quit the current routine immediately and begin the other routine.

That is a very very very bad idea. Did I mention that's a bad idea?

Switches. Motors. Carts. From a 16 MHz processor's perspective, all slow things. There is nothing in your description or your code to indicate interrupts are necessary. Why are you using them?

Could you post the whole of your code. I don't see any ISR's in what you did post!

Mark

I can’t see anything in your ISR that tells the rest of the code to exit early - change this while(var < Steps) statement to test an exit early flag which is set in your interrupt routine

Code:
while((var < Steps) && bExitEarly == false)
{

}

Thanks DuaneB, for your comments. Could you give some more information about the exit early flag? I received my Arduino less than 2 weeks ago so I am still very new to all of this. Any help is appreciated.

You are right about my lack of good comments. In the future I will make my code more readable for posting. Thanks for the tip.

Leisurely? locationChange looks like about 200 machine instructions. Which is about 200/16000000*1000000 = 12 milliseconds. Are you honestly going to try to convince us that you have a stepper motor + cart that responds to a signal change within 12 milliseconds?

Coding Badly, the delay in switching between ISR’s takes several seconds. The Arduino doesn’t stop the current routine, but it finishes it completely before going to the next routine. I’m sure the fault lies in my code.
As I said, I am still very new to this, but thanks for your input!

I don’t see any ISR’s in what you did post!

Mark, I have an interrupt at the end of my code. The interrupt sets the variable “currentLocation” to a 1 or 0. Based on that variable the void loop will execute one of two functions.
Does that answer your question, or am I wrong?

Is there a reason you are avoiding a Stepper library?

Is there a reason you are avoiding a Stepper library?

I'm just not familiar with that yet. I have to look into that.

make one masterIsr(), no need to swith isr()S

void masterIsr()
{
  if (switch == HIGH) isr1();  // best to be implemented with direct port manipulation
  else isr2();
}

ANd please use CTRL-T in your IDE to restyle the code, looks so much better (thank you :slight_smile: