We have looked at the basics of AVR Interrupts, now let us go ahead and use the External Interrupts feature on the AVR MCUs.

Basics

When an interrupt occurs, the current program execution is stopped, the context is saved and the control jumps to Interrupt Service Routine (the ISR). When the ISR is executed, the main program execution is continued. This is usually the case with most simple Micro-controllers. We have been working with Atmega32 for this series, however there shouldn't be much difference making it work with other AVR MCUs. Now, let us look at how to configure the External Interrupts in AVR.

Steps to configure the Interrupts:

  1. Set INT1 and INT0 bits in the General Interrupt Control Register (GICR)
  2. Configure MCU Control Register (MCUCR) to select interrupt type.
  3. Set Global Interrupt(I-bit) Enable bit in the AVR Status Register(SREG)
  4. Handle the interrupt in the Interrupt Service Routine code.

General Interrupt Control Register (GICR)

The GICR Register shown below is used to enable INT0 and INT1 interrupts. These interrupts correspond to the two physical pins PD3 and PD4 respectively. The INT0 is configured to produce low level triggered and INT1 as falling edge triggered interrupt respectively. A counter is increment and displayed when the interrupt occurs.

7 6 5 4 3 2 1 0
INT1 INT0 INT2 - - - IVSEL IVCE


MCU Control Register (MCUCR)

The MCUCR register allows us to configure the type of interrupt we need as shown by the table below:

7 6 5 4 3 2 1 0
SE SM2 SM1 SM0 ISC11 ISC10 ISC01 ISC00
ISC01 ISC00 Description
0 0 The low level of INT0 generates an interrupt request.
0 1 Any logical change on INT0 generates an interrupt request.
1 0 The falling edge of INT0 generates an interrupt request.
1 1 The rising edge of INT0 generates an interrupt request.

General Interrupt Flag Register(GIFR)
The bits of GIFR register are set when an interrupt occurs and cleared automatically when it is processed.

7 6 5 4 3 2 1 0
INTF1 INTF0 INTF2 - - - - -


We will connect two switches to the two interrupt pins and show the status on a LCD. The connections are shown in the image below.

Hook Up

The Ultra AVR development board has two switches and also an inbuilt LCD. It is hooked up as shown below:

EXT Interrupt Edge Level.png

The Code

Let us look at the code in a little detail here.

#include<avr/interrupt.h>

Line 2, includes the interrupt.h file, which includes all the interrupt definations.

volatile int cnt_zero,cnt_one;
ISR (INT0_vect)          //External interrupt_zero ISR
{
	cnt_zero++;
}

The volatile keyword for cnt_zero and cnt_one variables ensures that these variables are not optimized by the compiler and also tells the compiler that these can change at anytime during the execution. Well, remember the switch can be pressed any time by the user, and volatile tells the compiler not to be over-smart and optimize it because it is no where used in the main code.

Now look at the ISR() function, it is template that is included with the avr-gcc compiler. All the interrupts that we saw in the basics tutorial can be configured as input to this function. The library take cares of saving the context, and switching back to main code when the ISR is complete. This is the cool thing about programming micro-controllers in C.

There are a few details which I have left out, like the names of the files which define the names of the interrupts and map them to the Interrupt vector Table (IVT). Should you have questions about any of these, comment below!

Downloads

Code for the tutorial AVR Series

Demo Video