PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Interrupts per Programmcode auslösen?



Mitch64
14.01.2009, 22:21
Hallo zusammen,

ich habe eine Grundsätzliche Frage. Ist es möglich per Programm ein Interrupt-Flag zu setzen, so dass ein Interrupt ausgelöst wird und somit die ISR aufgerufen wird?

Kleines Beispiel:


on oc2 ISR_OC2
enable oc2

enable interrupts

do
tifr.ocf2 = 1
Wait 1
loop

ISR_OC2:
nop
Return

Funktioniert sowas? Kann man das mit jedem Interrupt machen, auch mit INT0 und INT1, oder gibts da irgendwelche Einschränkungen?

Hintergrund ist einen 2. Interrupt bedingt inerhalb einer gerade laufenden Interrupt-Routine zu iniziieren. Der Programmcode soll jedoch erst nach beenden der ersten ISR ausgelöst werden.

Gruß Mitch.

Besserwessi
14.01.2009, 22:34
Mit den normalen Interrupt flags kann man das so nicht machen. Im Datenlabtt steht das man gerade eine 1 reinschreiben muß um das Flag zu löschen.

Einige Interrupts wie die externen Interrupts kann aber künstlich auslösen indem man entweder die Bedingung für den Interrupt ändert, so das es paßt, oder indem man den Pin als Ausgang definiert und dann das passende ausgibt. Die externen Interrupts auf low werden aber nicht gepuffert. Dier werden also nur dann ausgefürt wenn der Pin nach der ISR noch auf low ist.

Alternativ könnte man doch gleich nach der 1. ISR in die 2 te ISR weiterspringen.

Besserwessi
14.01.2009, 22:35
Mit den normalen Interrupt flags kann man das so nicht machen. Im Datenlabtt steht das man gerade eine 1 reinschreiben muß um das Flag zu löschen.

Einige Interrupts wie die externen Interrupts kann aber künstlich auslösen indem man entweder die Bedingung für den Interrupt ändert, so das es paßt, oder indem man den Pin als Ausgang definiert und dann das passende ausgibt. Die externen Interrupts auf low werden aber nicht gepuffert. Dier werden also nur dann ausgefürt wenn der Pin nach der ISR noch auf low ist.

Alternativ könnte man doch gleich nach der 1. ISR in die 2 te ISR weiterspringen.

Mitch64
14.01.2009, 22:45
Wenn ich ein Flag (ext. Interrupt) durch schreiben einer 1 lösche, was passiert dann, wenn ich eine 0 rein schreibe?

Es würde mir schon reichen, wenn das mit den internen Interrupts geht. Im Simulator funktioniert das jedenfalls nicht.

Michael
14.01.2009, 23:05
Hallo Mitch64,

Probier doch mal Enable (Disable) Interrupts (oc2)?

Gruß, Michael

Mitch64
14.01.2009, 23:12
Ich will nicht im Mask-Register rumspielen.
Ich kenne Enable und Disable.

Das war nicht die Frage.

Michael
14.01.2009, 23:16
Hallo Mitch64,

wird der globale Interrupt beim Einsprung nicht automatisch "disabelt" und bei Return wieder "enabled"?

Gruß, Michael

Besserwessi
15.01.2009, 18:41
Die interrupt flag Register kann man nicht so direkt per software setzen. Die kann man über das Register nur löschen.

Der externe Interrupt hängt vom zusatd des Pins ab. Wieso der sich ändert ist egal. Es zählt also auch wenn der Pin als Ausgang definiert ist und man den Ausgangewert ändert. Wenn man auch noch echte externe Interrupts zulassen will, müßte man den über einen Widertand anschließen.

PicNick
15.01.2009, 18:51
Was ich mich frage: Du könntest doch die Glob-Interrrupts disablen und dann die ISR-Routine direkt anspringen. (Gosub).
Welchen speziellen Effekt, der darüber hinausgeht, willst du denn erreichen ?

Mitch64
15.01.2009, 19:17
Also,
ich wollte nur wissen, kann ich einen Interrupt (z.B. OC2) per Software im Programmcode auslösen oder nicht. Ich habe gelesen, das dies bei den internen Interrupts geht. Mit den Externen Interrupts muß ich den pin eben als Ausgang schalten und dann das Signal entsprechend per Software schalten. Das ist es was ich wissen wollte. Danke schon mal für diese Infos. Das hilft mir schon mal weiter.

Der Grund warum ich denn einen Interrupt per Programm auslösen will ist, weil ich in einer ziemlich zeitkritischen Interruptroutine keinen zu langen Code schreiben kann. Ich kann aber dafür sorgen, dass Quasi Synchron der andere Programmteil gestartet wird. Sozusagen direkt danach. Der Gag ist aber, dass ich den 2. Programmteil nicht immer ausführen muß, sondern nur wenn bestimmte Bedingungen gegeben sind.

Um dies zu erreichen dachte ich an einen internen Interrupt, den ich einfach nur iniziiere, wenn es sein muß.

Übrigens:
Mit Gosub kann ich keine ISR-Routine aufrufen, da diese mit IRET abgeschlossen sein muß. Der Compiler macht das halt so, wenn eine Unterroutine als Interrupt-Sprungziel angegeben ist. Das würde zum Absturz des Controllers führen.

PicNick
15.01.2009, 19:27
Der Unterschied zwischen RET und RETI ist nur, das letzerer auch das Glob-Int-Enable Flag wieder setzt. Da stürzt nix ab, wie auch.
Wenn das berücksichtigt wird, und das wäre es ja auch in diesem Fall, kann dir das nur recht sein.


EDIT: Vielleicht meinst du die alten Intels. die haben tatsächlich das statusregisrter zusätzlich zurückgeladen bei IRET, glaub ich mich zu erinnern

Besserwessi
15.01.2009, 20:12
In assembler get das in eine andere ISR zu springen. Man muß aber nur aufpassen, das die Register auf die gleiche Wiese wieder hergestellt werden. Wegen der Register auf dem Stack geht ein gosub nicht, höchstens ein goto. Soweit ich weiss werden von BASCOM immer alle Register gerettet da gibts also nur eine version. Mit GCC hätte man da Probleme.

Gerade wenn es zeitkritisch ist, ist der umweg über den extra Interrupt unpraktisch, denn in Basic braucht es recht lange bis alle Register rerettet und wieder hergestellt sind. Oft dauert das länger als die eigentliche ISR. Da wird es besser sein den Code einfach 2 mal da zu haben, wenn der Flash nicht zu knapp ist.