avr ersterer schritt
  ISR
 
ISR

(ISR() ersetzt bei neueren Versionen der avr-libc SIGNAL(). SIGNAL sollte nicht mehr genutzt werden, zur Portierung von SIGNAL nach ISR siehe den Anhang.)

#include <avr/interrupt.h>
//...
ISR(Vectorname) /* vormals: SIGNAL(siglabel) dabei Vectorname != siglabel ! */
{
    /* Interrupt Code */
}

Mit ISR wird eine Funktion für die Bearbeitung eines Interrupts eingeleitet. Als Argument muss dabei die Benennung des entsprechenden Interruptvektors angegeben werden. Diese sind in den jeweiligen Includedateien IOxxxx.h zu finden. Die Bezeichnung entspricht dem Namen aus dem Datenblatt, bei dem die Leerzeichen durch Unterstriche ersetzt sind und ein _vect angehängt ist.

Als Beispiel ein Ausschnitt aus der Datei für den ATmega8 (bei WinAVR Standardinstallation in C:WinAVRavrincludeavriom8.h) in der neben den aktuellen Namen für ISR (*_vect) noch die Bezeichnungen für das inzwischen nicht mehr aktuelle SIGNAL (SIG_*) enthalten sind.

//...
/* $Id: iom8.h,v 1.13 2005/10/30 22:11:23 joerg_wunsch Exp $ */
 
/* avr/iom8.h - definitions for ATmega8 */
//...
 
/* Interrupt vectors */
 
/* External Interrupt Request 0 */
#define INT0_vect                       _VECTOR(1)
#define SIG_INTERRUPT0                  _VECTOR(1)
 
/* External Interrupt Request 1 */
#define INT1_vect                       _VECTOR(2)
#define SIG_INTERRUPT1                  _VECTOR(2)
 
/* Timer/Counter2 Compare Match */
#define TIMER2_COMP_vect                _VECTOR(3)
#define SIG_OUTPUT_COMPARE2             _VECTOR(3)
 
/* Timer/Counter2 Overflow */
#define TIMER2_OVF_vect                 _VECTOR(4)
#define SIG_OVERFLOW2                   _VECTOR(4)
 
/* Timer/Counter1 Capture Event */
#define TIMER1_CAPT_vect                _VECTOR(5)
#define SIG_INPUT_CAPTURE1              _VECTOR(5)
 
/* Timer/Counter1 Compare Match A */
#define TIMER1_COMPA_vect               _VECTOR(6)
#define SIG_OUTPUT_COMPARE1A            _VECTOR(6)
 
/* Timer/Counter1 Compare Match B */
#define TIMER1_COMPB_vect               _VECTOR(7)
#define SIG_OUTPUT_COMPARE1B            _VECTOR(7)
 
//... 

Mögliche Funktionsrümpfe für Interruptfunktionen sind zum Beispiel:

#include <avr/interrupt.h>
/* veraltet: #include <avr/signal.h> */
 
ISR(INT0_vect)       /* veraltet: SIGNAL(SIG_INTERRUPT0) */
{
    /* Interrupt Code */
}
 
ISR(TIMER0_OVF_vect) /* veraltet: SIGNAL(SIG_OVERFLOW0) */
{
    /* Interrupt Code */
}
 
ISR(USART_RXC_vect) /* veraltet: SIGNAL(SIG_UART_RECV) */
{
    /* Interrupt Code */
}
 
// und so weiter und so fort... 

Auf die korrekte Schreibweise der Vektorbezeichnung ist zu achten. Der gcc-Compiler prüft erst ab Version 4.x, ob ein Signal/Interrupt der angegebenen Bezeichnung tatsächlich in der Includedatei definiert ist und gibt andernfalls eine Warnung aus. Bei WinAVR (ab 2/2005) wurde die Überprüfung auch in den mitgelieferten Compiler der Version 3.x integriert. Aus dem gcc-Quellcode Version 3.x selbst erstellte Compiler enthalten die Prüfung nicht (vgl. AVR-GCC).

Während der Ausführung der Funktion sind alle weiteren Interrupts automatisch gesperrt. Beim Verlassen der Funktion werden die Interrupts wieder zugelassen.

Sollte während der Abarbeitung der Interruptroutine ein weiterer Interrupt (gleiche oder andere Interruptquelle) auftreten, so wird das entsprechende Bit im zugeordneten Interrupt Flag Register gesetzt und die entsprechende Interruptroutine automatisch nach dem Beenden der aktuellen Funktion aufgerufen.

Ein Problem ergibt sich eigentlich nur dann, wenn während der Abarbeitung der aktuellen Interruptroutine mehrere gleichartige Interrupts auftreten. Die entsprechende Interruptroutine wird im Nachhinein zwar aufgerufen jedoch wissen wir nicht, ob nun der entsprechende Interrupt einmal, zweimal oder gar noch öfter aufgetreten ist. Deshalb soll hier noch einmal betont werden, dass Interruptroutinen so schnell wie nur irgend möglich wieder verlassen werden sollten.

[Bearbeiten] Unterbrechbare Interruptroutinen

"Faustregel": im Zweifel ISR. Die nachfolgend beschriebene Methode nur dann verwenden, wenn man sich über die unterschiedliche Funktionsweise im Klaren ist.

#include <avr/interrupt.h>
 
ISR(XXX,ISR_NOBLOCK) /* veraltet: INTERRUPT(SIG_OVERFLOW0) */
{
    /* Interrupt-Code */
}

Hierbei steht XXX für den oben beschriebenen Namen des Vektors (also z. B. TIMER0_OVF_vect). Der Unterschied im Vergleich zu einer herkömmlichen ISR ist, dass hier beim Aufrufen der Funktion das Global Enable Interrupt Bit durch Einfügen einer SEI-Anweisung direkt wieder gesetzt und somit alle Interrupts zugelassen werden – auch XXX-Interrupts.

Bei unsachgemässer Handhabung kann dies zu erheblichen Problemen wie einem Stack-Overflow oder anderen unerwarteten Effekten führen und sollte wirklich nur dann eingesetzt werden, wenn man sich sicher ist, das Ganze auch im Griff zu haben.

Insbesondere sollte möglichst am ISR-Anfang die auslösende IRQ-Quelle deaktiviert und erst am Ende der ISR wieder aktiviert werden. Robuster als die Verwendung einer NOBLOCK-ISR ist daher folgender ISR-Aufbau:

#include <avr/interrupt.h>
 
ISR (XXX) 
{
    // Implementiere die ISR ohne zunaechst weitere IRQs zuzulassen
 
    <<Dektiviere die XXX-IRQ>>
 
    // Erlaube alle Interrupts (ausser XXX)
    sei();
 
    //... Code ...
 
    // IRQs global deaktivieren um die XXX-IRQ wieder gefahrlos 
    // aktivieren zu koennen
    cli();
 
    <<Aktiviere die XXX-IRQ>>
}

Auf diese Weise kann sich die XXX-IRQ nicht selbst unterbrechen, was zu einer Art Endlosschleife führen würde.

Siehe auch: Hinweise in AVR-GCC

siehe dazu: http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html

 
  Heute waren schon 9 Besucher (10 Hits) hier!  
 
Diese Webseite wurde kostenlos mit Homepage-Baukasten.de erstellt. Willst du auch eine eigene Webseite?
Gratis anmelden