Alle Interrupts setzen voraus, dass sie zuerst global erlaubt wurden. Dies erfolgt durch das Setzen des I-Bits im Status-Register SREG des AVR's. Praktisch geschieht dies durch die Funktion sei(). Gesperrt werden Interrupts durch die Funktion cli().

Der ATmega8 verfügt über die im folgenden aufgelisteten Interruptquellen (Auszug aus iom8.h):

#define SIG_INTERRUPT0 _VECTOR(1) Ereignis an INT0 (siehe unten)
#define SIG_INTERRUPT1 _VECTOR(2) Ereignis an INT1 (siehe unten)
#define SIG_OUTPUT_COMPARE2 _VECTOR(3) siehe Timer/PWM
#define SIG_OVERFLOW2 _VECTOR(4) Überlauf von Timer/Counter2 (siehe Timer)
#define SIG_INPUT_CAPTURE1 _VECTOR(5) (habe ich noch nicht verwendet)
#define SIG_OUTPUT_COMPARE1A _VECTOR(6) siehe Timer/PWM
#define SIG_OUTPUT_COMPARE1B _VECTOR(7) siehe Timer/PWM
#define SIG_OVERFLOW1 _VECTOR(8) Überlauf von Timer/Counter1 (siehe Timer)
#define SIG_OVERFLOW0 _VECTOR(9) Überlauf von Timer/Counter0 (siehe Timer)
#define SIG_SPI _VECTOR(10) siehe SPI
#define SIG_UART_RECV _VECTOR(11) USART hat Zeichen empfangen (siehe USART)
#define SIG_UART_DATA _VECTOR(12) USART data register empty (siehe USART)
#define SIG_UART_TRANS _VECTOR(13) USART hat Transmission abgeschlossen (siehe USART)
#define SIG_ADC _VECTOR(14) ADC hat Konvertierung abgeschlossen (siehe ADC)
#define SIG_EEPROM_READY _VECTOR(15) (habe ich noch nicht verwendet)
#define SIG_COMPARATOR _VECTOR(16) (habe ich noch nicht verwendet)
#define SIG_2WIRE_SERIAL _VECTOR(17) (habe ich noch nicht verwendet)
#define SIG_SPM_READY _VECTOR(18) (habe ich noch nicht verwendet)

Man sieht, dass die Interrupts in einer Vektortabelle bestehend aus 18 Vektoren zusammengefasst sind. Der Inhalt der einzelnen Vektoren entspricht einem Zeiger auf die entsprechende Routine, welche beim Auslösen der Interrupts ausgeführt werden soll.
Beim Auslösen eines Interrupts unterbricht der Mikrocontroller automatisch das aktuelle Programm und lädt den Programmzähler und den Prozessorstatus auf den Stack. Dann startet die vom Programmierer festgelegte ISR (Interrupt-Service-Routine). Nach Abschluss der Bearbeitung werden die Daten wieder vom Stack herunter geladen und der normale Programmablauf fortgesetzt.

Hat man für den gewünschten Interrupt über das entsprechende Bit aktiviert und zusätzlich Interrupts noch global erlaubt, muss noch eine entsprechende Interrupt-Service-Routine (ISR) geschrieben werden. Ist diese nicht vorhanden, wird das Verhalten des MC unberechenbar. Normalerweise wird ein Reset ausgeführt.
Es gibt zwei Möglichkeiten eine solche ISR zu definieren:

SIGNAL ( xyz ) {                    //xyz entspricht einem Interruptvektor, z.B. SIG_INTERRUPT0
        Anweisung ( );              
//beliebige Anweisung
}

oder alternativ:

INTERRUPT ( xyz ) {
        Anweisung ( );
}

Der Unterschied zwischen beiden ISR's besteht im wesentlichen darin, dass bei betreten SIGNAL Interrupts global deaktiviert werden, bis die ISR fertig ausgeführt ist. Weitere Interrupts werden somit nicht erkannt, können allerdings den Programmablauf auch nicht stören.
Bei INTERRUPT bleiben Interrupts weiterhin aktiviert, somit kann während des Ausführens einer ISR bereits ein weiterer Interrupt erkannt und bearbeitet werden. Diese Option sollte mit Vorsicht benutzt werden! Generell empfiehlt sich die Verwendung von SIGNAL.
Zu finden sind beide Funktionen in den Headerdateien signal.h bzw. interrupt.h im Verzeichnis von WinAVR.

Ausgenommen der beiden nachfolgenden Interruptquellen habe ich die Interrupts jeweils schon in dem dazu passenden Kapitel erläutert.

Mit den Eingängen INT0 und INT1 verfügt der AVR über die Möglichkeit, auch externe Interrupts zu zulassen. Hervorzuheben ist hierbei, das es vollkommen egal ist, ob man die beiden PINS als Ein- oder Ausgänge definiert. Somit ist es sogar möglich, Software-Interrupts zu erzeugen. Die externen können auf steigende bzw. fallende Flanken getriggert werden. Es besteht zusätzlich die Möglichkeit, den Controller mit ihrer Hilfe "aufzuwecken", falls er sich in einem der Sleep-Modi befindet. Dieses hat jedoch für mein Projekt keinen Belang.
Wie die Eingänge agieren sollen, legen die Bits im Register MCUCR (MCU Control Register) fest.

INT1:

ISC11

ISC10

Beschreibung

0

0

Low-Pegel erzeugt Interrupt

0

1

Jeder Pegelwechsel erzeugt Interrupt

1

0

Fallende Flanke generiert Interrupt

1

1

Steigende Flanke generiert Interrupt

INT0:

ISC01

ISC00

Beschreibung

0

0

Low-Pegel erzeugt Interrupt

0

1

Jeder Pegelwechsel erzeugt Interrupt

1

0

Fallende Flanke generiert Interrupt

1

1

Steigende Flanke generiert Interrupt

 Nun müssen nur noch die externen Interrupts eingeschalten werden. Dies erfolgt durch setzen der Bits INT1 bzw. INT0 im Register GICR (General Interrupt Control Register).
Wird an INT1 ein Interrupt ausgelöst, so wird zusätzlich im GIFR  (General Interrupt Flag Register) INTF1 (Interrupt Flag) gesetzt. Dieses wird beim Ausführen der ISR (Interrupt-Service-Routine) automatisch wieder gelöscht.
Analog würde an INT0 das INTF0-Flag gesetzt und wieder gelöscht werden.
Diese Flags können auch manuell durch schreiben einer logischen 1 in die entsprechenden Bits gelöscht werden.

Eine Beispielanwendung kann man unter Programme finden.

 

Zurück zur Startseite.