-
        

Seite 1 von 3 123 LetzteLetzte
Ergebnis 1 bis 10 von 28

Thema: Interrupts - von der Vektortabelle zur ISR Definition

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    15.04.2006
    Beiträge
    18

    Interrupts - von der Vektortabelle zur ISR Definition

    Anzeige

    Guten Tag Leute!

    Hab mich lange um die Interrupts gedrückt, aber irgendwie will ichs heut
    wissen, und die Dinger nun endlich angehn.

    Es würde mich freuen, wenn hier ein kleines aber feines Tutorial entsteht. Betonung liegt auf klein und fein.

    Zunaechst mal wo liegt ueberhaupt mein Problem/was ist mein Stand?:
    Hab nun so weit im Atmega8 Datenblatt gewühlt und folgendes zusammengetragen:

    Code:
    //Wissenswertes zu Interrupts auf AVRs: 
    //   Global Interrupt Enable I-Bit im GICR Register ist normalerweise LOW wenn Interupt ausgeführt wird
    //   Interrupts haben zwar eine Priorität, können sich aber normalerweise nicht gegenseitig unterbrechen
    //   Interrupt Schachtelung mittels manuellem I-Bit setzen möglich
    //   Information im Statusregister SREG geht bei Interruptausführung verloren wenn man nicht sorgetraegt
    //   Befehle: _SEI() = Set I Bit - Aktiviert Interruptfaehigkeit
    //            _CLI()= Clear I Bit - Schaltet Interruptfaehigkeit aus
    //            _SLEEP() = uC geht in den Sleep Modus und wartet auf naechsten Interrupt
    Auch die Intterruptvektortabelle des Atmega 8 (auf Seite 44) ist mir ins Auge gestochen. Gut so weit. Was ich nun aber nicht gefunden habe, ist
    wo /wie schreibe ich nun eine ISR für einen Interrupt???

    Prinzipiell sollte es ja so gehen wie bei folgendem Programmbeispiel - einem RS232 Mirror:
    Code:
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>
    
    #define SYSCLK		7372800
    #define BAUD		38400UL
    #define UBRR_BAUD	((SYSCLK/(16*BAUD))-1)
    
    /* USART initialisieren */
    void uart_init(void);
    
    
    int main(void)
    {
    	/* USART initialisieren */
    	uart_init();
    
    	sei();
    
    	/* Nichts tun. Die Interrupts erledigten den Rest */
    	while (1)
    		;
    }
    
    void uart_init(void)
    {
    	/* Baudrate einstellen ( Normaler Modus ) */
    	UBRRH = (unsigned char) (UBRR_BAUD>>8);
    	UBRRL = (unsigned char) UBRR_BAUD;
    
    	/* Aktivieren des Empfängers, des Senders und des "Daten empfangen"-Interrupts */
    	UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);
    
    	/* Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit */
    	UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
    }
    
    /* Interrupt wird ausgelöst sobald neue Daten im USART-Empfangspuffer liegen */
    SIGNAL(SIG_UART_RECV)
    {
    	unsigned char buffer;
    
    	/* Daten aus dem Puffer lesen ... */
    	buffer = UDR;
    
    	/* ... warten bis der Sendepuffer leer ist ... */
    	while ( !( UCSRA & (1<<UDRE)) )
    		;
    	/* ... und gleich wieder zurück schicken */
    	UDR = buffer;
    }
    Aber woher weiß ich bzw. der Verfasser dieses Codes das der Interrupt ausgerechnet SIG_UART_RECV heißt? Dazu habe ich weder im Datenblatt noch sonst wo was gefunden.

    Wär super, wenn mir da jemand auf die Sprünge helfen könnte!

    Vielen Dank schon mal im Voraus !

    uC

  2. #2
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    08.05.2005
    Ort
    Issum
    Alter
    45
    Beiträge
    2.236
    Hallo,
    Bist Du auf die Idee gekommen mal io.h von Deinem µC zu lesen ?
    Wenn nicht dann schau mal rein

    Gruß Sebastian
    Software is like s e x: its better when its free.
    Linus Torvald

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    15.04.2006
    Beiträge
    18
    Code:
    /* Interrupt vectors */
    
    #define SIG_INTERRUPT0		_VECTOR(1)
    #define SIG_INTERRUPT1		_VECTOR(2)
    #define SIG_OUTPUT_COMPARE2	_VECTOR(3)
    #define SIG_OVERFLOW2		_VECTOR(4)
    #define SIG_INPUT_CAPTURE1	_VECTOR(5)
    #define SIG_OUTPUT_COMPARE1A	_VECTOR(6)
    #define SIG_OUTPUT_COMPARE1B	_VECTOR(7)
    #define SIG_OVERFLOW1		_VECTOR(8)
    #define SIG_OVERFLOW0		_VECTOR(9)
    #define SIG_SPI			_VECTOR(10)
    #define SIG_UART_RECV		_VECTOR(11)
    #define SIG_UART_DATA		_VECTOR(12)
    #define SIG_UART_TRANS		_VECTOR(13)
    #define SIG_ADC			_VECTOR(14)
    #define SIG_EEPROM_READY	_VECTOR(15)
    #define SIG_COMPARATOR		_VECTOR(16)
    #define SIG_2WIRE_SERIAL	_VECTOR(17)
    #define SIG_SPM_READY		_VECTOR(18)
    
    #define _VECTORS_SIZE 38
    Waer der Abschnitt der iom8.h die in die io.h eingebunden im Falle eines Atmega8 eigebunden wird. Danke für den spartanischen aber brauchbaren Tipp.

    Zum Gesamtverstaendnis und zur Eigenkontrolle: Es sind Hardwaremaessig Flags reserviert, welche ueber ein entsprechendes
    Ereigniss informieren (z.B. Int0, Toggle an Pin PD2), sobald aktueller
    Befehl abgearbeitet ist UND das IVCE-Bit im GICR Register ist Null sowie das Bit 7 (berühmtes I-Bit ) in SREG gesetzt ist.


    Danke für die Hilfe! Den Blick in die io.h hät ich wirklich eher waagen sollen...

    uC

  4. #4
    Neuer Benutzer Öfters hier
    Registriert seit
    15.04.2006
    Beiträge
    18
    Noch ne Frage, beim durchblaettern, hab ich die Anweisung _SFR_IO8(0x3A)
    gefunden. Ist das der Zauberbefehl, mit dem man Zeigerbiegen kann? Sprich
    Einen Zeiger auf eine Speicherstelle definieren kann?
    Danke wieder im Voraus

  5. #5
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    08.05.2005
    Ort
    Issum
    Alter
    45
    Beiträge
    2.236
    Den Blick in die io.h hät ich wirklich eher waagen sollen...
    Ja, das würde ich auch immer empfehlen, ist auch der einfachste Weg

    Zu Deiner anderen Frage, es ist ziemlich einfach zu erklären, die Vektoren liegen alle ganz am Anfang von Flash, bei Adresse 0 reset, also die Stelle, wo der µC immer anfängt, Adresse 1 externer Interrupt INT0 usw. wie in der io8.h aufgelistet.

    Wenn man das jetzt im Assembler schreibt sollte man die ganze Tabelle am Anfang ausschreiben z.B.
    [code]
    org 0x0000
    rjmp reset
    rjmp siginterrupt0
    reti
    reti
    ...
    [code]

    Wenn jetzt ein Ereignis eintrifft wird wie Du schon sagtest ein Flag gesetzt
    hier z.B Register GIFR Bit INTF0.
    Wenn jetzt Interrupts erlaubt sind (sei) und hier Register GICR bit INT0 wird zu Adresse 0x01 gesprungen, wo wiederum rjmp siginterrupt0
    steht, womit Du dann irgendwo im label siginterrupt0 landest.
    Andere Interrupts stoßen da direkt auf reti, kommen also sofort wieder zurück.
    Die Vectortabelle ist stark µC abhängig!
    also immer nachgucken wie sie heißen, der Kompiler prüft die Namen nicht
    und wenn Du Dich vertippt hast klappt die ganze Sache nicht...

    Ich hoffe das ist verständig genug, und alles so 100% richtig.

    P.S. Welche avr-gcc Version hast Du eigentlich, ist aber nicht die neueste
    man sollte nicht mehr mit SIG..... arbeiten, ich würde mal updaten sehe hier

    Gruß Sebastian
    Software is like s e x: its better when its free.
    Linus Torvald

  6. #6
    Neuer Benutzer Öfters hier
    Registriert seit
    15.04.2006
    Beiträge
    18
    Noch eine Frage: Welche Rolle spielen die Interrupt.h und die Signal.h

  7. #7
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    08.05.2005
    Ort
    Issum
    Alter
    45
    Beiträge
    2.236
    signal.h gilt als veraltet (avr 3.4.4) und wird irgendwann aus avr-gcc raufliegen, man soll nur die interrupt.h benutzen.

    Gruß Sebastian
    Software is like s e x: its better when its free.
    Linus Torvald

  8. #8
    Neuer Benutzer Öfters hier
    Registriert seit
    15.04.2006
    Beiträge
    18
    Hi, habe nun also ein wenig mit den Interrupts gespielt. Im Anhang ein nettes kleines Demoprogramm, dass beide externen Interrupts bedient.

    Kurzbeschreibung: Wird am Int0 Pin eine steigende Flanke produziert,
    so wird Zustand des PortsB um 1 erhöht.

    Wird INT1 ausgeloest, wird PortB einfach 0x0a aufgeprägt.

    Funktioniert so weit ganz gut, nur ein paar Schönheitsfehler die denke ich
    charakteristisch für Interrupts sind würde ich gerne noch geklärt wissen:

    Beim Erhöhen von PortB mußte ich intervenieren, da der nicht einfach
    ueberlief und wieder bei Null haengen blieb, sondern immer die oberen
    beiden Bits "haengen" bleiben.

    Die Sache mit dem Schalterprellen konnte ich nicht einfach dadurch beseitigen, dass ich den Interrupt in der entsprechenden ISR ausgeschaltet
    habe. Abhilfe?

    Code:
    // Demoprogramm zur Verwendung von Interrupts am Beispiel der externen Interruptquellen (Int1 Int0)
    // Autor: Bachmayer
    // Review Status: NONE
    //Wissenswertes zu Interrupts auf AVRs: 
    //   Global Interrupt Enable I-Bit im GICR Register ist normalerweise LOW wenn Interupt ausgeführt wird
    //   Interrupts haben zwar eine Priorität, können sich aber normalerweise nicht gegenseitig unterbrechen
    //   Interrupt Schachtelung mittels manuellem I-Bit setzen möglich
    //   Information im Statusregister SREG geht bei Interruptausführung verloren wenn man nicht sorgetraegt
    //   Befehle: _SEI() = Set I Bit - Aktiviert Interruptfaehigkeit
    //            _CLI()= Clear I Bit - Schaltet Interruptfaehigkeit aus
    //            _SLEEP() = uC geht in den Sleep Modus und wartet auf naechsten Interrupt  
    //
    // 
    // Die Verfuegbaren Interrupt Signale entnommen aus der io.h wo diese den entsprechenden Interruptvektoren zugeordnet werden: 
    // #define SIG_INTERRUPT0		_VECTOR(1)
    // #define SIG_INTERRUPT1		_VECTOR(2)
    // #define SIG_OUTPUT_COMPARE2	_VECTOR(3)
    // #define SIG_OVERFLOW2		_VECTOR(4)
    // #define SIG_INPUT_CAPTURE1	_VECTOR(5)
    // #define SIG_OUTPUT_COMPARE1A	_VECTOR(6)
    // #define SIG_OUTPUT_COMPARE1B	_VECTOR(7)
    // #define SIG_OVERFLOW1		_VECTOR(8)
    // #define SIG_OVERFLOW0		_VECTOR(9)
    // #define SIG_SPI				_VECTOR(10)
    // #define SIG_UART_RECV		_VECTOR(11)
    // #define SIG_UART_DATA		_VECTOR(12)
    // #define SIG_UART_TRANS		_VECTOR(13)
    // #define SIG_ADC				_VECTOR(14)
    // #define SIG_EEPROM_READY		_VECTOR(15)
    // #define SIG_COMPARATOR		_VECTOR(16)
    // #define SIG_2WIRE_SERIAL	    _VECTOR(17)
    // #define SIG_SPM_READY		_VECTOR(18)
    //
    //
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>
    #include <avr/delay.h>
    
    int8_t m;
    
    void main(void)
    {
    DDRB=0xff;
    DDRD=0x00; // Kompletter D Port wird hier als Input definiert. Beachte, auch als Output Interrupt möglich!
    //Konfiguration eines externen Interrupts (Alternativfunktion int0 int1 Pins) im MCUCR Register:
    // ISC11/ISC10 fuer INT1; ISC01/ISC00 fuer INT0; 
    //ISC11 ISC10 	Description
    //0 	0 		The low level of INT1 generates an interrupt request.
    //0 	1 		Any logical change on INT1 generates an interrupt request.
    //1 	0 		The falling edge of INT1 generates an interrupt request.
    //1 	1 		The rising edge of INT1 generates an interrupt request.
    cli(); // i Bit in Statusregister gelöscht=> Interrupts deaktiviert
    MCUCR=(1<<ISC11)|(1<<ISC10)|(1<<ISC01)|(1<<ISC00); // Definition der Ereignisse fuer die entsprechenden Interrupts
    GICR=(1<<INT1)|(1<<INT0); // Nun sind die Interrupts scharf
    sei(); // i Bit in Statusregister gesetzt=> Interrupts koennen ab jetzt auftreten
    for(;;)
    {
    }
    }
    
    SIGNAL(SIG_INTERRUPT0) // ISR fuer die erste Service Routine: Zaehlt einfach den PortB hoch
    {
    GICR=0x00;             //A: Versuch Schalterprellen zu beseitigen, maessiger Erfolg ...
    m=PINB;
    if (m>0x2e) {m=0;}
    PORTB=m+1;
    _delay_ms(250);         // warten... um garantiert nicht schneller zu sein wie Schalterprellen...
    _delay_ms(250);         // 
    GICR=(1<<INT1)|(1<<INT0); // A: Externe Interrupts wieder aktiviert
    }
    
    SIGNAL(SIG_INTERRUPT1)  // ISR fuer zweiten externen Interrupt: Setzt einfach charakteristisches Muster...
    {
    PORTB=0x0a;
    }
    In jedem Falle vielen vielen herzlichen Dank an izaseba!

    uC

  9. #9
    Neuer Benutzer Öfters hier
    Registriert seit
    15.04.2006
    Beiträge
    18
    Ich bin ja ein verspieltes Kind, wenn ich schon dabei bin neue Sachen auszuprobieren, wollt ich den AVR mal in den Schlaf wiegen, aber das will nicht funzen. Kann mir jemand das oben gepostete Programm so ergänzen,
    dass der AVR immer wieder aus dem Schlaf gerissen wird, ein paar Sekunden
    wach bleibt (_delay_ms()... o.ä.) damit man das Ergebniss des Interrupts bewundern kann und dann wieder wegschläft...?

  10. #10
    Neuer Benutzer Öfters hier
    Registriert seit
    15.04.2006
    Beiträge
    18
    Ok, nun eine neue Spielerei, ich wollte den 16Bit Timer als PWM Quelle
    nutzen, und das PWM Verhältniss sinusförmig variieren.

    Das ganze sollte nicht in ner Schleife passieren, sondern mittels eines
    Interrupts, der auf das Output Compare Match reagiert, und den OCR1A Eintrag des Timers Sinusförmig mit der Zeit ändert.

    Schön so weit, nur wenn ich sei(); mache, also die Interrupts aktiviere
    ist plötzlich Tote Hose!!!! Vertraegt sich der PWM nicht mit Interrupts???

Seite 1 von 3 123 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •