Table of Contents

Using Interrupts in C

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>