PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PIC16F84A Interruptproblem - oder doch sleep-Problem?



M!ni M0nk3y
17.09.2013, 18:34
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!




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

PICture
17.09.2013, 18:52
Hallo!

Ich denke, dass dein µC im Schlaf in endloser Schleife "für immer" bleibt. ;)

M!ni M0nk3y
17.09.2013, 19:04
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?

PICture
17.09.2013, 19:57
Wo in deinem unkomplettem Code sind die UP1 und UP2 und was sollten sie machen ?

M!ni M0nk3y
17.09.2013, 20:36
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.

PICture
17.09.2013, 20:42
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/threads/16678-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. ;)

M!ni M0nk3y
17.09.2013, 20:45
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?

witkatz
18.09.2013, 15:05
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.

M!ni M0nk3y
18.09.2013, 15:54
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 :-/

Klebwax
18.09.2013, 16:06
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

witkatz
18.09.2013, 22:08
...könnte es sein, dass noch die ganze Zeit dein Programmer an der Schaltung hängt und die Potentiale an RB6/RB7 runterzieht? Mein Pickit 2 macht das nämlich gerne...