Hallo!
Ich denke, dass dein µC im Schlaf in endloser Schleife "für immer" bleibt.![]()
Hallo,
ich habe ein Problem mit einer Interruptroutine.
Diese wird nur einmalig ausgeführt (bei RB7 = low) und dann nie wieder.
Der PIC soll eigentlich immer schlafen, es sei denn RB6 oder RB7 wechseln von high zu low - dann soll er eine Routine abarbeiten und wieder einschlafen
Beim ersten Interrupt durch RB7 springt der PIC in das richtige Unterprogramm (im Bsp unten "UP1"), arbeitet es ab und stellt danach komplett seine Arbeit ein. Dann kann ich an RB6 / 7 soviel Pegelwechsel vornehmen wie ich will, es passiert nichts mehr.
Ich habe mal den Quelltext angehängt: Mache ich etwas falsch mit dem Setzen / Rücksetzen der Interruptbits?
Oder habe ich ein Problem mit dem "Einschlafen"?
Danke schonmal für alle Tipps im Voraus!
Code:org 0x0000 ;Startadresse des Prozessors goto main ;springe in das Hauptprogramm ;********************************************************************** ;-----------Interrupt-Service-Routine--------------- org 0x4 ; Startadresse ISR ;Interruptroutine bcf INTCON,GIE bcf INTCON,RBIE ; PortB Interrupt verbieten bcf INTCON,RBIF movwf w_copy ; Arbeitsregister retten swapf STATUS,w ; Status retten movfw s_copy ; statusregister retten btfss PORTB,7 ;Wenn Eingang AB=0 überspringe nächsten Befehl call UP1 ;Rufe UP AB_Setzen auf btfss PORTB.6 ;Wenn Eingang AB=0 überspringe nächsten Befehl call UP2 ;Rufe UP AB_Setzen auf swapf s_copy,w ; STATUS zurückholen movwf STATUS ; Status aus dem Arbeitsregister in die Speicherzelle schreiben swapf w_copy,f ; w zurück mit flags swapf w_copy,w bsf INTCON, RBIE ; RBIF kann wecken bcf INTCON, RBIF bsf INTCON, GIE retfie ; ISR verlassen ; Hauptprogramm main: ;Initialisierung clrf PORTA ; PortA löschen clrf PORTB ; PortB löschen bsf STATUS,RP0 ; Umschalten auf Bank1 movlw B'00011111' ; movwf TRISA ; RA0-RA4 als Eingang definieren movlw B'11000111' ; movwf TRISB ; RB0-2=Eingang; RB3-5= Ausgang; RB6&7=Eingang bcf OPTION_REG, 7 bcf STATUS,RP0 ; Umschalteten auf Bank0 clrf INTCON ; GIE aus bsf INTCON, RBIE ; RBIF kann wecken bcf INTCON, RBIF bsf INTCON, GIE sleeploop sleep nop goto sleeploop
Hallo!
Ich denke, dass dein µC im Schlaf in endloser Schleife "für immer" bleibt.![]()
MfG (Mit feinem Grübeln) Wir unterstützen dich bei deinen Projekten, aber wir entwickeln sie nicht für dich. (radbruch) "Irgendwas" geht "irgendwie" immer...(Rabenauge) Machs - und berichte.(oberallgeier) Man weißt wie, aber nie warum. Gut zu wissen, was man nicht weiß. Zuerst messen, danach fragen. Was heute geht, wurde gestern gebastelt. http://www.youtube.com/watch?v=qOAnVO3y2u8 Danke!
Nein, dadurch dass der PortB Interrupt aktiviert ist (INTCON, RBIE und INTCON, GIE) sind ja Interrupts auf Pegelwechsel an PortB4-7 erlaubt.
Beim ersten Durchlauf funktioniert es ja: Der PIC schläft zunächst ein und auf Pegelwechsel von high zu low startet die ISR und das UP wird abgearbeitet.
Das Interruptflag was gesetzt wurde wird zurück gesetzt und der RB Interrupt Enable wird wieder aktiviert.
Somit sind die Interrupts wieder erlaubt und der PIC geht schlafen.
Ein Interrupt durch Pegelwechsel an RB4-7 soll den PIC16F84A laut Datenblatt wecken (macht er ja im Prinzip auch beim 1. Durchlauf).
Wenn ich das in MPLAB simuliere klappt alles wunderbar, aber in der Schaltung funktioniert es komischerweise nicht.
Am Unterprogramm kanns nicht liegen, das funktioniert ohne sleep und ohne Interruptroutine.
Sonst noch jemand ne Idee?
Wo in deinem unkomplettem Code sind die UP1 und UP2 und was sollten sie machen ?
MfG (Mit feinem Grübeln) Wir unterstützen dich bei deinen Projekten, aber wir entwickeln sie nicht für dich. (radbruch) "Irgendwas" geht "irgendwie" immer...(Rabenauge) Machs - und berichte.(oberallgeier) Man weißt wie, aber nie warum. Gut zu wissen, was man nicht weiß. Zuerst messen, danach fragen. Was heute geht, wurde gestern gebastelt. http://www.youtube.com/watch?v=qOAnVO3y2u8 Danke!
Habe ich der Übersichtlichkeit halber rausgelassen, da es nur verwirrt und dieser Programmteil ja (einmalig oder ohne Interrupt) funktioniert.
UP1 und UP2 sind Unterprogramme die selbst auch nochmal ein Unterprogramm aufrufen, aber das Stack müsste ja groß genug sein für 2 returns + das ein retfie.
Oder gibt es Probleme, wenn dir ISR zu lang wird?
Im Prinzip schalten die UPs nur je einen Ausgang für eine bestimmte Zeit die über ein Bitmuster an PortA definiert wird.
Wird jeweils der andere Eingang auf low gezogen, wird diese Zeitschleife direkt übersprungen und zur ISR zurückgekehrt um den Ablauf zu unterbrechen.
- - - Aktualisiert - - -
bsf INTCON, RBIE steht aber auch am Ende der ISR, somit sind beide Enable-Bits nach dem Beenden der ISR eingeschaltet.
Habe das Problem gelöst, verstehen tu ich es aber nicht.
Habe das label "sleeploop" nun direkt unter main geschrieben.
Nach der ISR führt der PIC beim "Nop"-Befehl fort, springt dann wieder zur Portinitialisierung inkl. Interrupt-Einstellung und siehe da, es funktioniert.
Es kann aber doch nicht sein, dass ich die komplette Init (der Ports) nach jeder ISR neu machen muss...
Zumal der Simulation in MPLAB mir ja gezeigt hat, dass nach dem verlassen der ISR die Interrupt Enable Bits richtig sind.
Gratulation !
Ich muss ehrlich zugeben, dass ich leider auch nicht alles verstanden habe, was doch gut endete.
Einige Beispiele sind in: https://www.roboternetz.de/community...678-PIC-Fallen . Dort findet man meine Empfehlung:
"Beim Schreiben eines Programms für reale Hardware nie ein Symulator benutzen !"
In den Thread gehört deine "Falle", falls keine Erklärung gefunden wird.![]()
Geändert von PICture (18.09.2013 um 07:20 Uhr)
MfG (Mit feinem Grübeln) Wir unterstützen dich bei deinen Projekten, aber wir entwickeln sie nicht für dich. (radbruch) "Irgendwas" geht "irgendwie" immer...(Rabenauge) Machs - und berichte.(oberallgeier) Man weißt wie, aber nie warum. Gut zu wissen, was man nicht weiß. Zuerst messen, danach fragen. Was heute geht, wurde gestern gebastelt. http://www.youtube.com/watch?v=qOAnVO3y2u8 Danke!
Ich habe den "Fehler" gefunden.
Es funktioniert auch mit oben stehendem Code, wenn ich am Ende der ISR Bit 7 des OPTION-Registers zurücksetze (PortB Pullups enabled).
Dieses Bit wird zwar nie gesetzt (zumindest sagt das die Watch in MPLAB und ich wüsste auch nicht wodruch), aber durch diese Änderungen funktioniert es!
Verstehen tu ich es allerdings nicht
Vorallem weil die benutzten Ports alle auf definiertem Pegel liegen - außer der Unbenutze RB5, der aber auch als Ausgang konfiguriert wurde.
Manche auch "hart" auf 5V ohne Widerstand - ist das vielleicht ein Problem?
Aber ohne diese internen Pullups funktioniert nichts...
Hat irgendjemand eine Erklärung für das Verhalten?
Geändert von M!ni M0nk3y (17.09.2013 um 21:03 Uhr)
Die PortB Pullups sind nach Power-On Reset disabled, das OPTION_REG bekommt den Wert b'11111111'
Wenn die High-Low Flanke ohne die internen Pull-ups nicht funktioniert, dann würde ich aus dem Bauch heraus ganz naiv vermuten, dass die RB6 und RB7 in der Luft hängen oder die externen Pull-Up Widerstände fälschlicherweise auf Masse gezogen sind.
Neín, RB6/7 sind zu 100% über einen 10k auf Vdd geschaltet!
Das Option Reg wird ja anfangs einmalig auf 01111111 gesetzt.
Danach wird es nie wieder angefasst und die Interrupt funktionieren nur, wenn ich nochmals 01111111 reinschreibe. Alles sehr merkwürdig.
Außerdem habe ich noch ein Problem:
ich schalte mit RB3/4 Trainsistoren durch, die ein Relais schalten (Masse).
Mit sind immer wieder PICs kaputt gegangen.
Ich habe im ersten Versuch die Freilaufdioden vergessen, aber auch mit denen sind mir schon 2 PICs gestorben.
Ich weiß nicht woran das liegen könnte.
RB5 ist unbenutzt und auf Ausgang beschaltet.
PortA + RB0-3 sind direkt hart auf Vdd oder Vss gelegt, wordurch die Zeit bestimmt wird, wie lange die Relais geschaltet werden.
Ich weiß nicht, was die PICs zerstört :-/
Schön daß es jetzt geht.
Obwohl mein letzter Kontakt zum PIC16F84 und zum PIC-Assembler schon eine Weile zurück liegt, hab ich aber einen anderen Schmerz mit dem Code. Am Anfang des Interrupthandlers disableds du sowohl die Interrupte global als auch den von PortB. Das ist einerseits überflüssig, als auch eher schädlich. Schau mal nach, ob ein bcf die Flags beinflußt. Das würde nämlich das Retten des Statusregisters danach beeinflussen. Das einzige, was zu tun ist, ist das RBIF irgendwann vor dem retfie zurückzusetzen. Das Zweite, problematischere ist, daß du die Interrupte im Interrupthandler wieder enablest, das kann dazu füheren, das ein Interrupt im Interrupt ausgeführt wird. Und das solange, bist der (recht kleine) Stack verbraucht ist. Die Interruptenable sollten nur in der main() angefaßt werden. Der Prozessor sperrt weitere Interrupte automatisch im Interupthandler und enabled sie automatisch nach dem retfie wieder.
MfG Klebwax
Strom fließt auch durch krumme Drähte !
Lesezeichen