{"id":9586,"date":"2023-05-18T15:39:00","date_gmt":"2023-05-18T13:39:00","guid":{"rendered":"https:\/\/deepbluembedded.com\/?p=9586"},"modified":"2023-08-17T23:49:59","modified_gmt":"2023-08-17T20:49:59","slug":"arduino-interrupts-tutorial-examples","status":"publish","type":"post","link":"https:\/\/deepbluembedded.com\/arduino-interrupts-tutorial-examples\/","title":{"rendered":"Arduino Interrupts Tutorial & Examples"},"content":{"rendered":"\n

In this tutorial, we’ll discuss Arduino Interrupts<\/strong> from the very basic concepts all the way to implementing Arduino interrupt-based systems. We’ll start off by discussing what are interrupts, how they work, and what are different types of interrupts. You’ll learn all Arduino interrupts mechanics and how to properly set up an interrupt-based system and write efficient ISRs (interrupt service routines).<\/p>\n\n\n\n

We’ll create a couple of Arduino Interrupt Example Code Projects<\/strong> in this tutorial to practice what we’ll learn all the way through. And finally, we’ll draw some conclusions and discuss some advanced tips & tricks for Arduino interrupts that will definitely help you take some guided design decisions in your next projects. Without further ado, let’s get right into it!<\/p>\n\n\n

Table of Contents<\/h2>\n
    \n
  1. How Interrupts Work?<\/a>\n\n\n<\/li>\n\n
  2. Types of Interrupts<\/a>\n\n\n<\/li>\n\n<\/li>\n\n<\/li>\n\n
  3. Why & When To Use Interrupts?<\/a>\n\n<\/li>\n
  4. Interrupt Service Routines (ISR)<\/a>\n\n<\/li>\n
  5. Arduino Interrupts<\/a>\n\n\n<\/li>\n\n<\/li>\n\n<\/li>\n\n
  6. Using Interrupts in Arduino<\/a>\n\n\n<\/li>\n\n<\/li>\n\n<\/li>\n\n<\/li>\n\n<\/li>\n\n<\/li>\n\n
  7. Arduino External Interrupt Example<\/a>\n\n\n<\/li>\n\n<\/li>\n\n<\/li>\n\n<\/li>\n\n
  8. Guidelines For Writing Efficient Arduino ISRs<\/a>\n\n\n<\/li>\n\n<\/li>\n\n<\/li>\n\n<\/li>\n\n
  9. Remarks on Arduino Interrupts<\/a>\n\n\n<\/li>\n\n
  10. Arduino Interrupts Wrap Up<\/a>\n<\/li><\/ol>\n\n\n
    \n\n\n

    How Interrupts Work?<\/strong><\/h2>\n\n\n

    To better understand interrupts in microcontrollers like Arduino (Atmega328p), Let’s consider the following analogy as an example to demonstrate how interrupts actually work.<\/p>\n\n\n

    Interrupts Analogy<\/strong><\/h3>\n\n\n

    First of all, let’s say you are acting as the (CPU) and your main task is to read a book. But your friend can call you on the phone at any moment to check how you’re doing. Therefore, the phone ringing is considered an interrupt<\/strong>, and your answering the phone is the handling of this interrupt signal.<\/p>\n\n\n\n

    When the phone rings, you need to bookmark or save where you’re currently on the book ( let’s page x, line y). Then, you pick up the phone and get done with it. And you can continue the main work (reading the book) exactly where you left off (page x, line y).<\/p>\n\n\n\n

    If you’re receiving too many calls or taking too long to service each call, you’ll never progress through the main, and most important, task which is reading the book. And this is exactly why we need to limit the number of interrupts the CPU receives per second and also make the ISR (interrupt service routine) handlers as quick as possible.<\/p>\n\n\n\n

    Interrupts are side tasks that the CPU needs to handle as soon as they arrive and it should not take too long doing so. Otherwise, the main program execution will greatly slow down and the responsiveness of the whole system will also deteriorate.<\/p>\n\n\n

    Arduino Interrupts Mechanics<\/strong><\/h3>\n\n\n

    The actual interrupt handling mechanism in Arduino (Atmega328p) microcontroller is very similar to the previous analogy example in the previous section. And it goes like this:<\/p>\n\n\n\n

    \"Arduino-Interrupts\"<\/figure>\n\n\n\n

    <\/p>\n\n\n\n

    When the microcontroller’s CPU receives an interrupt signal, it pauses the main program execution and saves its current context.<\/p>\n\n\n\n

    The CPU then jumps to the interrupt vector (address) where the corresponding ISR handler function is located. And starts executing that ISR handler function till completion.<\/p>\n\n\n\n

    Then, the CPU restores back the context of the main program and jumps back to where it left off the main program. And everything resumes as it used to before the arrival of the interrupt signal.<\/p>\n\n\n\n

    When a new interrupt is fired, the CPU will immediately be notified and all previous steps will be repeated again. Otherwise, the CPU will keep executing the main program (super loop()<\/code> function).<\/p>\n\n\n

    \n
    \u2755 Note<\/div>\n\n\n

    Context Saving & Switching<\/strong><\/p>\n\n\n\n

    Context saving and restoration is a process that the CPU needs to do just to smoothly switch between main program execution and ISR handlers. It needs to save the current CPU registers, program counter address, and shadow registers. This is the only way the CPU can know where it left off before jumping to the interrupt vector to execute the ISR function located there.<\/p>\n\n\n\n

    After finishing the execution of the ISR handler function, the CPU needs to remember where it left off the main program to continue from that point. Therefore, context restoration is needed. So it pops up all saved addresses and registers (context) and jumps back to where it left off the main program.<\/p>\n\n<\/div><\/div>\n\n\n


    \n\n\n

    Types of Interrupts<\/strong><\/h2>\n\n\n

    Interrupts can be categorized based on their type into different categories as we’ll discuss in this section. Each interrupt type has a unique set of features, advantages, and disadvantages. And it’s totally dependent on what your actual microcontroller supports.<\/p>\n\n\n

    1. Software & Hardware Interrupts<\/strong><\/h3>\n\n\n

    Software Interrupts<\/strong><\/p>\n\n\n\n

    Software interrupts are interrupt signals that can be fired with specific software instructions. Some microcontrollers support native software interrupt instructions while others don’t have dedicated assembly instructions for the CPU to get an interrupt from the software.<\/p>\n\n\n\n

    Other techniques can be implemented to programmatically enforce an interrupt to the CPU within your software even if it doesn’t have a soft interrupt instruction. This of course requires some workarounds but it’s not that hard to do in general.<\/p>\n\n\n\n

    A software interrupt can be referred to as a Trap as well. Which is a technique to signal the CPU within the software to change the mode, throw an error, indicate an arithmetic error, or signal the OS.<\/p>\n\n\n\n

    Hardware Interrupts<\/strong><\/p>\n\n\n\n

    Hardware interrupts are generated by hardware peripherals in the microcontroller itself (like Timers, External IRQ pins, UART, SPI, etc.). Hardware modules fire various interrupt signals so the CPU gets notified about it and handles them as quickly as possible.<\/p>\n\n\n

    2. External & Internal Interrupts<\/strong><\/h3>\n\n\n

    Internal Interrupts<\/strong><\/p>\n\n\n\n

    Internal interrupts are generated by internal events within the microcontroller itself, such as timers, ADC, UART, or any other peripheral events.<\/p>\n\n\n\n

    External Interrupts<\/strong><\/p>\n\n\n\n

    External interrupts on the other hand are triggered by external signals applied to specific pins of the microcontroller. Those pins are usually referred to as IRQ pins (interrupt request pins). Which directly fire interrupt signals to the CPU when a certain external event occurs, that’s why those interrupts are known as external interrupts.<\/p>\n\n\n\n

    The most common types of IRQ pins are dedicated external interrupt pins and IOC (interrupt-on-change) pins. The difference is that dedicated external IRQ pins have separate interrupt vectors, while IRQ IOC pins share a common interrupt signal and you have to manually check which pin state has changed and caused that IOC global flag to fire the interrupt.<\/p>\n\n\n

    3. Vectored & Non-Vectored Interrupts<\/strong><\/h3>\n\n\n

    Vectored Interrupts<\/strong><\/p>\n\n\n\n

    A vectored-quantity in physics is a quantity that has a magnitude and a direction. Similarly, a vectored interrupt is an interrupt signal that has a specific address (vector) that points to the memory location where its ISR handler is located. So when an interrupt is fired, the CPU goes directly to the corresponding interrupt vector to execute the respective ISR handler.<\/p>\n\n\n\n

    This means, in vectored-interrupts systems, we’ll have a dedicated ISR handler for each interrupt signal that we’re using in the system. For example, here is how to handle two interrupt sources (INT0, and TMR1) in a vectored-interrupts system.<\/p>\n\n\n\n

    ISR (TIMER1_vect)\n{\n    \/\/ Handle The Timer1 Interrupt\n}\n\nISR (INT0_vect)\n{\n    \/\/ Handle The External INT0 Interrupt\n}<\/pre>\n\n\n\n

    <\/p>\n\n\n\n

    As you might have noticed, there are two separate ISR handlers for each interrupt signal source and each one has its own vector (address).<\/p>\n\n\n\n

    Non-Vectored Interrupts<\/strong><\/p>\n\n\n\n

    Non-Vectored Interrupts, on the other hand, share a common global interrupt vector (address) for all interrupt signal sources. This means you need to manually check which interrupt has occurred and service them after validating the interrupt flag bits. This has to be done each time any interrupt is fired.<\/p>\n\n\n\n

    Here is an example of how to handle two interrupt sources (INT0, and TMR1) in a non-vectored interrupts system.<\/p>\n\n\n\n

    ISR(void)\n{\n  if(INT0IF)\n  {\n     \/\/ Handle The External INT0 Interrupt\n  }\n  if(TMR1IF)\n  {\n     \/\/ Handle The External INT0 Interrupt\n  }\n  ..\n  ..\n}<\/pre>\n\n\n\n

    <\/p>\n\n\n\n

    As you might have noticed, there is only one global ISR handler for all interrupt sources. And we had to manually check the interrupt flag bits (INT0IF & TMR1IF) to detect which interrupt has occurred and service it accordingly.<\/p>\n\n\n

    \n
    \u2755 Note<\/div>\n\n\n

    The Arduino UNO’s microcontroller (Atmega328p) has a vectored-interrupt system.<\/p>\n\n<\/div><\/div>\n\n

    4. Maskable & Non-Maskable Interrupts<\/strong><\/h3>\n\n\n

    Maskable Interrupts<\/strong><\/p>\n\n\n\n

    Maskable interrupts can be programmatically enabled or disabled using dedicated interrupt enable\/disable bits. Maskable interrupts can be enabled or disabled during runtime using software instructions which can be helpful in a lot of applications.<\/p>\n\n\n\n

    Non-Maskable Interrupts<\/strong><\/p>\n\n\n\n

    Non-Maskable interrupts on the other hand are always enabled by default and there is no way to disable them by software instructions in runtime. Things like RESET, WDT (watchdog timer), BOD (brown-out detection or power failure), and hardware failures are common non-maskable interrupts that you can’t disable in software.<\/p>\n\n\n\n


    \n\n\n

    Why & When To Use Interrupts?<\/strong><\/h2>\n\n\n

    We typically use interrupts in embedded systems as a better alternative for event polling mechanism which keeps the CPU blocked in a busy-waiting state waiting for something to happen. Interrupts on the other hand saves the CPU time from being wasted in unnecessarily polling events & peripherals. And provides a near-immediate response to various events instead.<\/p>\n\n\n\n

    But there are so many other reasons to use interrupts in embedded systems other than replacing polling instructions. Here are some other situations and use cases for interrupts:<\/p>\n\n\n\n

    Time-Critical Tasks<\/strong>: When certain tasks require immediate attention and cannot be delayed by the main program flow, interrupts provide a way to handle them immediately.<\/p>\n\n\n\n

    Real-Time Event Handling<\/strong>: Interrupts allow quick responses to external events, such as button clicks, sensor readings, or communication signals, enabling the microcontroller to react instantly.<\/p>\n\n\n\n

    Efficient CPU Time Utilization<\/strong>: By using interrupts, the microcontroller can multitask and handle multiple events concurrently, optimizing resource utilization and ensuring smooth operation.<\/p>\n\n\n\n

    Precise Timing Requirements<\/strong>: For tasks that require precise timing or synchronization, timer interrupts can be used to trigger actions at specific moments or time intervals.<\/p>\n\n\n\n

    Energy Efficiency<\/strong>: Interrupts enable the microcontroller to stay in a low-power mode until an external event occurs, reducing power consumption and prolonging battery life in portable devices.<\/p>\n\n\n

    \n
    \u2755 Note<\/div>\n\n\n

    While interrupts make the system more responsive and provide a near-instant response to various internal & external events, it also adds to the system’s complexity and sometimes overload the CPU if not reasonably designed (set up). Using Interrupts also reduces the predictability of the system and makes it harder to analyze the dynamic behavior (timing) of the system.<\/p>\n\n<\/div><\/div>\n\n\n


    \n\n\n

    Interrupt Service Routines (ISR)<\/strong><\/h2>\n\n\n

    The ISR<\/strong> (I<\/strong>nterrupt S<\/strong>ervice R<\/strong>outine) is a dedicated function that the CPU executes in response to an interrupt event. It is responsible for handling the specific task associated with the interrupt signal. When an interrupt occurs, the microcontroller jumps to the ISR handler function, executes it, and returns to where it left off the main program.<\/p>\n\n\n\n

    ISRs should be kept short and efficient to minimize the disruption of the main program flow. They should focus on completing the critical tasks associated with the interrupt and avoid unnecessary delays or time-consuming operations.<\/p>\n\n\n\n

    An ISR handler function should have a unique identifier that designates an ISR function from a general-purpose user-defined function. This varies from one toolchain to another, each compiler has its own syntax to define an ISR function (whether it’s vectored or non-vectored ISR handler).<\/p>\n\n\n\n

    As stated earlier, Arduino’s Atmega328p microcontroller has a vectored-interrupt system. This means we need to define an ISR handler function for each interrupt signal being used in the system. Here is an example of the Timer1 overflow interrupt handler definition.<\/p>\n\n\n\n

    ISR(TIMER1_OVF_vect)\n{\n  \/\/ Handler Timer1 OverFlow Interrupt\n}\n<\/pre>\n\n\n\n

    <\/p>\n\n\n\n

    Similarly, other interrupt signals can be handled by ISR functions written in the same way as the one shown above. Which we’ll see in this tutorial’s examples hereafter.<\/p>\n\n\n\n


    \n\n\n

    Arduino Interrupts<\/strong><\/h2>\n\n\n

    In this section, we’ll shift the focus from general interrupts working principles and mechanisms to discuss Arduino Interrupts<\/strong> in detail. We’ll explore Arduino interrupt types, available features, and more other details.<\/p>\n\n\n

    1. Arduino Software Interrupts<\/strong><\/h3>\n\n\n

    It’s stated clearly in the Arduino UNO’s Atmega328p datasheet that it doesn’t have a dedicated assembly instruction to trigger a software-generated interrupt signal. But as we’ve stated earlier, we can still implement some workarounds to fire software-generated interrupt signals.<\/p>\n\n\n\n

    One technique to generate a software interrupt is clearly stated in the datasheet itself. Which is to enable any external interrupt pin (IRQ) and set it as an output pin. Writing to any pin of these will trigger an interrupt, and that’s how we get a software-generated interrupt even if it’s not supported by the microcontroller.<\/p>\n\n\n\n

    Check this tutorial below for more information about Arduino Software Interrupts and to get some code examples as well as some useful tips and tricks.<\/p>\n\n\n

    \n
    ???? Also Read<\/div>\n\n
    \n
    \n\n
    \"Arduino<\/a><\/figure>\n\n<\/div><\/div><\/div>\n\n
    \n
    Arduino Software Interrupts<\/a><\/div>\n\n\n

    This article will give more in-depth information about Arduino Software Interrupts, how to generate software interrupts in Arduino, and will also provide an example code for Arduino software interrupts generation.<\/p>\n\n<\/div><\/div><\/div>\n<\/div>\n<\/div><\/div>\n\n

    2. Arduino Hardware Interrupts<\/strong><\/h3>\n\n\n

    The Arduino hardware peripherals have the ability to generate various interrupt signals to the CPU, which include but are not limited to the following hardware interrupt signals:<\/p>\n\n\n\n