
Hey everyone! Have you ever written an Arduino sketch with a bunch of delay() functions, only to realize your buttons suddenly feel unresponsive? It’s a frustrating but incredibly common problem. Your Arduino is so busy waiting for a delay to finish that it completely misses the fact that you pressed a button.
Enter the magic of hardware interrupts.
Think of a hardware interrupt as a tap on the shoulder for your microcontroller. No matter what your Arduino is currently doing (even if it’s stuck in a long delay or a heavy calculation), an interrupt forces it to drop everything, handle the event immediately, and then resume exactly where it left off.
Here are a few reasons why interrupts are game-changers:
digitalRead() in your loop() to see if a button state changed.loop() to focus on the big picture instead of micro-managing inputs.attachInterrupt()To use a hardware interrupt on an Arduino Uno, you typically use pins 2 or 3. Here is a simple example that turns on an LED when a button is pressed, using an interrupt.
const byte ledPin = 13;
const byte interruptPin = 2;
volatile byte state = LOW;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(interruptPin, INPUT_PULLUP);
// Attach the interrupt to pin 2
// Trigger the blink() function when the pin goes from HIGH to LOW (FALLING edge)
attachInterrupt(digitalPinToInterrupt(interruptPin), blink, FALLING);
}
void loop() {
// The main loop can do whatever it wants!
// The LED state is handled entirely in the background.
digitalWrite(ledPin, state);
// Let's pretend we are doing some heavy processing here
delay(1000);
}
// This is the Interrupt Service Routine (ISR)
void blink() {
state = !state; // Toggle the state
}
volatile keyword: Notice how the state variable is declared as volatile byte. This tells the compiler that this variable can change at any time (outside the normal flow of the program), so it shouldn’t try to optimize it away. Always use volatile for variables modified inside an ISR!digitalPinToInterrupt(pin): You should always use this function rather than just typing the interrupt number directly. It ensures your code is portable across different Arduino boards.blink()): This is the Interrupt Service Routine. It’s the function that gets called when the interrupt triggers. ISRs should be as short and fast as possible. Don’t use delay() or Serial.print() inside an ISR!FALLING: This is the trigger mode. Because we used INPUT_PULLUP, the pin is normally HIGH. Pressing the button connects it to ground, making it go LOW. The transition from HIGH to LOW is a “falling” edge.Interrupts are an essential tool for building responsive, professional-grade projects. Start incorporating them into your builds and see the difference!
To follow along with this lesson, you’ll need the following components: