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