Using Interrupts in C

A Dr. Taylor Tutorial

Whenever a hardware interrupt occurs on the ATmega32, the appropriate instruction in the jump vector is executed. Recall that the C compiler places jumps to _bad_interrupt in all of the jump vectors for unused interrupts. In order to use interrupts in C we must:

  1. Write an ISR (interrupt service routine).
  2. Initialize the appropriate jump vector to jump to the ISR.
  3. Enable the desired interrupt.
  4. Setting the global interrupt flag.

Setting the global interrupt flag is done with the sei() "function" defined in <avr/interrupt.h>. Enabling the desired interrupt is accomplished by setting the appropriate flag in the control register for the desired interrupt. The syntax for defining the ISR and initializing the appropriate jump vector is described below.

Defining ISR and Initializing Jump Vector

The <avr/interrupt.h> header file defines a macro, ISR(interrupt_vector), for initializing the jump vector and specifying the code to be executed when the interrupt occurs.

The interrupt_vector must be one of the following (defined in avr/iom32.h, which is included by avr/io.h):

Interrupt type Vector Name Vector Number
External Interrupt Request 0 INT0_vect 1
External Interrupt Request 1 INT1_vect 2
External Interrupt Request 2 INT2_vect 3
Timer/Counter2 Compare Match TIMER2_COMP_vect 4
Timer/Counter2 Overflow TIMER2_OVF_vect 5
Timer/Counter1 Capture Event TIMER1_CAPT_vect 6
Timer/Counter1 Compare Match A TIMER1_COMPA_vect 7
Timer/Counter1 Compare Match B TIMER1_COMPB_vect 8
Timer/Counter1 Overflow TIMER1_OVF_vect 9
Timer/Counter0 Compare Match TIMER0_COMP_vect 10
Timer/Counter0 Overflow TIMER0_OVF_vect 11
Serial Transfer Complete SPI_STC_vect 12
USART, Rx Complete USART_RXC_vect 13
USART Data Register Empty USART_UDRE_vect 14
USART, Tx Complete USART_TXC_vect 15
ADC Conversion Complete ADC_vect 16
EEPROM Ready EE_RDY_vect 17
Analog Comparator ANA_COMP_vect 18
2-wire Serial Interface TWI_vect 19
Store Program Memory Ready SPM_RDY_vect 20

Example Code

Consider the following example program.

#include <avr/io.h>
#include <avr/interrupt.h>
  
uint8_t portVal = 128;
  
int main()
{
    sei();
    DDRB = 0x00;
    DDRC = 0xff;
    while(1)
    {
        PORTC = portVal;
    }
  
    return 0;
}
  
ISR(TIMER0_OVF_vect)
{
  portVal = PINB;
}
00000000 <__vectors>:
   0:   0c 94 2a 00     jmp     0x54    ; 0x54 <__ctors_end>
   4:   0c 94 47 00     jmp     0x8e    ; 0x8e <__bad_interrupt>
   8:   0c 94 47 00     jmp     0x8e    ; 0x8e <__bad_interrupt>
   c:   0c 94 47 00     jmp     0x8e    ; 0x8e <__bad_interrupt>
  10:   0c 94 47 00     jmp     0x8e    ; 0x8e <__bad_interrupt>
  14:   0c 94 47 00     jmp     0x8e    ; 0x8e <__bad_interrupt>
  18:   0c 94 47 00     jmp     0x8e    ; 0x8e <__bad_interrupt>
  1c:   0c 94 47 00     jmp     0x8e    ; 0x8e <__bad_interrupt>
  20:   0c 94 47 00     jmp     0x8e    ; 0x8e <__bad_interrupt>
  24:   0c 94 47 00     jmp     0x8e    ; 0x8e <__bad_interrupt>
  28:   0c 94 47 00     jmp     0x8e    ; 0x8e <__bad_interrupt>
  2c:   0c 94 51 00     jmp     0xa2    ; 0xa2 <__vector_11>
  30:   0c 94 47 00     jmp     0x8e    ; 0x8e <__bad_interrupt>
  34:   0c 94 47 00     jmp     0x8e    ; 0x8e <__bad_interrupt>
  38:   0c 94 47 00     jmp     0x8e    ; 0x8e <__bad_interrupt>
  3c:   0c 94 47 00     jmp     0x8e    ; 0x8e <__bad_interrupt>
  40:   0c 94 47 00     jmp     0x8e    ; 0x8e <__bad_interrupt>
  44:   0c 94 47 00     jmp     0x8e    ; 0x8e <__bad_interrupt>
  48:   0c 94 47 00     jmp     0x8e    ; 0x8e <__bad_interrupt>
  4c:   0c 94 47 00     jmp     0x8e    ; 0x8e <__bad_interrupt>
  50:   0c 94 47 00     jmp     0x8e    ; 0x8e <__bad_interrupt>

<snip>

00000092 <main>:
  92:   78 94           sei
  94:   17 ba           out     0x17, r1        ; 23
  96:   8f ef           ldi     r24, 0xFF       ; 255
  98:   84 bb           out     0x14, r24       ; 20
  9a:   80 91 60 00     lds     r24, 0x0060
  9e:   85 bb           out     0x15, r24       ; 21
  a0:   fe cf           rjmp    .-4             ; 0x9e <main+0xc>

000000a2 <__vector_11>:
  a2:   1f 92           push    r1
  a4:   0f 92           push    r0
  a6:   0f b6           in      r0, 0x3f        ; 63
  a8:   0f 92           push    r0
  aa:   11 24           eor     r1, r1
  ac:   8f 93           push    r24
  ae:   86 b3           in      r24, 0x16       ; 22
  b0:   80 93 60 00     sts     0x0060, r24
  b4:   8f 91           pop     r24
  b6:   0f 90           pop     r0
  b8:   0f be           out     0x3f, r0        ; 63
  ba:   0f 90           pop     r0
  bc:   1f 90           pop     r1
  be:   18 95           reti

Declaring a Variable as Volatile

Example Code Revisited

Changing the declaration of portVal in the previous example to this:

volatile uint8_t portVal = 128;

Results in a minor change to the machine code generated for main:

00000092 <main>:
  92:   78 94           sei
  94:   17 ba           out     0x17, r1        ; 23
  96:   8f ef           ldi     r24, 0xFF       ; 255
  98:   84 bb           out     0x14, r24       ; 20
  9a:   80 91 60 00     lds     r24, 0x0060
  9e:   85 bb           out     0x15, r24       ; 21
  a0:   fc cf           rjmp    .-8             ; 0x9a <main+0x8>

Tutorials for Other Courses

Additional Links

Site Mirror

This is a mirror to be used when http://myweb.msoe.edu/taylor/, (EDU instead of US) is not available.