As an Arduino Maker, you may have found yourself trapped in the throes of a delay() function. This blocking function means your Arduino is held hostage, unable to process anything else until the delay has run its course.
There are a couple of notable solutions to this common problem. I have discussed one of them in a previous article.
Another solution lies in a nifty feature known as “Timer Interrupts”.
In this post, I will show you how you can break free from blocking code and make your Arduino projects more efficient by employing timer interrupts.
Understanding Interrupts and Timer Interrupts
First, let’s understand what an interrupt is. An interrupt is a signal that temporarily halts the processor’s current task to execute a separate routine. Once the routine is completed, the processor resumes its previous task.
Timer Interrupts are a specific type of interrupt triggered by the hardware timers inside the Arduino Uno. Unlike external interrupts triggered by external events like a button press, timer interrupts occur at precise, programmable intervals.
This opens up a world of possibilities for non-blocking code execution.
How to setup a Timer Interrupt
Arduino Uno has three built-in timers; you can set up these timers to trigger an interrupt routine at exact intervals. To make this process more straightforward, we will use the TimerOne library.
Here’s a step-by-step guide to setting up a Timer Interrupt:
- Install the TimerOne library in your Arduino IDE.
- Include the TimerOne library at the top of your sketch.
- In the setup() function, initialize the timer and attach the interrupt handler.
- Write the interrupt routine. This routine is called every time the timer interrupt occurs.
- Make sure your interrupt routine is short and fast. Remember, interrupts pause the processor’s current task, so long-running interrupt routines can make your program unresponsive.
Non-Blocking Blink
To demonstrate a timer interrupt, let’s make a non-blocking blink. An LED will blink every second without using delay()
.
#include <TimerOne.h>
#define LED_PIN 13
void setup() {
pinMode(LED_PIN, OUTPUT);
Timer1.initialize(1000000); // 1 second
Timer1.attachInterrupt(timerIsr);
}
void loop() {
// The LED blink is handled by the interrupt, so we can do other tasks here
}
void timerIsr() {
digitalWrite(LED_PIN, digitalRead(LED_PIN) ^ 1); // Toggle LED state
}
The single line of code in the timerlsr
function drives the LED, making it blinks at exact one-second intervals, and the main loop remains free to handle other tasks.
Within the digitalWrite function, the first parameter “LED_PIN
” refers to the pin where the LED is connected.
In the second parameter, I have provided the state of the LED, which can be either HIGH or LOW. I used the code “digitalRead(LED_PIN) ^ 1
” in this example. This code reads the current state of the LED (HIGH or LOW, represented by 1 or 0, respectively) and then uses the XOR bitwise operator (^
) to toggle its state.
“digitalRead(LED_PIN)
” will return either HIGH (1) or LOW (0), depending on the current state of the pin LED_PIN.
The “^ 1
” then toggles that state:
- If the current state is HIGH (1), then “
1 ^ 1
” results in 0 (LOW). - If the current state is LOW (0), then “
0 ^ 1
” results in 1 (HIGH).
So, “digitalRead(LED_PIN) ^ 1
” will return HIGH if the current state is LOW, and vice versa. It’s a neat way to toggle the state of a digital pin in just one line of code.
Advantages and Considerations
The beauty of non-blocking code is that it allows your Arduino to be more responsive. The Arduino could miss an input with the delay()
function because it’s preoccupied.
Timer interrupts help to bypass this issue.
However, while timer interrupts are powerful, they should be used judiciously. Your interrupt routines should be short and quick. Long-running interrupt routines can disrupt your main program flow and may result in unexpected behaviour.
Further readings
Here are some free online resources on the topic:
- Arduino Reference: The official Arduino reference is always a good place to start. It covers all the basics, as well as some more advanced topics. You might be interested in the section on interrupts.
- Arduino Playground – Timer1: This wiki provides a more detailed explanation of the Timer1 library, which can be used to set up timer interrupts on an Arduino Uno.
- Instructables – Arduino Timer Interrupts: This Instructables guide provides a beginner-friendly introduction to timer interrupts and shows how to use them in various projects.
-
Tech Explorations website: We have published several relevant articles that you might enjoy reading:
- Optimizing the reaction time of the ATMega328.
- Why should I call detachInterrupt at the start of an interrupt service routine?
- The basic functions of the TimerOne library.
- Can you use delay() inside Interrupt Service Routine?
- The interrupt service routine and volatile variables.
- Simple multitasking on the Arduino.
- Concurrency with the Scheduler library on the Arduino Due and Zero.
- Arduino StackExchange: This Q&A forum has many experienced users who can provide insights and answers on more advanced topics like interrupts and timers.
- Arduino Tutorial – Interrupts: This tutorial on the official Arduino site provides a detailed introduction to interrupts, a prerequisite for understanding timer interrupts.
Remember that while these resources are free, some may require you to create an account or sign up for a newsletter.
Wrapping Up
Timer interrupts open up opportunities for non-blocking code execution in Arduino. This powerful tool helps make your projects more responsive and efficient. As you continue exploring timer interrupts, you’ll discover more creative ways to utilize this clever technique. Happy tinkering!