EXTERNAL INTERRUPTS ON THE ATmega8
INTRODUCTION:
In the previous section I talked about the basics of interrupts. In this section, we will talk about the first type of device interrupts called external interrupts. These interrupts are basically called on a given status change on the INTn pin. This is essentially an input interrupt and is great to use for applications when you might need to react quickly to an outside source, such as a bumper of your robot hitting the wall or to detect a blown fuse.
HARDWARE:
If you look at the AVR data sheet, the second page shows the pin configuration of the AVR chip. All the PA#, PB#, PC# and PD# could be configured as an outputs.
Figure 1: ATmega8 - External Interrupt Pins
Hardware wise there is not difference between External Interrupts and Inputs so don't be afraid to reread the Digital Input Tutorial if you need a refresher.
If you look at the AVR pinout diagram you will see the INTx which are used for External Interrupts.
THEORY OF OPERATION:
External interrupts are fairly powerful, they can be configured to trigger on one of 4 states. Low level will trigger whenever the pin senses a LOW (GND) signal. Any Logic Change trigger at the moment the pin changes from HIGH (Vcc) to LOW (GND) or from LOW (GND) to HIGH(Vcc). On Falling Edge will trigger at the moment the pin goes from HIGH (Vcc) to LOW (GND). On Rising Edge will trigger at the moment the pin goes from LOW (GND) to HIGH (Vcc). The best part is that you can configure each INTx independently.
External interrupts use the below 3 registers. Which you could find under the "External Interrupts" section of the datasheet.
7 bit | 6 bit | 5 bit | 4 bit | 3 bit | 2 bit | 1 bit | 0 bit | |
---|---|---|---|---|---|---|---|---|
MCUCR | SE | SM2 | SM1 | SM0 | ISC11 | ISC10 | ISC01 | ISC00 |
MCU Control Register
ISCx1 | ISCx0 | DESCRIPTION |
---|---|---|
0 | 0 | Low level of INTx generates an interrupt request |
0 | 1 | Any logic change on INTx generates an interrupt request |
1 | 0 | The falling edge of INTx generates an interrupt request |
1 | 1 | The rising edge of INTx generates an interrupt request |
ISC Bits Settings
7 bit | 6 bit | 5 bit | 4 bit | 3 bit | 2 bit | 1 bit | 0 bit | |
---|---|---|---|---|---|---|---|---|
GICR | INT1 | INT0 | - | - | - | - | IVSEL | IVCE |
General Interrupt Control Register
7 bit | 6 bit | 5 bit | 4 bit | 3 bit | 2 bit | 1 bit | 0 bit | |
---|---|---|---|---|---|---|---|---|
GIFR | INTF1 | INTF0 | - | - | - | - | - | - |
General Interrupt Flag Register
When the event specified by the Interrupt Sense Control (ISCxy) bits in the MCU Control Register (MCUCR) is sensed on the INTx pin, the External Interrupt Flag x (INTFx) in the General Interrupt Flag Register (GIFR) is set HIGH (1). If the I-bit in SREG and the INT1 bit in the GICR are both HIGH(1) the MCU will jump to the corresponding vector. The Flag is set to LOW (0) when the INTx_vect routine is executed.
SOFTWARE:
The external interrupt code is fairly simple, just declare your INTx pins as inputs, set the inputs as interrupts, turn on the interrupts, and finally don't forget your ISR routines.
ATmega8 Code:
#include <avr/io.h> #include <avr/interrupt.h> int main(void) { DDRD &= ~(1 << DDD2 ); // Clear the PD2 pin // PD2 (INT0 pin) is now an input PORTD |= (1 << PORTD2); // turn On the Pull-up // PD0 is now an input with pull-up enabled MCUCR |= (1 << ISC00); // set INT0 to trigger on ANY logic change GICR |= (1 << INT0); // Turns on INT0 sei(); // turn on interrupts while(1) { /* main program loop here */ } } ISR (INT0_vect) { /* interrupt code here */ }
I like big bots and I can not lie.
Cheers
Q