Hallo @ all Ich benutze den µC ATMEGA32. Ich habe ein kleines Programm geschrieben, das eine Interruptserviceroutine abarbeiten soll. Jedoch wird der Interrupt schon ausgelöst, obwohl keiner anliegt. Problem: Ich schalte die Powerversorgung an. Der µC initialisiert sich wartet anschließend 3 Sekunden und aktiviert das globale Interruptflag mit dem Befehl "sei". Anschließend soll mit der Abarbeitung des Hauptprogramms begonnen werden. Dies ist jedoch nicht der Fall. Der µC springt nach der Aktivierung des globalen Interruptflags sofort in die Interruptserviceroutine. Dies kann ich erkennen, da die Interruptserviceroutine "Interrupt" auf ein Zweizeihlendisplay schreibt. Nachdem er den Interrupt verarbeit hat springt der µC zurück ins Hauptprogramm. Das Hauptprogramm gibt auf dem Display "Hauptprogramm" aus. Der Interrupt wird nur einmalig ausgeführt. Ich habe meine Interrupts wie folgt konfiguriert: 1. nur der externe INT0 so an sein --> GICR |=0x40; 2. der Interrupt soll nur bei einer fallenden Flanke ausgeführt werden --> MCUCR=0x40; 3.MCUCSR=0x00; --> weiß nicht was MCUCSR macht 4.GIFR=0x40; --> Interruptflag vom externen INT0 setzen --> ich denke das hier der Fehler ist und ein Interrupt ausgelöst wird. Jedoch habe ich diesen Wert schon auf 0x00 gesetzt und der Interrupt wird trotzdem ausgelöst. Ich habe am INT0 Port des µC nachgemessen. Dieser ist kontinuierlich logisch 1. Kann es vielleicht sein das beim Einschalten des System ein Flankenwechsel erzeugt wird, den der µC sich merkt? Anschließend beim aktivieren der Interrups wird dieser dann ausgelöst. Ich hoffe jemand kann mir weiterhelfen, sitze schon 2 Tage an diesem Problem Grüsse Sebastian
Ein geposteter Codeabschnitt sagt mehr als 1000 erklärende Worte!
// External Interrupt 0 service routine interrupt [EXT_INT0] void ext_int0_isr(void) { // go on the first LCD line lcd_gotoxy(0,0); // display the message lcd_clear(); lcd_putsf("INTERRUPT"); delay_ms(3000); } void main(void) { // Declare your local variables here unsigned long int status; status = START; // Input/Output Ports initialization // Port A initialization // Declare your local variables here PORTA=0x00; DDRA=0xFF; // PORTA ist Ausgang // Port B initialization // Func7=Out Func6=In Func5=Out Func4=Out Func3=In Func2=In Func1=Out Func0=Out // State7=0 State6=T State5=0 State4=0 State3=T State2=T State1=0 State0=1 PORTB=0x01; DDRB=0xB3; // Port C initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T PORTC=0x00; DDRC=0x00; // Port D initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T PORTD=0x00; DDRD=0x00; // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: Timer 0 Stopped // Mode: Normal top=FFh // OC0 output: Disconnected TCCR0=0x00; TCNT0=0x00; OCR0=0x00; // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: Timer 1 Stopped // Mode: Normal top=FFFFh // OC1A output: Discon. // OC1B output: Discon. // Noise Canceler: Off // Input Capture on Falling Edge // Timer 1 Overflow Interrupt: Off // Input Capture Interrupt: Off // Compare A Match Interrupt: Off // Compare B Match Interrupt: Off TCCR1A=0x00; TCCR1B=0x00; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // Timer/Counter 2 initialization // Clock source: System Clock // Clock value: Timer 2 Stopped // Mode: Normal top=FFh // OC2 output: Disconnected ASSR=0x00; TCCR2=0x00; TCNT2=0x00; OCR2=0x00; // External Interrupt(s) initialization // INT0: On // INT0 Mode: Falling Edge // INT1: Off // INT2: Off GICR|=0x40; MCUCR=0x02; MCUCSR=0x00; GIFR=0x40; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x00; // Analog Comparator initialization // Analog Comparator: Off // Analog Comparator Input Capture by Timer/Counter 1: Off ACSR=0x80; SFIOR=0x00; PORTB.0 = 1; //FPGA RESET aktivieren // LCD module initialization lcd_init(20); lcd_clear(); delay_ms(2000); PORTB.0 = 0; // FPGA RESET deaktivieren while (1) { // globale Interrupts deaktivieren #asm("cli") if(status == START) { lcd_clear(); lcd_putsf("Hauptprogramm"); //delay_ms(3000); } //globale Interrupts aktivieren #asm("sei") delay_ms(1000); }; }
Sebastian wrote: > Was macht GIFR=0x40; > > Löse ich damit einen Interrupt aus? Nein. Das löscht das Flag, das anzeigt, dass ein Interrupt auf seine Abarbeitung wartet. Mach vor dem sei() noch mal ein GIFR = 0x40; Das ist das Problem mit diesen Wizards. Kein Mensch liest mehr Datenblätter und sieht nach, was die vom Wizard vorgeschlagenen Einstellungen eigentlich bewirken. Hol dir von Atmel das Datenblatt zum Prozessor und lies nach was die einzelnen Flags tatsächlich bewirken anstatt 2 Tage mit einem Code der nicht so funktioniert wie du dir das vorstellst zu verplempern.
Sebastian wrote: > Was macht GIFR=0x40; > > Löse ich damit einen Interrupt aus? Nein, Interrupts kann man nicht per Software auslösen. Damit wird nur das Flag vom INT0 gelöscht. Da Du ziemlich viele und lange Delays drin hast, ist die Wahrscheinlichkeit recht groß, dass nach dem Löschen des Flags dieses wieder gesetzt wird. Und das wiederum führt dann zu einem Aufruf des Handlers, sobald das I-Bit gesetzt wird.
Für mich heist GIFR=0x40; schreibe in Register GIFR den Wert 0x40. Demnach sollte nur das 7.Bit gesetzt sein. Ich habe das Datenblatt durchgelesen dort steht folgendes: When an edge or logic change on the INT0 pin triggers an interrupt regquest, INTF0 becomes set (one). If the I-bit in SREG and the INT0 bit in GICR are set(one), the MCU will jump to the corresponding interrupt vector. The flag is cleared when the interrupt routine is executed. Alternatively, the flag can be cleared by writing a logical one to it. This flag is always cleared when INT0 is configured as a level interrupt. Das verstehe ich nicht ganz. In der ersten Zeile wird geschriben, das der Zustand des Flags 1 ist, wenn ein Interrupt ausgelöst wurde. Unten steht wenn ich das Flag löschen will muss ich eine 1 ins Register schreiben. Kann mir das vielleicht einer genauer erklären
Das ist genau so wie es da steht: Wenn das Flag gesetzt ist, ist es "1", d.h., wenn Du das Flagregister liest, bekommst Du jedes gesetzte Flag als "1" ausgegeben, während nicht gesetzte Flags "0" sind. Um ein Flag zu löschen, muss man eine "1" hineinschreiben, was mit der internen Logik dazu führt, dass das Flag gelöscht wird. Das Schreiben einer "0" hat bei Interrupt-Flags keinen Effekt. Wie oben schon gesagt: Ein Interrupt-Flag kann nur von der dazugehörigen Hardware gesetzt werden. Softwaremäßig kann man es nur löschen. EDIT: ...Und das ganze hat zur Folge, dass man Register, die nur Interrupt-Flags enthalten (wie z.B. GIFR) nicht mit Read-Modify-Write-Operationen beschreibt (z.B. "|="), sondern direkt mit einer Zuweisung. Ein Read-Modify-Write-Zugriff hätte zur Folge, dass alle gesetzten Flags gelöscht werden, da sie ja beim Einlesen "1" sind und ebenso als "1" zurückgeschrieben werden. Da das Schreiben einer "0" aber eh keinen Effekt hat, kann man auch direkt "=" schreiben.
Johannes M. wrote: > Nein, Interrupts kann man nicht per Software auslösen. Damit wird nur Man kann (wenn ich mich recht erinnere) einen PINCHANGE Interupt beim AVR per Software auslösen...
Läubi Mail@laeubi.de wrote: > Johannes M. wrote: >> Nein, Interrupts kann man nicht per Software auslösen. Damit wird nur > > Man kann (wenn ich mich recht erinnere) einen PINCHANGE Interupt beim > AVR per Software auslösen... Man kann auch einen "normalen" externen Interrupt aus dem Programm heraus auslösen, wenn man den betreffenden Portpin als Ausgang konfiguriert und über das PORTx-Register eine entsprechende Flanke erzeugt. Allerdings wird auch dabei das Flag von der Hardware gesetzt und nicht direkt durch das Programm! Und meine Aussage oben bezog sich auf die Frage, ob durch "setzen" des Bits im GIFR ein Interrupt ausgelöst wird. Und das ist nicht der Fall.
Komisch ist es aber trotzdem. Wenn ein Interrupt ausgelöst wird, dann wird das Flag gesetzt. Wenn ich jedoch eine 1 zuweise wird das Flag gelöscht. Dann werde ich mir einfach merken, dass ich das Interruptflag per GIFR=0x40; lösche. Noch mal vielen Dank an alle
Das ist eben durch die interne Logik (oder Unlogik?) bei den AVR-Controllern so geregelt und gilt eben nur für Interrupt-Flags.
Kann das sein, wenn der INT0 aktiviert ist, jedoch das global Interruptflag deaktiviert ist, das trotzdem Interrupts erkannt, jedoch nicht sofort ausgeführt werden. Erst wenn das global Interruptflag gesetzt wird, wird der gespeichert Interrupt ausgeführt.
Alle Freigaben von Interrupts beziehen sich NUR auf die BEARBEITUNG der Ereignisse. Die Flags werden IMMER gesetzt, wenn das betreffende Hardware-Ereignis eintritt, auch dann, wenn die Bearbeitung des Interrupts (global durch das I-Bit im SREG und/oder lokal durch das entsprechende Interrupt-Enable-Bit) nicht freigegeben ist. Deshalb ist es auch in vielen Fällen sinnvoll (besonders bei externen Interrupts), vor der Freigabe das betreffende Flag zu löschen, was der schlaue Wizard von CodeVision durch eben das "GIFR = 0x40;" macht. Ist das Flag bei der Freigabe bereits gesetzt, wird es natürlich sofort bearbeitet (vorausgesetzt, es stehen keine weiteren Interrupts mit niedrigeren Vektoradressen und dementsprechend höherer Verarbeitungs-"Priorität" an). Du solltest Dir aber wirklich mal die entsprechenden Abschnitte im Tutorial durchlesen. Es macht keinen Sinn, alles, was irgendwo schon steht, hundertmal neu zu schreiben...
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.