Beruflich Dokumente
Kultur Dokumente
Unter einem Interrupt kann man sich einen durch Hardware ausgelösten
Unterprogrammaufruf vorstellen.
Interrupts werden bei Mikrocontrollern dazu eingesetzt, um auf äußere und interne
Systemzustände augenblicklich reagieren zu können. So kann zum Beispiel in einem
gesteuerten Prozess ein gefährlicher Betriebszustand eintreten oder ein interner
Prozessorzustand erfordert eine Reaktion, zum Beispiel beim Empfang von Daten an
der seriellen Schnittstelle.
Wenn ein Interrupt eintrifft, wird automatisch das Global Interrupt Enable Bit GIE
im Status Register SREG gelöscht und alle weiteren Interrupts unterbunden.
Obwohl es möglich ist, zu diesem Zeitpunkt bereits wieder das GIE-Bit zu setzen,
wird dringend davon abgeraten. Dieses wird nämlich automatisch gesetzt, wenn die
Interruptroutine beendet wird.
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 gelöscht.
Die Interrupt-Service_Routinen heißen alle ISR und haben als Parameter für den
betreffenden Interrupt einen Interruptvektor.
Mit Hilfe des Interruptvektors sorgt der Compiler dafür, 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
Die Abbildung zeigt die Lage der Pin-Anschlüsse der externen Interrupts
INT0, INT1 und INT2.
Die Interrupt-Service-Routine:
Die ISR wird automatisch aufgerufen, wenn ein Fußgänger beim Drücken der
Ruftaste an PD2 eine ansteigende Signalflanke erzeugt.
Die Ampel durchläuft dann die 6 Steuerphasen, um anschließend wieder in den
Grundzustand zurückzukehren.
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:
//Datenrichtungsregister setzen:
DDRC=0xf0;//Straßenampel PC4(ROT),PC5(Gelb),PC6(Grün)
DDRD=0xf0;//Fussgängertaste PD2,
//Fussgängerampel PD4(ROT),PD5(Rot),PD6(Grün)
//Interrupt initialisieren:
MCUCR|=(1<<ISC01)|(1<<ISC00); //Steigende Flanke löst 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();
Stellt man nun das Register OCR0 auf 249, so wird das Zählregister TCNT0
125-mal in der Sekunde zurückgesetzt (31250/250=125).
Damit können 125 OutputCompare0-Interruptsausgelöst 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"
TIMER0_interrupt_init(void){
z=0; //ISR-Zähler = 0
TCNT0=0; //Anfangszählerstand = 0
OCR0=249; //Zähler zählt bis 250: 31250/250 = 125
TCCR0=0x0c; //CTC-Modus: Takt intern von 8 Mhz /256 = 31250Hz
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);
}