Arduino programming guide series
Can you use delay() inside Interrupt Service Routine?
An interrupt service routine (ISR) looks like a regular function. It can hold any code you want, and it will work as it would in any other function.
But, the ISR is not a regular function, and you should treat it as special.
The ISR is a function that is registered to be called when an interrupt event occurs. For example, this interrupt can be a change in the state of an interrupt-capable pin, or the expiration of a timer (here's an example sketch of a timer interrupt).
A question I often receive is about the contents of the ISR:
- "Can I include arbitrary code?"
- "Can I include slow functions like delay() or even Serial.print()?"
Although this is possible, you should not.
Both delay() and Serial.print() functions are "blocking". This means that they stop anything else from happening in the Arduino.
The delay() function will make the Arduino stop until your specified interval has expired. The Serial.print() function will also make the Arduino stop until the entire message has been printed to the serial monitor at the slow communication speeds of the serial interface.
An interrupt service routine should be as light as possible so that it can service an interrupt quickly. The objective is to allow the Arduino to continue doing what it was doing before the interrupt.
If you use a delay(5) inside the ISR, you will be blocking the processor for at least 5ms, which for a computer is a lot of time.
If you need to check the passage of time inside the ISR, it is much better to use an "if" statement, like I discussed in a separate article.
The Arduino will be able to process the "if" statement within a few nanoseconds, and quickly return control of the program to the code outside of the ISR.
Here is an example sketch showing how to write an ISR that uses the "if" statement to assess the passage of time. This example is from Arduino Step by Step Getting Serious, where I show how to use a rotary encoder.
I have highlighted the relevant block in bold.
You can see this code on Github.
//Original sketch: https://bigdanzblog.wordpress.com/2014/08/16/using-a-ky040-rotary-encoder-with-arduino/
//Modified by Peter Dalmaris, July 2015
const int PinCLK=2; // Used for generating interrupts using CLK signal
const int PinDT=3; // Used for reading DT signal
const int PinSW=8; // Used for the push button switch
volatile long virtualPosition =0; // must be volatile to work with the isr
void isr0 () {
detachInterrupt(0);
static unsigned long lastInterruptTime = 0;
unsigned long interruptTime = millis();
// If interrupts come faster than 5ms, assume it's a bounce and ignore
if (interruptTime - lastInterruptTime > 5) {
if (!digitalRead(PinDT))
virtualPosition++;
else
virtualPosition--;
}
lastInterruptTime = interruptTime;
attachInterrupt (0,isr0,RISING);
} // ISR0
void setup () {
pinMode(PinCLK,INPUT);
pinMode(PinDT,INPUT);
pinMode(PinSW,INPUT);
attachInterrupt (0,isr0,RISING); // interrupt 0 is always connected to pin 2 on Arduino UNO
Serial.begin (9600);
Serial.println("Start");
}
void loop () {
int lastCount = 0;
while (true) {
if (!(digitalRead(PinSW))) { // check if pushbutton is pressed
virtualPosition = 0; // if YES, then reset counter to ZERO
while (!digitalRead(PinSW)) {} // wait til switch is released
delay(10); // debounce
Serial.println("Reset"); // Using the word RESET instead of COUNT here to find out a buggy encoder
}
if (virtualPosition != lastCount) {
lastCount = virtualPosition;
Serial.print("Count:");
Serial.println(virtualPosition);
}
} // while
}
Done with the basics? Looking for more advanced topics?
Arduino Step by Step Getting Serious is our comprehensive Arduino course for people ready to go to the next level.
Learn about Wi-Fi, BLE and radio, motors (servo, DC and stepper motors with various controllers), LCD, OLED and TFT screens with buttons and touch interfaces, control large loads like relays and lights, and much much MUCH more.
Jump to another article
3. Focus on the type parameter in "println()"
4. "0" or "A0" when used with analogRead()?
5. What is the "_t" in "uint8_t"?
6. Save SRAM with the F() macro
7. What is the gibberish in the Telnet output?
9. Confusing keywords? follow the source code trail
10. The interrupt service routine and volatile variables
11. The problem with delay() and how to fix it
12. How to deal with the millis rollover
13. Can you use delay() inside Interrupt Service Routine?
15. A closer look at line feeds and carriage returns
16. Understanding references and pointers
17. Simple multitasking on the Arduino
19. Concurrency with the Scheduler library on the Arduino Due and Zero
20. Bitshift and bitwise OR operators
21. What is a "static" variable and how to use it
22. Understanding the volatile modifier
Last Updated 8 months ago.
We publish fresh content each week. Read how-to's on Arduino, ESP32, KiCad, Node-RED, drones and more. Listen to interviews. Learn about new tech with our comprehensive reviews. Get discount offers for our courses and books. Interact with our community. One email per week, no spam; unsubscribe at any time