[SOLVED] Is there any way to "delay()" (or equivalent) within an interrupt?

I have searched and tried what looked like some solutions but have not found anything yet.

I have spent hours looking for some solution to wait or delay after an interrupt has been triggered.

Is there any way to "delay()" (or equivalent) within an interrupt?

Thanks,
Will

Update: The Solution Implemented

volatile byte HumanDetected = 0; // Interrupt var

void setup()
  {
    attachInterrupt (0, pinChange, HIGH);  // PIN2 is "Interrupt 0"
    Serial.begin(9600);
  }

// Interrupt Service Routine (ISR)
void pinChange ()
  {
    HumanDetected = 1;
  }

void loop() 
 {
   if (HumanDetected == 1)
     {
       StopforHuman();
     }
 }

void StopforHuman()
  {
    Serial.println("Stopped for Human");
     for (byte x = 4; x >= 1; x--)
	  {
            delay(1000);
            Serial.print(x);
	  }
    //Read all Human Sensors and check if clear otherwise loop
    while (digitalRead(2) == 0) ; // do nothing until == 1 (or is it anything other then "0"?)
    HumanDetected = 0; // If all sensor is clear reset volatile var for Interrupt
  }

Hard to give advice without any idea of the application.

What you can do is set a flag/status from the interrupt routine to signal that the interrupt has occurred. Then somewhere else (like loop()) count up time until the required delay has happened. You should always make your interrupt routines as fast as possible, so any form of lingering in the ISR is a generally bad idea.

wballum:
...after an interrupt has been triggered.

What you mean? Waiting some time in the code of the function executed when interrupt trigger?

wballum:
Is there any way to "delay()" (or equivalent) within an interrupt?

Why do you want to, and how long do you want to delay for?

