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.