Sie sind auf Seite 1von 11

Interrupttechnik mit dem ATmega32

Unter einem Interrupt kann man sich einen durch Hardware ausgelsten
Unterprogrammaufruf vorstellen.
Aufgrund einer Interruptanforderung wird das laufende Programm unterbrochen und
das hierfr vorgesehene Unterprogramm ausgefhrt. Danach wird das unterbrochene
Programm an der Unterbrechungsstelle wieder fortgesetzt.
Interrupts werden bei Mikrocontrollern dazu eingesetzt, um auf uere und interne
Systemzustnde augenblicklich reagieren zu knnen. So kann zum Beispiel in einem
gesteuerten Prozess ein gefhrlicher Betriebszustand eintreten oder ein interner
Prozessorzustand erfordert eine Reaktion, zum Beispiel beim Empfang von Daten an
der seriellen Schnittstelle.
Ein Programm mit Interruptsteuerung hat folgende Merkmale:
Es muss eine Interrupt-Service-Routine vorhanden sein (das auszufhrende
Unterprogramm)
Die Interruptsteuerung muss an Anfang des Hauptprogramms aktiviert worden sein.

Die folgenden Ereignisse knnen einen Interrupt auf einem AVR ATmega32 auslsen,
wobei die Reihenfolge der Auflistung auch die Prioritt der Interrupts entspricht:

Allgemeines ber die Interruptabarbeitung


Wenn ein Interrupt eintrifft, wird automatisch das Global Interrupt Enable Bit GIE
im Status Register SREG gelscht und alle weiteren Interrupts unterbunden.
Obwohl es mglich ist, zu diesem Zeitpunkt bereits wieder das GIE-Bit zu setzen,
wird dringend davon abgeraten. Dieses wird nmlich automatisch gesetzt, wenn die
Interruptroutine beendet wird.
Wenn in der Zwischenzeit weitere Interrupts eintreffen, werden die zugehrigen
Interrupt-Bits gesetzt und die Interrupts bei Beendigung der laufenden InterruptRoutine in der Reihenfolge ihrer Prioritt ausgefhrt. Dies kann eigentlich nur dann
zu Problemen fhren, wenn ein hoch priorisierter Interrupt stndig und in kurzer
Folge auftritt. Dieser sperrt dann mglicherweise alle anderen Interrupts mit
niedrigerer Prioritt. Dies ist einer der Grnde, weshalb die Interrupt-Routinen sehr
kurz gehalten werden sollen.
Interrupts mit dem AVR GCC Compiler (WinAVR)
Funktionen zur Interrupt-Verarbeitung werden in der Includedatei interrupt.h
der avr-libc zur Verfgung gestellt :
#include <avr/interrupt.h>

// fuer sei(), cli() und ISR():

Das Makro sei() schaltet die Interrupts ein. Eigentlich wird nichts anderes gemacht,
als das Global Interrupt Enable Bit im Status Register gesetzt.
Das Makro cli() schaltet die Interrupts aus, oder anders gesagt, das Global
Interrupt Enable Bit im Status Register wird gelscht.

Die Interrupt-Service_Routinen heien alle ISR und haben als Parameter fr den
betreffenden Interrupt einen Interruptvektor.
Mit Hilfe des Interruptvektors sorgt der Compiler dafr, dass die ISR an der
richtigen Interrupt-Einsprungadresse im Controller platziert wird.
Damit eine ISR aufgerufen werden kann, muss der Interrupt im Hauptprogramm
aktiviert werden. Diese Aktivierung besteht aus der Aktivierung des jeweiligen
Interrupts und aus der allgemeinen Interruptfreigabe mit sei();

Tabelle der Interruptvektoren des Atmega32


_VECTOR(1)
_VECTOR(2)
_VECTOR(3)
_VECTOR(4)
_VECTOR(5)
_VECTOR(6)
_VECTOR(7)
_VECTOR(8)
_VECTOR(9)
_VECTOR(10)
_VECTOR(11)
_VECTOR(12)
_VECTOR(13)
_VECTOR(14)
_VECTOR(15)
_VECTOR(16)
_VECTOR(17)
_VECTOR(18)
_VECTOR(19)
_VECTOR(20)

INT0_vect
INT1_vect
INT2_vect
TIMER2_COMP_vect
TIMER2_OVF_vect
TIMER1_CAPT_vect
TIMER1_COMPA_vect
TIMER1_COMPB_vect
TIMER1_OVF_vect
TIMER0_COMP_vect
TIMER0_OVF_vect
SPI_STC_vect
USART_RXC_vect
USART_UDRE_vect
USART_TXC_vect
ADC_vect
EE_RDY_vect
ANA_COMP_vect
TWI_vect
SPM_RDY_vect

External Interrupt Request 0


External Interrupt Request 1
External Interrupt Request 2
Timer/Counter2 Compare Match
Timer/Counter2 Overflow
Timer/Counter1 Capture Event
Timer/Counter1 Compare Match A
Timer/Counter1 Compare Match B
Timer/Counter1 Overflow
Timer/Counter0 Compare Match
Timer/Counter0 Overflow
Serial Transfer Complete
USART, Rx Complete
USART Data Register Empty
USART, Tx Complete
ADC Conversion Complete
EEPROM Ready
Analog Comparator
2-wire Serial Interface
Store Program Memory Ready