It is not a good idea to delay during an interrupt because they are done to do a fast operation with precise temporization (ie when you press a button or when a time last since previous interrupt... So I think that would be better is you change your code a little bit so that the interrupt occurs only when a particular action is done, for example a button press and the delay will be outside the interrupt itself. Remember that delayMicroseconds(long) function disable interrupts (if I don't remember badly) and so you can use it to change your temporization.
With more precise information maybe I could help in a better way!
Regards

You can use _delay_us(). It basically sets up a tight loop with exact parameters and puts it inline. #include <utils/delay.h> and you're good to go.

You can use _delay_ms() as well, but remember that interrupts are disabled by default in your ISR, so delaying that long you'll likely miss timer overflow interrupt(s).

Here is a simplified Sketch I use to wait after an interrupt using a Flag :

setup()
{
 pinMode(34, INPUT);   
 attachInterrupt(34,handleTopRise,RISING);
 holdTime = 200; // milliseconds to wait between refresh cycles.
}

void loop()   
 {
    perform();
  }

void handleTopRise()
   {
   shadowTopRise[topRiseCount] = micros();
   topRiseCount++;
   }

void perform()
   {
   if (topRiseCount != drum1Flag)
      {  
      drum1Flag = topRiseCount;
      unsigned long now=millis();                  
      if ((now - previousRefreshTime) > holdTime)
         {
          Serial.print (activeVCO); 
          previousRefreshTime = now;
         }
      }
  }

As others have said it is unwise to introduce delays into an ISR. Usually it is not necessary. Maybe reading serial data in a specifically timed sequence (like SoftwareSerial) might be an exception.

" it is unwise to introduce delays into an ISR." Like a Serial.print...

Yes, Nick you are right, I rushed to post a simplified Sketch and left in a Serial.print, a bad choice. Here is an improved version :

// Rev. 2
setup()
{
 pinMode(34, INPUT);   
 attachInterrupt(34,handleTopRise,RISING);
 holdTime = 200; // milliseconds to wait between refresh cycles.
}

void loop()   
 {
    perform();
  }

void handleTopRise()
   {
   shadowTopRise[topRiseCount] = micros();
   topRiseCount++;
   }

void perform()
   {
   if (topRiseCount != drum1Flag)
      {  
      drum1Flag = topRiseCount;
      unsigned long now=millis();                  
      if ((now - previousRefreshTime) > holdTime)
         {
          refresh();
          previousRefreshTime = now;
         }
      }
  }

It also looks like you have an undefined array.

The point of an interrupt routine is to service an urgent hardware event. If you
are finding you want to wait around in one, clearly you haven't understood the
purpose of interrupts. Delays aren't really urgent (unless a few us). The response
to any interrupt is limited by the slowest interrupt routine in use. If you only have
one source of interrupts and know what you're doing you can break this rule, but
its a rare situation.

One fairly common use-case is an interrupt handler scheduling another
interrupt at a later point in time - for this a hardware timer is used.

Other approaches are having a repetitive timer interrupt firing all the time to test
for semi-urgent events and scheduling its own future events using the BlinkWithoutDelay
paradigm. This uses up a certain proportion of the processor time, but in return you
relax the need for the rest of the code to adhere to real-time constraints. You can think
of this as a higher-urgency version of loop()

AmbiLobe:
Yes, Nick you are right, I rushed to post a simplified Sketch and left in a Serial.print, a bad choice. Here is an improved version :

That still doesn't compile let alone work, and doesn't demonstrate any of the techniques that would be required to use interrupts safely.

Interrupts introduce considerable issues and should IMO be used only when necessary, and then only reluctantly and with the logic kept as simple as possible. Wanting to introduce delays into an interrupt handler suggests that the handler is trying to do too much. In the absence of any information about the system, I wonder whether it actually needs to use interrupts at all.

marco_c:
Hard to give advice without any idea of the application.

What you can do is set a flag/status from the interrupt routine to signal that the interrupt has occurred. Then somewhere else (like loop()) count up time until the required delay has happened. You should always make your interrupt routines as fast as possible, so any form of lingering in the ISR is a generally bad idea.

Thanks for your reply; this is what I ended up doing.

volatile byte HumanDetected = 0; // Interrupt var

void setup()
  {
    attachInterrupt (0, pinChange, HIGH);  // PIN2 is "Interrupt 0"
  }

// Interrupt Service Routine (ISR)
void pinChange ()
  {
    HumanDetected = 1;
  }

void loop() 
 {
   if (HumanDetected == 1)
     {
       StopforHuman();
     }
 }

void StopforHuman()
  {
    Serial.println(" ");
    Serial.println("Stopped for Human");
     for (int x = 4; x >= 1; x--){
       delay(1000);
       Serial.print(x);
     }
    //Read all Human Sensors and check if clear otherwise loop
    STATE = digitalRead(2);
    if (STATE == 0){
      StopforHuman(); // Ouroboros ;)
    }
    // If all sensor is clear reset volatile var for Interrupt
    HumanDetected = 0;
  }

Thanks to everyone that replied. If you want critique the above code. I need all the help I can get. :wink:

Recursion is usually not a good thing with Arduino, due to the tiny size of the stack. You may want to convert that call to StopForHuman() inside the StopForHuman() procedure to a loop. Or, just return without setting HumanDetected to 0 and loop() will immediately call StopForHuman() again.

Where do you declare STATE? It is convention to use all upper case for #define constants. Using it for a temp variable is a little bit confusing.

    STATE = digitalRead(2);
    if (STATE == 0){
      StopforHuman(); // Ouroboros ;)
    }

is the same as

while (digitalRead(2) == 0)
  ; // do nothing

with no recursion.

You do know that the processor will appear to just stop and actually do nothing while this loop is running?

     for (int x = 4; x >= 1; x--){
       delay(1000);
       Serial.print(x);
     }

Are you sure you don't want to use a long (or maybe a long long) for your index variable? After all, it does need to count all the way up to 4.

Steady, Paul. All the programming texts recommend int for integers.

marco_c:

    STATE = digitalRead(2);

if (STATE == 0){
      StopforHuman(); // Ouroboros :wink:
    }




is the same as



while (digitalRead(2) == 0)
  ; // do nothing




with no recursion.

You do know that the processor will appear to just stop and actually do nothing while this loop is running?

This worked very well thanks.

PaulS:

     for (int x = 4; x >= 1; x--){

delay(1000);
       Serial.print(x);
     }



Are you sure you don't want to use a long (or maybe a long long) for your index variable? After all, it does need to count all the way up to 4.

I assume you were trying to be funny or make fun of me to drive a point. Either way is this your point? :wink:

for (byte x = 4; x >= 1; x--){
       delay(1000);
       Serial.print(x);
     }

PaulS likes to encourage people to minimize their use of resources, hence the jesting reference to using an even larger data type.

Using "byte" will use slightly less program memory and execution time, but be aware that it is an unsigned type, so if you had done this it wouldn't have worked:

for (byte x = 3; x >= 0; x--){
       delay(1000);
       Serial.print(x);
     }

That is because a byte type is always >= 0.