Introduction: Arduino - Periodic Interrupt
This Instructable is about using a periodic interrupt for timing in Arduino programs. This is a step for a budding Arduino programmer who knows that the Arduino can do more, but doesn't quite know how to make that happen.
If there's a performance problem I'm assuming that you're using one or more delay() functions. The trick is to get rid of the delay() function(s) and substitute an interrupt. The delay() function forces the Arduino to do nothing while waiting for the delay() to complete. Using an interrupt allows your program to do other things while waiting for the end of the delay. There is usually a huge amount of unused dead time that could be used for other things when using delay(). Using an interrupt solves this problem.
Attachments
Step 1: Interrupt Handler
1. Add the interrupt handler to your program. Just copy and paste somewhere above setup();
const unsigned long TIMER0_COUNT = 500; // 500 msec timer interval // TIMER0 interrupt handler volatile bool time = false; ISR( TIMER0_COMPA_vect ) { static unsigned long count = 0; if ( ++count > TIMER0_COUNT ) { count = 0; time = true; // time is set to true every TIMER0_COUNT ms } // (time needs to be cleared in the main routine) }
Step 2: Set Periodic Time Interval
2. Set the time interval. This routine piggybacks itself onto the TIMER0 interrupt, which is set to fire every ~1 msec.
Your "interval" is the number of TIMER0 interrupts to process. Each interval is ~1 msec, so you're really setting how many TIMER0 interrupts to count before activating your interval. IOW, set the variable TIMER0_COUNT to however many milliseconds you want to wait. For example, use 500 for one half of a second. Use 3000 for 3 seconds.
Step 3: Interrupt Initialization
3. Add the "TIMER0 initialization" code to your setup() method. Again, just copy and paste in setup().
// *** TIMER0 initialization *** cli(); // turn off all interrupts TIMSK0 = 0; // turn off timer0 for lower jitter OCR0A = 0xBB; // arbitrary interrupt count TIMSK0 |= _BV( OCIE0A ); // piggy back onto interrupt sei(); // turn interrupts back on
Step 4: Where to Add Your Code
4. Add the "time check" code to your loop() method. Copy and paste in loop().
if ( time ) { time = false; // do something here }
The "time = false;" line is important. Without this line the "do something here" line(s) would be executed every time the program executes loop().
Of course, you substitute your own activities in the "do something here" line. Start out with printing some text or flashing the LED.
You're done!
2 Comments
5 years ago
Could you give a few examples of when an interrupt would be preferable?
Reply 5 years ago
Hi. I've generated a cheesy program to demonstrate where an interrupt is preferable to using delay(). It's supposed to be a stop light. Once the light is triggered by hitting the 'Send' button on the Serial Monitor the program walks through its stop light sequence (prints which light is lit to the serial port).
What's significant here is that the program is able to read the keyboard input at any time, not waiting until it's done with a delay. Whatever you type into the Serial Monitor will get echoed to the serial port. This won't work with delay() AFAIK because the serial port only buffers one character at a time. This program will echo everything that is typed in.
This is useful because it frees up the microprocessor to do other things. This type of thing is very important for a user interface. Users (myself included) don't want to wait to input data - they want everything responsive, which can't happen with delay().
I'll be happy to generate a more complicated program that demonstrates this. The downside is it's more complicated and that tends to get in the way of understanding what's going on.
I've included a simple state diagram for the stop light to indicate how I built the state machine.