Introduction: Beginning Microcontrollers Part 12: Intro to Interrupts

About: I like robots!

In this part of the tutorial we will talk about interrupts work using the counter for example. Interrupts enhance the usage of microcontrollers in a huge way. Interrupts make your programs react to the hardware of the microcontrollers, which may be a reaction from the circuit outside of the microcontroller.

In basic terms, an interrupt is exactly what it is stated as. It interrupts a normal running program flow to do another task (other code block that you program). Say for example your program is doing normal blinking LEDs and you want it to react to a PIR sensor (connected to an interrupt pin), and goes to a special code block to make a beep from a buzzer connected to another pin. If you tell the microcontroller to do this, it will stop the program dead and go to the code that belongs to the interrupt (make a beep). After interrupt code is executed, the stopped program resumes precisely where it left off. In some examples, interrupts would be an alternative to polling, which would require program cycles. Say your program is wanting to only beep when someone passes the PIR sensor. Your program could keep testing that pin to see if it has a high reading over and over within the never ending loop (while (1)). Alternatively, remove all the polling program code to test the pin for a high reading and allow the interrupt to automatically proceed to the beep code when the microcontroller senses the high reading.

What kinds of interrupts are available for the AVR microcontroller? Interrupts can be established for events such as a counter's number, a pin changing state (from low to high or vice versa) serial communication receiving of information, or the Analog to Digital having established a conversion. Here is a list of interrupt vectors that you can use. Other tutorials will make use of many of these vectors.

We are going to use the timer/counter as an example. We will tell the timer/counter a number that the TCNT1 (the counter) will need to match. The number to match will go into a register called OCR1A (Output Compare Register). The "1" represents the specific counter we are using which is the 16-bit version. We have two OCRs, the A and the B. We will use A for this example. But do we know if the counter will reset to zero when the match is made? We definitely want the TCNT1 to go back to zero so the count will start over and we get another match at our intended number, but this isn't done in code like we did last time (remember the TCNT1 = 0;). This time, we will want to turn on another switch in the TCCR1B control register called WGM12 (waveform Generation Mode for timer 1). The #2 in that switch just represents which WGM it is, since there are a few. We will also be using the CS10 and CS11 again to set the prescaling to 64 as in the intro to timers video.

Then the timer/counter will need to know that we intend to use the interrupt feature. This is done through the TIMSK (Timer/Counter Interrupt Mask Register). We only need to turn on one switch in this register: the OCIE1A (Output Compare A Match Interrupt Enable) switch. Once the number put into the OCR1A is matched by the counter, the program will be interrupted to toggle the LED. For an interrupt to happen, we will need to enable the global interrupts "sei()", then we will need to enable the interrupt for the timer/counter, and finally the interrupt service routine (ISR) will need to be created. The interrupt service routine is just like the functions that were made in the button game example. The interrupt service routine is just a code block outside of the main routine and begins with ISR with the vector within parenthesis "(vector)", allowed by the block of code within brackets"{Code}". For the timer/counter (16-bit version), and the fact that we are using the A version of the OCR1, the vector name is: TIMER1_COMPA_vect. So the routine would be: ISR(TIMER1_COMPA_vect) { code to execute }. We used a number in the intro to timers video that represented one second: 15625, so we will use this one for the OCR1A. But, the number should consider indexing from 0, so we will need to use the number 15624 instead.

Step 1: The Code

#include <avr/io.h>
#include <avr/interrupt.h>

int main(void)

{

sei () ;
DDRB |= 1<

TCCR1B |= 1<

while(1) { } }

ISR(TIMER1_COMPA_vect)

{

PORTB ^= 1<<PINB0;
}

Step 2: Pseudocode Version

  • Include some basic information to properly configure our microcontroller.
  • Include the interrupt library that has all the interrupt functions we need.
  • Start the main routine (do the indented stuff)
    • Enable the global interrups
    • Since we are using an LED, enable that pin to be output
    • Turn on the timer and use 64 prescaling (skip 64 clock ticks)
    • Enable the output compare register and set a number to represent one second
    • Loop Forever
    • No code needed in the forever loop this time
  • End main routine
  • Start Interrupt routine (for the correct vector)
    • Toggle the pin to which the LED is connected
  • End Interrupt routine (go back to where the program left off)