Home ArduinoArduino Tutorials Tutorial: Arduino Interrupts

Tutorial: Arduino Interrupts

by shedboy71

Interrupts in Arduino allow you to execute specific pieces of code immediately when a particular event occurs, regardless of what the main program is doing.

They are essential for creating responsive and time-sensitive applications.

This tutorial explains how to use interrupts in Arduino and demonstrates practical examples.

Table of Contents

1. What Are Interrupts in Arduino?

Interrupts are mechanisms that pause the main program flow and execute a specific piece of code (an interrupt service routine, or ISR) when a defined event occurs. Once the ISR is complete, the main program resumes.

2. How Do Interrupts Work?

  1. Trigger an Event: An interrupt is triggered by hardware events such as a change in pin state or a timer overflow.
  2. Execute ISR: The ISR runs immediately and completes as quickly as possible.
  3. Resume Main Code: After the ISR finishes, the main program continues.

3. Types of Interrupts

3.1 External Interrupts

  • Triggered by events on specific external pins (INT0 and INT1 on most Arduino boards).
  • Use attachInterrupt() to configure them.

Available Interrupt Pins (Common Boards)

Board Pins
Arduino Uno 2 (INT0), 3 (INT1)
Arduino Mega 2, 3, 18, 19, 20, 21
Arduino Nano 2, 3

3.2 Pin Change Interrupts

  • Triggered by changes on any GPIO pin.
  • Requires the EnableInterrupt library for easy implementation.

4. Functions for Interrupts

4.1 attachInterrupt()

  • Configures an external interrupt.
  • Syntax:
    attachInterrupt(digitalPinToInterrupt(pin), ISR, mode);
    
    • pin: The pin number (use digitalPinToInterrupt(pin) to convert it to the interrupt number).
    • ISR: The interrupt service routine function to execute.
    • mode: Trigger condition (LOW, CHANGE, RISING, FALLING).

4.2 detachInterrupt()

  • Disables an interrupt.
  • Syntax:
    detachInterrupt(digitalPinToInterrupt(pin));
    

5. Practical Examples

5.1 Button Press Interrupt

Use an interrupt to toggle an LED when a button is pressed.

const int buttonPin = 2;  // Interrupt pin
const int ledPin = 13;    // LED pin
volatile bool ledState = false;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);  // Configure button pin with pull-up resistor
  pinMode(ledPin, OUTPUT);           // Configure LED pin
  attachInterrupt(digitalPinToInterrupt(buttonPin), toggleLED, FALLING);
}

void loop() {
  digitalWrite(ledPin, ledState);  // Set LED state
}

// ISR to toggle LED state
void toggleLED() {
  ledState = !ledState;
}

5.2 Pulse Counting

Count the number of pulses received on a pin (e.g., from a rotary encoder or sensor).

const int pulsePin = 2;  // Interrupt pin
volatile int pulseCount = 0;

void setup() {
  Serial.begin(9600);
  pinMode(pulsePin, INPUT_PULLUP);  // Configure pin with pull-up resistor
  attachInterrupt(digitalPinToInterrupt(pulsePin), countPulse, RISING);
}

void loop() {
  Serial.print("Pulse Count: ");
  Serial.println(pulseCount);
  delay(1000);  // Print every second
}

// ISR to increment pulse count
void countPulse() {
  pulseCount++;
}

5.3 Toggle LED Using a Timer Interrupt

Use a timer interrupt to toggle an LED periodically. This requires the TimerOne library.

  1. Install the TimerOne Library:
    • Go to Tools > Manage Libraries.
    • Search for “TimerOne” and install it.
  2. Code Example:
#include <TimerOne.h>

const int ledPin = 13;  // LED pin
volatile bool ledState = false;

void setup() {
  pinMode(ledPin, OUTPUT);
  Timer1.initialize(1000000);  // Set timer to 1 second (1,000,000 microseconds)
  Timer1.attachInterrupt(toggleLED);  // Attach interrupt
}

void loop() {
  digitalWrite(ledPin, ledState);  // Set LED state
}

// ISR to toggle LED state
void toggleLED() {
  ledState = !ledState;
}

5.4 Random LED Blinking Using Interrupt

Use interrupts to randomly blink LEDs when triggered by a button press.

const int buttonPin = 2;  // Interrupt pin
const int ledPins[] = {3, 4, 5};  // LED pins
const int numLeds = 3;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  for (int i = 0; i < numLeds; i++) {
    pinMode(ledPins[i], OUTPUT);
  }
  attachInterrupt(digitalPinToInterrupt(buttonPin), randomBlink, FALLING);
}

void loop() {
  // Main loop does nothing; all work is handled in the ISR
}

// ISR to randomly blink an LED
void randomBlink() {
  int randomLed = random(0, numLeds);
  digitalWrite(ledPins[randomLed], HIGH);
  delay(200);
  digitalWrite(ledPins[randomLed], LOW);
}

6. Best Practices for Using Interrupts

  1. Keep ISRs Short:
    • Avoid delays or complex operations in ISRs. Only set flags or increment counters.
    void ISR() {
      // Avoid using Serial.print or delay() here
      flag = true;  // Use flags for further processing in the main loop
    }
    
  2. Disable Unused Interrupts:
    • Use detachInterrupt() to disable interrupts when no longer needed.
  3. Minimize Shared Resources:
    • Avoid accessing variables shared between ISRs and the main program. Use volatile for shared variables.
  4. Debounce Buttons:
    • Add debouncing logic to prevent multiple triggers from button noise.
  5. Test Interrupt Priority:
    • Understand that some interrupts may take priority over others. Ensure critical tasks are prioritized.
  6. Use External Pull-Up Resistors When Necessary:
    • Ensure clean signal transitions for stable interrupt triggers.

Conclusion

Interrupts in Arduino are powerful tools for creating responsive and real-time applications.

They allow you to handle events like button presses, sensor pulses, or timer overflows with minimal delay.

By following the examples and best practices in this tutorial, you can confidently use interrupts in your Arduino projects.

For more details, visit the official Arduino reference.

 

You may also like