Table of Contents

Interrupts

 General audience classification icon  General audience classification icon  General audience classification icon
Interrupt is a signal that stops the normal execution of a program in the processor and starts the function assigned to a specific source. This function is called Interrupt Service Routine (ISR) or interrupt handler. The ISR can be recognized as a task with higher priority than the main program. Interrupt signals can be generated by the external source, like a change of value on the pin, and by the internal source, like a timer or any other peripheral device. When the interrupt signal is received, the processor stops executing the code and starts the ISR. After completing the interrupt handler, the processor returns to the normal program execution state.

ISR should be as short as possible; good practice is avoiding delays and long code sequences. Suppose there is a need to trigger the execution of a long part of the code with an incoming interrupt signal. In that case, the good practice is to define the synchronization variable, modify this variable in the ISR with a single instruction, and handle all other steps in the main program. The interrupt handler does not have arguments and does not return any value, so its type is void. To ensure fast execution of the programs, some of the Arduino functions do not work or behave differently in the ISR; for example, the delay() function does not work inside the ISR. Variables used in the ISR must be declared as volatile.

Interrupts are used to detect critical real-time events which occur during normal code execution of the code. ISR is executed only when there is a need to do it.

Polling vs. interrupts

Interrupts can help in efficient data transmission. Using interrupts and checking if some situation occurred periodically is unnecessary. Such continuous checking is named polling. For example, a serial port interrupt is executed only when new data comes without polling the incoming buffer in a loop. This approach saves the processor time and, in many situations, creates code that is more energy efficient.

Interrupt handling example

Because interrupts need support from the hardware layer of the microcontroller, the availability of specific interrupt sources depends heavily on the microcontroller model. For example, different Arduino models have different external interrupt pin availability. In most Arduino boards, pins numbered 2 and 3 can be used for interrupts; in Arduino Uno, only these two, while in ESP32 and STM32, almost any digital pin is valid.

Very often, interrupts are used together with hardware timers to generate stable frequency signals. It ensures accurate timing independent of the main loop content and delays. Because internal peripherals are very different for different microcontrollers in this chapter, the example for the external interrupt is shown.

The function attachInterrupt(digitalPinToInterrupt(pin), ISR, mode) is called to attach an interrupt to the handler. This function has 3 arguments.

  1. pin – the pin number where the interrupt signal-generating device will be attached.
  2. ISR – the name of an ISR function.
  3. mode – defines when an interrupt signal is triggered. There are five basic mode values:
    • LOW – interrupt is triggered when the pin value is LOW,
    • HIGH – interrupt is triggered when the pin value is HIGH,
    • RISING – interrupt is triggered when the pin value is changed from LOW to HIGH,
    • FALLING – interrupt is triggered when the pin value is changed from HIGH to LOW,
    • CHANGE – interrupt is triggered when the pin value is changed in any direction.

The example program that uses external interrupt:

volatile bool button_toggle = 0; //A variable to pass the information 
                                 //from ISR to the main program
 
void setup() {  
  pinMode(13,OUTPUT);            //Define LED pin
  pinMode(2,INPUT_PULLUP);       //Define button pin
  attachInterrupt(digitalPinToInterrupt(2),ButtonIRS,FALLING); 
                                 //Attach interrupt to button pin
}
 
void ButtonIRS() {               //IRS function
  button_toggle =!button_toggle;
}
 
void loop() {
  digitalWrite (13,button_toggle);
}

In this example, the code needed to handle the interrupt signal is just one instruction. Still, it shows how to use the synchronization variable to pass information from ISR to the main program, keeping the ISR very short.