Pin Interrupts
From Wiki
A common task in embedded programming is checking when the state of pin has changed. You can write software to poll a pin's state, or in the case of AVR you can set up an interrupt. An interrupt can be used to notify your program when a pin state has changed.
The following example will show how to use external interrupts (as opposed to timer interrupts) on an Atmel AVR using software written in GCC.
The first thing to do is to see what interrupts are available for your model of processor. For this example I will be using the attiny2313.
You can use the data sheet (http://www.atmel.com/dyn/resources/prod_documents/doc2543.pdf) available from atmel to find the interrupts. On the attiny2313 externeral interrupts are triggered by INT0, INT1 and PCINT0..7 . (Table 21).
http://www.windmeadow.com/imgs/avrinterrupt1.png
Next, you must find out which pins can be used as external interrupts. Figure 1 of the datasheet shows that pins 6 (PD2) and pin 7 (PD3) may be used as external interrupts for INT0 and INT1. Pins 12 through 19 can be used for PCINT.
http://www.windmeadow.com/imgs/avrinterrupt2.png
The next step is find out the register that controls the pins that contribute to the pin change interrupt. The PCMSK register controls the external interrupt pins in the atttiny2313.
http://www.windmeadow.com/imgs/avrinterrupt3.png
So what are your options? What can the pins detect?
The interrupts can detect four different types of pin changes:
1. pin goes low
2. any logical change in pin
3. falling edge (pin goes from high to low)
4. rising edge (ping goes from low to high)
Tables 31 and 32 describe this for the attiny2313.
http://www.windmeadow.com/imgs/avrinterrupt4.png
MCUR , the MCU control register, defines which of the four states will active the interrupt. The above bits table 31 and 32 must be set in the MCUR register.
Lastly, we must turn on the interrupt. The general interrupt mask register, GIMSK, controls when an interrupt is enabled.
Now for a code sample. The following sample code will set interrupt int0 when pin 6 goes from high to low:
#include <avr/interrupt.h>
int main (void)
{
// Set Pin 6 (PD2) as the pin to use for this example
PCMSK |= (1<<PIND2);
// interrupt on INT0 pin falling edge (sensor triggered)
MCUCR = (1<<ISC01) | (1<<ISC00);
// turn on interrupts!
GIMSK |= (1<<INT0);
while (1) { }
}
SIGNAL (SIG_INT0)
{
// Do some stuff<br>
}
First tell PCMSK which pin we will use. This line sets bit 2 of PCMSK to 1.
// Set Pin 6 (PD2) as the pin to use for this example PCMSK |= (1<<PIND2);
Look at table 32 to find out the bits to set to make the interrupt trigger on the falling edge.
// interrupt on INT0 pin falling edge (sensor triggered) MCUCR = (1<<ISC01) | (1<<ISC00);
Last we turn it on.
// turn on interrupts! GIMSK |= (1<<INT0);
We have to figure out which vector will be called when the interrupt triggers. To find this out look at the avr/interrupt.h http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html documentation.
| INT0_vect | SIG_INTERRUPT0 | External Interrupt 0 | AT90S1200, AT90S2313, AT90S2323, AT90S2333, AT90S2343, AT90S4414, AT90S4433, AT90S4434, AT90S8515, AT90S8535, AT90PWM3, AT90PWM2, AT90CAN128, AT90CAN32, AT90CAN64, ATmega103, ATmega128, ATmega16, ATmega161, ATmega162, ATmega163, ATmega165, ATmega169, ATmega32, ATmega323, ATmega325, ATmega3250, ATmega329, ATmega3290, ATmega406, ATmega64, ATmega645, ATmega6450, ATmega649, ATmega6490, ATmega8, ATmega8515, ATmega8535, ATmega168, ATmega48, ATmega88, ATmega640, ATmega1280, ATmega1281, ATmega324, ATmega164, ATmega644, ATtiny11, ATtiny12, ATtiny13, ATtiny15, ATtiny22, ATtiny2313, ATtiny26, ATtiny28, ATtiny24, ATtiny44, ATtiny84, ATtiny45, ATtiny25, ATtiny85, ATtiny261, ATtiny461, ATtiny861 |
This signal gets run when the interrupt fires.
SIGNAL (SIG_INT0)
<BR>{
<BR> // Do some stuff<br>
<BR>}
The PCINT interrupt differs from INT0 and INT1. With INT0 and INT1 you can trigger the interrupt on the falling or rising edge. With PCINT, the interrupt is triggered by any change in the pin state. Pins 12 through 19 share the same interrupt. The MCU control register (MCUR) is not used with the PCINT interrupt. You set the PCMSK mask to tell the attiny2313 which pins can trigger the interrupt. An example would be to set the mask to pins 12,13 and 14. When any of these three pins changes state, the SIG_PCINT event will fire. The event will not know which of the pins changed states.
Sample code:
#include <avr/interrupt.h><br>
int main (void)
{
PCMSK |= (1<<PCINT2); // tell pin change mask to listen to pin14
PCMSK |= (1<<PCINT3); // tell pin change mask to listen to pin15
PCMSK |= (1<<PCINT4); // tell pin change mask to listen to pin16
GIMSK |= (1<<PCIE); // enable PCINT interrupt in the general interrupt mask
sei(); // Enable all interrupts<br>
while (1) { }
}
SIGNAL (SIG_PCINT)
{
// One of pins 14,15 or 16 just changed states
// do some stuff
}
Resources: http://www.avrfreaks.com , http://www.smileymicros.com/ C Programming for Microcontrollers , http://www.windmeadow.com