Beispiel 1:
Interruptgesteuerte Fugngerampel mit dem externen Interrupt INT0:

Die Abbildung zeigt die Lage der Pin-Anschlsse der externen Interrupts
INT0, INT1 und INT2.
Initialisierung von INT0:
GICR|=(1<<INT0); // INT0 enable im General Interrupt Control Register
MCUCR|=(1<<ISC01)|(1<<ISC00); //Steigende Flanke lst aus
sei();
Die Interrupt-Service-Routine:
Die ISR wird automatisch aufgerufen, wenn ein Fugnger beim Drcken der
Ruftaste an PD2 eine ansteigende Signalflanke erzeugt.

Die Ampel durchluft dann die 6 Steuerphasen, um anschlieend wieder in den


Grundzustand zurckzukehren.
Die recht lang dauernde ISR entspricht eigentlich nicht den Regeln!
Da das Hauptprogramm nach den Start jedoch nichts mehr macht, geht das in
Ordnung.

ISR(INT0_vect){
uint8_t n;
for(n=0;n<6;n++){
PORTC=sampel[n];
PORTD=fampel[n];
warten_ns(zeit[n]);
}
}

Das komplette Programm:


//Steuerung einer Fugngerampel
//Anwendung von INT0
//W.Tschallener 6.11.2007
//Verbindungen MCU - APL-Karte:
//PortC - SV4, PortD - SV5
//--------------------------------------------------------------#include <avr/io.h>
#include <avr/interrupt.h>
#include "warten.h"
const uint8_t fampel[6]={0x20,0x10,0x10,0x10,0x30,0x40},
sampel[6]={0x30,0x30,0x40,0x30,0x30,0x30},
zeit[6] = {1,
1,
5,
1,
1,
5};
//---------------------------------------------------------------void FussgaengerAmpel_init(void){
//Datenrichtungsregister setzen:
DDRC=0xf0;//Straenampel PC4(ROT),PC5(Gelb),PC6(Grn)
DDRD=0xf0;//Fussgngertaste PD2,
//Fussgngerampel PD4(ROT),PD5(Rot),PD6(Grn)
//Ampel in Grundstellung bringen:
PORTC=sampel[5];//Straenampel
PORTD=fampel[5];//Fugngerampel
//Interrupt initialisieren:
MCUCR|=(1<<ISC01)|(1<<ISC00); //Steigende Flanke lst aus
GICR|=(1<<INT0); // INT0 enable
// Interrupt starten
sei();
}
//---------------------------------------------------------------ISR(INT0_vect){
uint8_t n;
for(n=0;n<6;n++){
PORTC=sampel[n];
PORTD=fampel[n];
warten_ns(zeit[n]);
}
}

//---------------------------------------------------------------int main(void){
FussgaengerAmpel_init();
while(1);//Endlosschleife, die nichts macht
return 0; }

Beispiel 2
Software-Uhr mit Timer/Counter0 im CTC-Mode
(CTC: Clear Timer On Compare Match)
Timer/Counter0 Compare Match Interrupt:
Im Timer Interrupt Masken Register muss das Bit OCIE0 = 1 gesetzt werden.
(OCIE0 : Output Compare Interrupt Enable 0)

Das Control-Register TCCR0 wird auf CTC-Mode eingestellt:


WGM00=0, WGM01=1
Der Ausgang OC0 ist nicht angeschlossen:
COM00=0, COM01=0
Der Prescaler wird auf den Teilungsfaktor 256 eingestellt:
CS02=1, CS01=0, CS00=0
Hieraus ergibt sich eine Taktfrequenz von 8MHz/256=31 250 Hz.

Stellt man nun das Register OCR0 auf 249, so wird das Zhlregister TCNT0
125-mal in der Sekunde zurckgesetzt (31250/250=125).
Damit knnen 125 OutputCompare0-Interruptsausgelst werden, die das Timing
einer Softwareuhr bewirken

//Einfaches Uhrenprogramm mit Timer/Counter0 im CTC-Modus


//--------------------------------------------------------------#include <avr/io.h>
#include <avr/interrupt.h>
#include "lcd_port.h"
volatile uint8_t z, stunde=23,minute=59,sekunde=50;
//Die ISR wird 125-mal pro Sekunde aufgerufen
ISR(TIMER0_COMP_vect){
z++;
if(z==125) {sekunde++; z=0;
//Das nachfolgende Stellen der Uhr knnte auch in main erfolgen!
if(sekunde==60){sekunde=0; minute++;}
if(minute==60){minute=0;stunde++;}
if(stunde==24)stunde=0;
}
}
TIMER0_interrupt_init(void){
z=0;
//ISR-Zhler = 0
TCNT0=0; //Anfangszhlerstand = 0
OCR0=249; //Zhler zhlt bis 250: 31250/250 = 125
TCCR0=0x0c; //CTC-Modus: Takt intern von 8 Mhz /256 = 31250Hz

//Timer/Counter0 Compare Match Interrupt aktivieren:


TIMSK|=(1<<OCIE0);
sei();

void uhrzeit_anzeigen(void){
lcd_gotoxy(0,0);lcd_putui_0(stunde,2);
lcd_putc(':'); lcd_putui_0(minute,2);
lcd_putc(':'); lcd_putui_0(sekunde,2);
}

void main(){
lcd_init(12);
TIMER0_interrupt_init();
do{
uhrzeit_anzeigen();

}while(1);