Handling Interrupts on Arduino: External and Timer Setups
Handling interrupts on Arduino microcontrollers ensures critical hardware events—such as rotary encoder pulses, tachometer signals, or emergency stop triggers—are processed immediately without waiting for main loop execution.
1. Hardware interrupt pins and attachInterrupt()
Standard ATmega328P boards (Uno and Nano) provide two external hardware interrupt pins: Digital Pin 2 (Interrupt 0) and Digital Pin 3 (Interrupt 1). Attach an interrupt handler using attachInterrupt(digitalPinToInterrupt(2), isrFunction, RISING). Trigger modes include LOW, CHANGE, RISING, and FALLING.
2. Core rules for Interrupt Service Routines (ISRs)
An ISR must be short and fast to avoid blocking the microcontroller:
- No blocking functions:
delay()does not work inside an ISR because it relies on internal timer interrupts, which are disabled during ISR execution. - No lengthy I/O: Avoid calling
Serial.print()or drawing to I2C/SPI displays within an ISR. - Set flags: Update a simple counter or set a boolean flag in the ISR, then handle heavy processing in your main loop.
3. Declaring shared variables with the volatile keyword
Any global variable modified inside an ISR and read by the main loop must be declared with the volatile qualifier (e.g., volatile int pulseCount = 0;). This prevents the compiler optimizer from caching variable values in registers instead of reading fresh values from SRAM.
4. Deterministic hardware timer interrupts
For precise periodic actions (such as sampling ADC channels every 1ms), configure hardware timers like Timer1 using the TimerOne library rather than relying on software polling. For board platform comparisons, see our guide on Arduino vs Raspberry Pi[cite: 2].
When to get help
If you'd rather have this handled directly, see our Embedded Firmware Engineering Services for scope and turnaround times.