AVR microcontroller interrupts handling using WINAVR

Microcontrollers without interrupts are almost worthless. Interrupt is called what interrupts normal program flow. Interrupts are nothing more than subroutines that put on hold normal program flow while they are executed. After interrupt subroutines are finished they return to normal from last point. Those subroutines are called interrupt handlers that are called by some event like toggle external pin or some register value overfilled like timer overflow and so on.
Why interrupts are so important? For instance without interrupts you would have to do loops in order to check if one or another event occurred. This operation is called polling. But pooling has many disadvantages like program have do loops taking resources from other task may be done. This is why microcontroller comes with multiple interrupt sources. Instead of checking events microcontroller has ability to interrupt normal program flow on event and jump to interrupt service subroutine and then get back to normal program flow.

What happens when interrupt occurs? After interrupt event microcontroller stops the task at current point, saves current information to stack and gives its resources to interrupt subroutine. When interrupt subroutine is finished last program point is restored and program flow continues.

In assembly language your program usually would start with interrupt table:

 

This table indicates where all interrupt subroutines are located. After particular interrupt occurs, program pointer jumps to interrupt table where it is directed to interrupt subroutine location.

For instance every time you power up microcontroller program pointer jumps to location $000 where it is directed to (RESET) location. With C program this would be location of main() function.

C Compiler creates this table while compiling the source code. But how to describe interrupts handling routines in C language using WinAVR toolset. All time when compilers are improving, there is no agreement how to handle interrupt code. As compilers tries to stay away from machine dependant details, each compiler is designed with their own methods. AVR-GCC isn’t exception. There each interrupt is pointed with predefined names – you will find in microcontroller definition header file like in iom8.h.

Defining the interrupt routines is ease…

First of all include desired library that compiler could understand interrupt macro commands:

#include <avr/interrupt.h>

All interrupts then can be described using macro command: ISR(), for instance:

 

ISR(ADC_vect)

{

//Your code here

}

 

This subroutine is for ADC conversion complete handler. Macro command ISR() is convenient for handling all unexpected interrupts. Just create routine like this;

 

ISR(_vector_default)

{

//your code here;

}

 

If you want to describe an empty interrupt for particular event (puts “reti” command in interrupt table) just use:

  EMPTY_INTERRUPT(ADC_vect)

 

 

Example:

 

Simple program:

#include <avr\io.h>

#include <avr\iom8.h>

#include <avr\interrupt.h>

 

#define outp(a, b) b = a

#define inp(a) a

uint8_t led;

typedef unsigned char  u08;

ISR(INT0_vect) { /* signal handler for external interrupt int0 */

    led =  0x01;

   }

ISR(INT1_vect) {    /* signal handler for external interrupt int1 */

    led =  0x00;

   }

int main(void) {

 

    outp(0x01, DDRB);      /* use PortB for output (LED) */

    outp(0x00, DDRD);      /* use PortD for input (switches) */

    outp((1<<INT0)|(1<<INT1), GIMSK); // enable external int0, int1

    sei();       /* enable interrupts */

    led =  0x01;

    for (;;) {

    outp(led, PORTB);

    }                      /* loop forever */

}

 

In earlier versions of WINAVR there were SIGNAL() macro used. Now this is the same as ISR() and not used anymore.

Another interesting interrupt handling macro is ISR_ALIAS(vector, target_vector). This is used when you need to pint one vector o another vector. This way you may handle multiple interrupts with single implementation, for instance:

 

    ISR(INT0_vect)
    {
        PORTB = 42;
    }
 
    ISR_ALIAS(INT1_vect, INT0_vect);

{mos_ri} 

 

Comments

Let the ISR simply increment a global variable x which is initially 0. What will be the value of
the variable after 1 minute if a 1 kHz TTL signal is applied to INT1?

(60 sec x 1000 sec-1 mod 256) -1 = 95