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.
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
}
}
}
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.
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.
Lesezeichen