Soooo....
Ich habe jetzt hier ein (ungeprüftes) Beispielprogramm das, wenn es funktioniert, zwei Taster darauf überprüfen soll ob sie kurz (<3s) oder lang (>3s) gedrückt wurden, und jeweils eine von 4 zugehörigen Funktionen aufruft.
Der Code ist etwas lang, und normalerweise würde ich ein derartiges Programm auf mehrere .c und .h Dateien verteilen, aber es ist ja nur ein einfaches Beispiel.
Es beginnt mit der Definition einiger Variablen, dann kommt eine funktion die die Initialisierung des Mega8 übernimmt, gefolgt von den drei ISRs und den 4 Funktionen die aufgerufen werden sollen. Das eigentliche "Hauptprogramm", also main, kommt gaaanz am Schluss.Code:#include <avr/io.h> #include <avr/signal.h> #include <avr/interrupt.h> /* globale Variablen */ volatile unsigned char timer_10ms, timer_1s; volatile unsigned char flags; #define FLAG_INT0_SHORT 0 #define FLAG_INT0_LONG 0 #define FLAG_INT1_SHORT 0 #define FLAG_INT1_LONG 0 /* Hardware initialisieren */ void avr_init(void) { //Ports //Port-D DDRD = 0xF3; //Pins PD2(Int0) und PD3(Int1) als Eingang PORTD = 0x0C; //Pull-Up Widerstände von PD2 und PD3 aktiviert //Timer //Timer0 (10ms Takt) //ATmega8 Datenblatt, Seite 72 TCCR0 = 0x05; //Prescaler: 1/1024 TCNT0 = 0x64; //Vorgabewert: 100 //Timer Interrupt Register //ATmega8 Datenblatt, Seite 72-73 TIMSK = 0x01; //Overflow-Interrupt für Timer0 TIFR = 0x00; //Interrupt-Flag für Timer0 löschen //Externe Interrupts //ATmega8 Datenblatt, Seite 66-68 MCUCR = 0x0A; //Externe Interrupts für fallende Flanke konfigurieren GICR = 0xC0; //Externe Interrupts aktivieren GIFR = 0x00; //Interrupt-Flags löschen sei(); //Interrupts global aktivieren } /* Timer0 Interrupt Service Routine */ SIGNAL(SIG_OVERFLOW0) { TCNT0 = 0x64; //Vorgabewert neu einstellen timer_10ms++; //10ms Variable inkrementieren //nach einer Sekunde if(Timer_10ms % 100 == 0) { Timer_10ms = 0; //10ms Variable = 0 Timer_1s++; //1s Variable inkrementieren } } /* INT0 Interrupt Service Routine */ SIGNAL(SIG_INTERRUPT0) { static char int0_start, int0_duration; char tmp; //fallende oder steigende Flanke? if((MCUCR & 0x03) == 0x02) { //fallende Flanke //Startzeit merken int0_start = timer_1s; //Interrupt auf steigende Flanke einstellen tmp = MCUCR; tmp &= 0xFC; //Konfigurationsbits für INT0 löschen tmp |= 0x03; //einstellen auf steigende Flanke MCUCR = tmp; } else if((MCUCR & 0x03) == 0x03) { //steigende Flanke //aktuelle Zeit zwischenspeichern, falls ISR durch Timer-Interrupt unterbrochen wird tmp = timer_1s; if(tmp <= int0_start) int0_duration = tmp + (255 - int0_start); else int0_duration = tmp - int0_start; //kurz oder lang? if(int0_duration < 3) flags |= (1 << FLAG_INT0_SHORT); else flags |= (1 << FLAG_INT0_LONG); //Interrupt auf fallende Flanke einstellen tmp = MCUCR; tmp &= 0xFC; //Konfigurationsbits für INT0 löschen tmp |= 0x02; //einstellen auf fallende Flanke MCUCR = tmp; } else { //Interrupt falsch eingestellt, rücksetzen auf fallende Flanke tmp = MCUCR; tmp &= 0xFC; //Konfigurationsbits für INT0 löschen tmp |= 0x02; //einstellen auf fallende Flanke MCUCR = tmp; } } /* INT1 Interrupt Service Routine */ SIGNAL(SIG_INTERRUPT1) { static char int1_start, int1_duration; char tmp; //fallende oder steigende Flanke? if((MCUCR & 0x0C) == 0x08) { //fallende Flanke //Startzeit merken int0_start = timer_1s; //Interrupt auf steigende Flanke einstellen tmp = MCUCR; tmp &= 0xF3; //Konfigurationsbits für INT1 löschen tmp |= 0x0C; //einstellen auf steigende Flanke MCUCR = tmp; } else if((MCUCR & 0x0C) == 0x0C) { //steigende Flanke //aktuelle Zeit zwischenspeichern, falls ISR durch Timer-Interrupt unterbrochen wird tmp = timer_1s; if(tmp <= int1_start) int1_duration = tmp + (255 - int1_start); else int1_duration = tmp - int1_start; //kurz oder lang? if(int0_duration < 3) flags |= (1 << FLAG_INT1_SHORT); else flags |= (1 << FLAG_INT1_LONG); //Interrupt auf fallende Flanke einstellen tmp = MCUCR; tmp &= 0xF3; //Konfigurationsbits für INT1 löschen tmp |= 0x08; //einstellen auf fallende Flanke MCUCR = tmp; } else { //Interrupt falsch eingestellt, rücksetzen auf fallende Flanke tmp = MCUCR; tmp &= 0xF3; //Konfigurationsbits für INT1 löschen tmp |= 0x08; //einstellen auf fallende Flanke MCUCR = tmp; } } /* Hier kommen die Funktionen */ void action_int0_short(void) { //eine Funktion muss tun, was eine Funktion tun muss } void action_int0_long(void) { //eine Funktion muss tun, was eine Funktion tun muss } void action_int1_short(void) { //eine Funktion muss tun, was eine Funktion tun muss } void action_int1_long(void) { //eine Funktion muss tun, was eine Funktion tun muss } /* last but not least: main */ int main(void) { //Variablen initialisieren timer_10ms = 0; timer_1s = 0; flags = 0x00; //Hardware initialisieren avr_init(); while(1) { //Taster an INT0 wurde kurz betätigt if(flags & (1 << FLAG_INT0_SHORT)) { action_int0_short(); //zugehörige Funktion aufrufen flags &= ~(1 << FLAG_INT0_SHORT); //flag löschen } //Taster an INT0 wurde lang betätigt if(flags & (1 << FLAG_INT0_LONG)) { action_int0_long(); //zugehörige Funktion aufrufen flags &= ~(1 << FLAG_INT0_LONG); //flag löschen } //Taster an INT1 wurde kurz betätigt if(flags & (1 << FLAG_INT1_SHORT)) { action_int1_short(); //zugehörige Funktion aufrufen flags &= ~(1 << FLAG_INT1_SHORT); //flag löschen } //Taster an INT1 wurde lang betätigt if(flags & (1 << FLAG_INT1_LONG)) { action_int1_long(); //zugehörige Funktion aufrufen flags &= ~(1 << FLAG_INT1_LONG); //flag löschen } } }
Die Funktionen werden übrigens aus einem bestimmten Grund in main() aufgerufen: jede Funktion die man innerhalb einer ISR aufruft, verlängert diese unnötig, daher ist es sinnvoll sich nur zu merken welche Funktion aufgerufen werden soll, und dieses dann außerhalb der ISR zu tun.







Zitieren

Lesezeichen