Hallo,
ich möchte gerade ein UP von einem Interrupt aus starten.
Irgendwo klemmt es da.
Also das UP funktioniert wenn ich es normal per CALL aufrufe.
Der Interrupt funktioniet auch, wenn ich dort NUR einen PIN vom PIC ein
und ausschalte. Im Interrupt werden auch die Register gesichert.
Gebe ich nun in der Interrupt-Routine CALL UP ein, dann geht nichts
mehr.
Das UP liegt am Ende vom Programm aber innerhalb von dem selben BLOCK.
Irgend etwas habe ich da nicht beachtet.
Ich denke mal du meinst mit UP=Unterprogramm?
Das geht beim PIC nicht, hat auch nichts mit der Interrupttiefe (das
wären z.b. 1 beim 16F, 2 beim 18F) oder der Stacktiefe (8 beim 16F, 18F
grad ned im Kopp) zu tun. Geht einfach Prinzipbedingt nicht aus dem
Interrupt heraus calls auszuführen. Hat mich auch schon oft gestört, is
aber leider so.
Bei den PIC18 kann ein HIGH PRIORITY interrupt eine interrupt routine
unterbrechen. Im CCS Compiler Handbuch steht:
"The keywords HIGH and FAST may be used with the PCH compiler to mark an
interrupt as high priority. A high-priority interrupt can interrupt
another interrupt handler. An interrupt marked FAST is performed without
saving or restoring any registers. You should do as little as possible
and save any registers that need to be saved on your own. Interrupts
marked HIGH can be used normally. See #DEVICE for information on
building with high-priority interrupts.
A summary of the different kinds of PIC18 interrupts:
#INT_xxxx
Normal (low priority) interrupt. Compiler saves/restores key registers.
This interrupt will not interrupt any interrupt in progress.
#INT_xxxx FAST
High priority interrupt. Compiler DOES NOT save/restore key registers.
This interrupt will interrupt any normal interrupt in progress.
Only one is allowed in a program.
#INT_xxxx HIGH
High priority interrupt. Compiler saves/restores key registers.
This interrupt will interrupt any normal interrupt in progress.
#INT_GLOBAL
Compiler generates no interrupt code. User function is located
at address 8 for user interrupt handling."
Ich selber habe das noch nicht ausprobiert. Den Ausfuehrungen nach
muesste es funktionieren solange die SFRs richtig konfiguriert sind.
Hoffe dass ein bischen hilft,
Gerhard
@ Jens Plappert,
das musst du mir genauer erklären.
Also ich programmiere seit Jahren meine Interrupts als Unterprogramm das
ich mit einem CALL an der Interrupt-Vectoradresse aufrufe (ggf. noch
Kontextsavingmaßnahmen davor). Hatte nie Probleme damit.
Ich denke da eher an ein Stack-Problem.
Jens Plappert wrote:
>Das geht beim PIC nicht, hat auch nichts mit der Interrupttiefe (das>wären z.b. 1 beim 16F, 2 beim 18F) oder der Stacktiefe (8 beim 16F, 18F>grad ned im Kopp) zu tun. Geht einfach Prinzipbedingt nicht aus dem>Interrupt heraus calls auszuführen. Hat mich auch schon oft gestört, is>aber leider so.
Warum sollte das nicht gehen? Das ist gängige Praxis bei meinen
Programmen.
@Mario:
Vieleicht solltest Du mal ein bisschen Code posten!
Hallo Mario,
wenn Du mit call die Inteterrupt-Service-Routine (ISR) aufrufst, springt
er am Ende nach dem return *1) an die Adresse (+ 1 Adresse) zurück, von
der sie gestartet wurde: also in Deinem Fall wieder direkt hinter den
Interrupt-Vektor. Die Rücksprungadresse wird auf den Stack gelegt.
Gebe statt call den Befehl goto, bzw. bra zum Aufruf der ISR ein. Am
Ende der ISR steht dann retfie. Damit landest Du dann beim Rücksprung
(mit retfie) mitten im Programm eine Adresse hinter der Adresse, an der
der Interrupt ausgelöst wurde. Nach dieser Aktion ist die Welt also
wieder in Ordnung.
*1) Der Unterprogrammaufruf mittels call wird grundsätzlich mit return
beendet, da call die Rücksprungadresse auf den Stack legt und er wieder
mittels return bereinigt werden muß. Beim Interrupt-Aufruf wird bereits
die Rücksprungadresse auf den Stack gelegt. Retfie korrigiert ihn
wieder, ein zusätzliches call würde nur eine weitere Adresse auf den
Stack legen, ohne daß er jemals wieder korrigiert werden würde.
Viel Spaß dabei,
urgs
Hallo.
Vielen Dank für die vielen Antworten.
Jetzt komme ich leider nicht mehr mit.
Leider fehlt mein 2. Posting von gestern. Hatte leider auch
Internetprobleme.
Es geht um den PIC 16F876A
Die Anzahl der UP-Aufrufe (TIEFE) im Hauptprogramm liegt bei CALL bei 2
oder 3.
Ich bin jetzt nicht sicher, aber 7 sind wohl noch möglich.
Mal angenommen es sind 3, dann würde doch ein weiterer Wert
(Rücksprungandresse) im Stack gespeichert werden, wenn der Interrupt
ausgeführt wird.
Dann folgt im Interrupt mein CALL. Macht 5
Das UP selber ruft mehrmalig ein UP per Call auf, die aber alle mit
Return wieder in das UP zurückspringen. Macht eigentlich 6 Adressen im
Stack. Oder nicht?
Call muss aber grundsätzlich funktionieren aus der Interruptroutine,
denn da habe ich schon einige Demoprogramme wo es geht.
Hier mal der Code von der Interruptroutine, der Rest stark gekürzt:
org 4
intvec
movwf w_copy ; w retten
swapf STATUS, w ; STATUS retten
clrf STATUS
movwf s_copy ;
movf PCLATH, W
movwf p_copy
clrf PCLATH ; Bank 0
; Intrupt servic routine
BSF PORTC,5 ;per Oszi ist der Impuls sichtbar!
nop
BCF PORTC,5
call Tempmessen
call TempAusgabe ; anzeigen am LCD
Int_end
movf p_copy, W
movwf PCLATH
swapf s_copy, w ; STATUS zurück
movwf STATUS
swapf w_copy, f ; w zurück mit flags
swapf w_copy, w
bcf INTCON, T0IF ; Interupt-Flag löschen
retfie
Tempmessen x
Call A ;Rücksprung per Return
Call B ;Rücksprung per Return
Return
OHHHHHHHH
Jetzt wo ich das so sehe, das kann nicht gehen.
Das UP wird auch im Hauptprogramm benutzt.
Da stimmen ja keine Variablen mehr.
Und da wollte ich es mir leichter machen.
Also muss ich in diesem UP den Interrupt abschalten, sonnst kann das ja
nicht gehen.
Sorry für meine Blödheit ;o)
@urgs
>*1) Der Unterprogrammaufruf mittels call wird grundsätzlich mit return>beendet, da call die Rücksprungadresse auf den Stack legt und er wieder>mittels return bereinigt werden muß. Beim Interrupt-Aufruf wird bereits>die Rücksprungadresse auf den Stack gelegt. Retfie korrigiert ihn>wieder, ein zusätzliches call würde nur eine weitere Adresse auf den>Stack legen, ohne daß er jemals wieder korrigiert werden würde.
Das ist so nicht richtig. Selbstverständlich kann in einer ISR ein CALL
auftauchen, ohne das da irgendwetwas "durcheinander kommt". Selbst in
den Unterroutine können weitere CALLs vorhanden sein. Es muss nur wie
immer beachtet werden: Jedes CALL muss mit einem RETURN enden. Der
Unterschied zu RETFIE ist, das bei RETFIE der GIE wieder enabled wird.
Dieses ist z. B. gar kein Problem:
ISR:
...
...
CALL abc
...
...
RETFIE
abc:
...
...
...
RETURN
Wie gesagt: CALL->RETURN. Und die Stacktiefe muss beachtet werden, wobei
besonders zu beachten ist, das beim Auftreffen eines Interrupts schon
Adressen auf dem Stack liegen könnten.
Leute ihr habt mich da aber n bissl falsch verstanden. Dass man die ISR
per Call aufrufen kann ist ja klar. Ich wollte nur darauf hinweisen dass
man aus der ISR heraus keine Calls ausführen sollte...
Genau das haben doch nun aber mehrere Leute hier gesagt ist eben gerade
kein Problem. Warum solltest du in einer ISR kein CALL ausführen dürfen?
Ist doch alles kein Problem solange du beachtest das der Stack nicht
überläuft und du den CALL mit RETURN beendest. Der Stack hat Platz für 8
Aufrufe. Also
ISR
CALL
CALL
CALL
CALL
CALL
CALL
:
RETURN
RETURN
RETURN
RETURN
RETURN
RETURN
RETFIE
sollte kein Problem sein (vorausgesetzt vor dem Aufruf der ISR wurde
nicht schon ein CALL ausgeführt ** ups ** )
Sven
ich schlage mich auch gerade mit den interrupts rum und lese mich gerade
durch die Interrupt postings bezüglich PIC...
es müsste doch auch so gehen:
Call
| ISR
| | Call
| | | Call
| | | |
| | | |
| | | return
| | return
| retfie
return
Um nicht noch ein Posting dazu zu öffnen,
welche Register muss ich retten, zurücksetzen, oder umschreiben, wenn
ich mich gerade in der ISR befinde?
Muss man den GIE zurücksetzen, oder macht der PIC das automatisch nach
dem retfie?
ich habe im moment den fall, dass ich mit einem Signal mit pull down
(100k evtl zu viel?)am RA2 eine Intrrupt starten möchte und so lange in
der Routien bleiben möchte, biss das signal wieder auf 0 ist.
Hier mein Code:
org 0x0
goto Start
org 0x04
timer_0
bsf PORTB,7
BTFSC PORTA,2
GOTO timer_0
bcf OPTION_REG,6
bcf INTCON,INTF
bcf PORTB,7
retfie
@dertom83
Du verschweigst wie so viele, welchen PIC du einsetzt. :(
(man beachte den zweiten Post)
Was man schon mal aus dem Stand sagen kann:
>ich schlage mich auch gerade mit den interrupts rum und lese mich gerade>durch die Interrupt postings bezüglich PIC...
Am besten lies auch gleich noch das Datenblatt des PIC, den du
verwendest. Was du dir aus den Posts zusammengereimt hast, ist so noch
nicht praktikabel.
>welche Register muss ich retten, zurücksetzen, oder umschreiben, wenn>ich mich gerade in der ISR befinde?
Genau genommen gar keine, als sinnvoll haben sich aber das
zwischenspeichern des Arbeitsregisters w, des Statusregisters und je
nach PIC des BSR oder PCLATH erwiesen. Das hängt davon ab, ob diese
Register in der ISR manipuliert werden oder nicht.
>Muss man den GIE zurücksetzen, oder macht der PIC das automatisch nach>dem retfie?
Probiers aus, das kannst du sogar ohne PIC in MPSIM testen.
>ich habe im moment den fall, dass ich mit einem Signal mit pull down>(100k evtl zu viel?)am RA2 eine Intrrupt starten möchte und so lange in>der Routien bleiben möchte, biss das signal wieder auf 0 ist.
Nochmal, schau ins Datenblatt. Was soll denn heissen: am RA2 ein
Interrupt auslösen???
So wie ich deinen code (dem übrigens das Hauptprogramm fehlt)
interpretiere, fragst du PORTA, 2 in der Hauptschleife ab und setzt dann
per Hand das INTF. Das macht keinen Sinn, es sei dann, du wolltest so
das Verhalten von GIE überwachen. Dann hättest du aber nicht danach
gefragt, sondern wüsstest es jetzt...
Was dein code macht, kann man problemlos ohne Interrupt lösen.
Gruss,
Edson
okok, ich habe ein 16F690
habe mir das datenblatt schon mehrfach durchgelesen, da steht aber nicht
genau drin was ich zu tun habe...
Wenn ich da lesen:
"When an Interrupt is serviced:
The GIE is cleard
the returnadress is pushed onto the stack
The PC is loaded with 0004"
Sagt mir das zwar was passiert, wenn ich den Interrupt auslöse, aber
nicht was ich während der ISR machen muss um diesen evtl erneut auslösen
zu können.
Klar, hier steht noch, dass ich mit INTE diesen Interrupt ab- und
einschalten kann. Und dass INTF gesetzt wird wenn ich diesen so
genannten "RA2/INT Interrupt" auslöse und von hand zurückgesetzt werden
muss.
in der ISR muss also nur stehen?:
org 0x04
ISR BSF INTF
BSF LED
BCF LED
RETFIE
Mir ist klar, dass ich das ganze auch ohne intererupt lösen kann... hab
ich schon.... aber ich denke, so ist es am einfachsten in die Interrupts
einzusteigen.
Gruß
Thomas
>habe mir das datenblatt schon mehrfach durchgelesen, da steht aber nicht>genau drin was ich zu tun habe...
Prinzipiell steht im Datenblatt, was und wie der PIC tut. Um das alles
zu verstehen, brauchts am Anfang Geduld und Spucke.
>in der ISR muss also nur stehen?:
Du schreibst selber,
>dass INTF gesetzt wird
also warum setzt du dieses Bit in der ISR nochmal? Das anschliessende
toggeln von LED bringt dir ausser einem kurzen Impuls mit der Dauer
eines Maschinenzyklus nichts ein.
>Mir ist klar, dass ich das ganze auch ohne intererupt lösen kann... hab>ich schon....
Versteh mich jetzt nicht falsch, aber das würde ich gerne sehen. Aus
deinen bisherigen Codefragmenten geht nicht gerade hervor, das du es
kannst.
>aber ich denke, so ist es am einfachsten in die Interrupts>einzusteigen.
Kaum Gedacht, schon falsch gemacht ;)
Aber im Ernst: Ein Interrupt oder das Setzten des zugehörigen
Interrupt-Flags, das den Sprung in die ISR bewirkt, werden durch ein
bestimmtes (und zu bestimmendes) Ereignis ausgelöst. In deinem Fall eine
Flanke am Eingang RA2. Das Ereignis führt zum Sprung in die ISR, wenn
das zugehörige Enable-Bit gesetzt ist. GIE ist das globale Enable-Bit
für alle Interrupts des PIC. Es muss gesetzt sein, wenn Interrupts
ausgelöst werden sollen. In der ISR brauchst du dich nicht darum zu
kümmern, wohl aber um das Interrupt-Flag des eingetretenen Ereignisses.
Dein Code aus dem vorigen Post beinhaltet demnach einen Kardinalfehler,
den du jetzt auch erkennen solltest.
Alles klar jetzt?
Gruss,
Edson