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.
Kommt drauf an was für ein PIC es ist. Die ganz kleinen haben nur Stack für 2 UP bzw. INT Ebenen, vielleicht liegt es daran.
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
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.