Forum: Mikrocontroller und Digitale Elektronik PIC16F886 Interupt on Change RB7 läuft nicht


von Thomas B. (dertom83)


Lesenswert?

Ich hatte vor einiger Zeit schon einmal einen Beitrag gespostet, leider 
konnte mir nicht geholfen werden... jetzt steh ich vor dem selben 
Problem:

Ich habe ein PIC16F886

und möchte über den Pin RB7 ein Interupt auslösen.
Ich komme aber nicht ins die Routine.

könnt ihr mir weiter helfen?

So sieht meine ISR aus:
org     0x04
InterruptServiceVector
        movwf   W_save
        swapf   STATUS,W
        bcf     STATUS, RP0
        movwf   Status_save

    MOVFW  PORTC
    XORLW  B'00000001'
    MOVWF  PORTC

  MOVFW  PORTB
Intende_

    BCF    INTCON,RBIF
     bcf     INTCON, T0IF
    swapf   Status_save, w
        movwf   STATUS
        swapf   W_save,f
        swapf   W_save,w

        retfie


Und das ist meine Konfiguration:
#include <p16F886.inc>
#define CONFIGURATION1 _INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & 
_MCLRE_ON & _CP_OFF
#define CONFIGURATION2 _BOR_OFF & _IESO_OFF & _FCMEN_OFF & _LVP_OFF & 
_DEBUG_OFF
        __CONFIG _CONFIG1, CONFIGURATION1 & CONFIGURATION2
Init
  BANKSEL    TRISB
  movlw    b'10000000'
  movwf    TRISB
  BANKSEL    TRISC
  movlw    b'00000000'
  movwf    TRISC

        bsf    STATUS, RP0
        bsf    OPTION_REG, INTEDG ; 0-1-Flanke an RB0
        bcf    STATUS, RP0

        bsf    INTCON, INTE
        bsf     INTCON, GIE
        bsf  IOCB,7
  BANKSEL    0
Start_

  GOTO  Start_
END

Vielen dank schonmal!

Gruß
Thomas

von TK (Gast)


Lesenswert?

Hallo Thomas,

ich kenn jetzt speziell den PIC16F886 Typ nicht - ABER wenn ich das noch
richtig in Erinnerung habe, muß im INTCON auch noch das 'RBIE'-Bit 
gesetzt werden. (Bei den PIC16F76 Typen heißt das Bit auf jeden Fall 
so). Kann sein, daß es beim 886 anders heißt. Aber ohne das Enable-Bit 
kommt auch kein Interrupt.

Gruß
TK

von Thomas B. (dertom83)


Lesenswert?

Jetzt sieht der code so aus und funktiniert immernoch nicht:

#include <p16F886.inc>
#define CONFIGURATION1 _INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & 
_MCLRE_ON & _CP_OFF
#define CONFIGURATION2 _BOR_OFF & _IESO_OFF & _FCMEN_OFF & _LVP_OFF & 
_DEBUG_OFF
        __CONFIG _CONFIG1, CONFIGURATION1 & CONFIGURATION2

org   0x00
  GOTO Config

org   0x04

InterruptServiceVector
  movwf   W_save
  swapf   STATUS,W
  bcf     STATUS, RP0
  movwf   Status_save


  MOVFW    PORTC
  XORLW    B'00000001'
  MOVWF    PORTC
  nop

  MOVFW    PORTB
  MOVLW    B'10000000'
  MOVWF    PORTB

  nop
  nop

Intende_

  BCF     INTCON,RBIF
  bcf     INTCON, T0IF
  bcf     INTCON,INTF

  swapf   Status_save, w
  movwf   STATUS
  swapf   W_save,f
  swapf   W_save,w
  retfie


Config
  BANKSEL TRISB
  movlw   b'10000000'
  movwf   TRISB
  BANKSEL TRISC
  movlw   b'00000000'
  movwf   TRISC
  bsf     STATUS, RP0
  bsf     OPTION_REG,INTEDG ; 0-1-Flanke an RB0
  bcf     STATUS, RP0

  bsf     INTCON, INTE
  bsf     INTCON, GIE
  bsf     INTCON, RBIE
  bsf     IOCB,7
  BANKSEL 0

Start_
  GOTO    Start_
END


Hat noch jemand eine Idee?

von TK (Gast)


Lesenswert?

Wenn ich das richtig interpretiere, soll PORTC,0 mit jedem RB7 Int 
getoggelt werden. In dem letzten Code setzt Du innerhalb der ISR den 
PORTB,7 immer H. Da B7 jedoch Input ist, hat dieser Code eigentlich 
keine Wirkung.
Wie wird denn extern der PORTB,7 angesteuert (oder soll nur eine 
Simulation durchgeführt werden)?
Ansonsten seh ich jetzt erst mal kein weiteres Problem.

Gruß
TK

von Thomas B. (dertom83)


Lesenswert?

das mit dem PORTB,7 hab ich zum Test gemacht, weil im datenblatt etwas 
davon steht, dass der Port gelesen oder geschrieben werden muss um aus 
der ISR raus zu kommen.


Ich steuer den eingang mit 5V direkt an ohne weitere anschaltung

von Erhard (Gast)


Lesenswert?

Hallo,

wenn du den Eingang ohne weitere Ansteuerung beschaltest, kann das zu 
Problemen führen, da kein definierter Zustand am Pin.

Schalte die Pull-Up´s im OPTION-Register ein (RPPU = 0) und steuere 
PORTB,7 mit logisch 0 an.

von TK (Gast)


Lesenswert?

Das mit dem PORT lesen um aus der ISR rauszukommen ist nur die halbe 
Wahrheit! Durch den MOVFW PORTB wird dieser Zustand bereits beendet.
Ich denke mal an PORTC,0 hängt eine LED oder so.
Durch das Schalten von 5V am PORTB,7 kann auch ein Prellvorgang 
entstehen (je nachdem, ob das mit einem Taster, oder mit einer 
Drahtbrücke oder so geschieht)
Besser wäre innerhalb der ISR den PORTC,0 so auszugeben, dass dieser den 
gleichen Pegel wie B7 aufweist. Dann wäre nach einem Prellvorgang am 
Ende der Pegel von C0 identisch mit B7. Das kann man dann besser 
vergleichen, als nur einen reinen Toggeleffekt. Dabei prellt der C0 
nämlich mit und am Ende kann C0 dann einen anderen Pegel aufweisen, als 
an B7.
Und wie der Vorgänger schon geschrieben hat, reicht es nicht aus 5V an 
den Eingang zu legen. So bekommt man zwar immer einen schönen H-Pegel, 
aber der L Pegel stellt sich nicht automatisch ein, wenn man die 5V 
wieder weg nimmt.
Daher sollte ein externer Pull-Down an B7 hängen oder aber die internen 
Pull-Ups aktiviert werden und dann nur mit externen 0V an B7 
umgeschaltet werden.

Gruß
TK

von Thomas B. (dertom83)


Lesenswert?

Das sind gute Hinweise, ich werde das heute nachmittag mal Testen!

- Pullups aktivieren und oV beschalten
- Und statt C,0 zu Togglen besser c0= B7 ausgeben.

von Thomas B. (dertom83)


Lesenswert?

sooo,
tests abgeschlossen, leider nicht erfreulich... Ich habe meinen Code 
jetzt so weit abgespeckt, dass nichts mehr stören kann und einen 
Pull-Down Widerstand (100k) angeschlossen.

#include <p16F886.inc>
#define CONFIGURATION1 _INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF 
&_MCLRE_ON & _CP_OFF
#define CONFIGURATION2 _BOR_OFF & _IESO_OFF & _FCMEN_OFF & _LVP_OFF 
&_DEBUG_OFF
        __CONFIG _CONFIG1, CONFIGURATION1 & CONFIGURATION2

W_save       Equ    0x20
Status_save  Equ    0x21

org   0x00
  GOTO Configur

org   0x04

InterruptServiceVector

  BSF    PORTC,0    ;Test
  BCF    PORTC,0    ;Test

  retfie

org 0xFA
Configur
  BANKSEL TRISB
  movlw   b'10000000'
  movwf   TRISB

  BANKSEL TRISC
  movlw   b'00000000'
  movwf   TRISC

  BANKSEL ANSEL
  CLRF    ANSEL
  BANKSEL 0

  BANKSEL ANSELH
  CLRF    ANSELH
  BANKSEL 0

  BANKSEL OPTION_REG
  bsf     OPTION_REG,INTEDG
  bcf     OPTION_REG,7
  BANKSEL 0

  bsf     INTCON, INTE
  bsf     INTCON, INTF
  bsf     INTCON, GIE
  bsf     INTCON, RBIE
  MOVLW    B'10000000'
  MOVWF   IOCB

  CLRF    PORTB
  CLRF    PORTC

Start_
  GOTO    Start_
END

Jetzt stellt sich mir die Frage, warum mein PortC,0 ständig an und aus 
geschaltet wird? (siehe anhang)

Obwohl ich keinerlei änderungen am Pin RB7 habe.
Ist das eines sache der Konfiguration?

Wenn jemand die möglichkeit hat, das mal an eine PICKit2 oder ähnlichem 
zu testen, würde mir das sehr weiter helfen!

Gruß
Thomas

von TK (Gast)


Lesenswert?

Hallo Thomas,

ich sehe gerade dass du in der INIT-Routine das RBIF-Flag setzt. Wieso 
denn das?
Damit erklärt sich auch, warum du ständig einen Interrupt bekommst!
In der ISR müssen am Ende alle aufgelaufenen Interrupts von "Hand" 
gelöscht werden. Das war in einem vorherigen Code ja bereits drin.
Nachdem RETFIE abgearbeitet wird, kommt dann natürlich sofort wieder ein 
Interrupt - und zwar der INTF!
Also nimm die alte ISR wieder - mit dem gesamten Overhead für W- und 
STATUS Register Rettung usw.
Dann gehts auch.
Ach so, noch was - In den ADCON und CCPCON Registern sollte man die Pins 
noch alle auf Digital schalten, wenn man nicht mit analogen Inputs 
arbeitet.

Gruß
TK

von Thomas B. (dertom83)


Lesenswert?

Das sind alles gute hinweise, jetzt sieht mein Code so aus... mit ein 
paar kommentaren zum besser lesen.
In der Interruptrotine schalte ich PortC,0 kurz ein und wieder aus... 
Mit den Osca kann ich dann messen ob der Pin schaltet.



#include <p16F886.inc>
#define CONFIGURATION1 _INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF 
&_MCLRE_ON & _CP_OFF
#define CONFIGURATION2 _BOR_OFF & _IESO_OFF & _FCMEN_OFF & _LVP_OFF 
&_DEBUG_OFF
        __CONFIG _CONFIG1, CONFIGURATION1 & CONFIGURATION2

W_save       Equ    0x20
Status_save  Equ    0x21

org   0x00
  GOTO Configur

org   0x04

InterruptServiceVector
  movwf   W_save
  swapf   STATUS,W
  bcf     STATUS, RP0
  movwf   Status_save


  BSF    PORTC,0
  nop
  nop
  BCF    PORTC,0

;PORTB Lesen/schreiben, damit ich
;RBIF Löschen kann
  MOVFW  PORTB
  MOVWF  PORTB

;Die Flaggen RBIF und INTF Löschen
  BANKSEL INTCON
  BCF     INTCON,RBIF
  BCF     INTCON,INTF
  BANKSEL 0

Intende_
  swapf   Status_save, w
  movwf   STATUS
  swapf   W_save,f
  swapf   W_save,w
  retfie


org 0xE0
Configur
;RB7 - Input
;RB6:0 - Output
  BANKSEL TRISB
  movlw   b'10000000'
  movwf   TRISB
  BANKSEL 0

;RC7:0 Output
  BANKSEL TRISC
  movlw   b'00000000'
  movwf   TRISC
  BANKSEL 0

;alle Ports Digital
  BANKSEL ANSEL
  CLRF    ANSEL
  BANKSEL 0

  BANKSEL ANSELH
  CLRF    ANSELH
  BANKSEL 0

  BANKSEL ADCON0
  CLRF    ADCON0
  BANKSEL 0

  BANKSEL ADCON1
  CLRF    ADCON1
  BANKSEL 0

  BANKSEL CCP1CON
  CLRF    CCP1CON
  BANKSEL 0

  BANKSEL CCP2CON
  CLRF    CCP2CON
  BANKSEL 0

;PORTB Pull-up Disable - ist bei mir mit 100k nach
;Masse beschaltet Interupt bei steigender Flanke
  BANKSEL OPTION_REG
  bsf     OPTION_REG,7
  bsf     OPTION_REG,INTEDG
  BANKSEL 0


  CLRF    PORTB
  CLRF    PORTC

;Interrupt-on-Change Port - RB7
  MOVLW   B'10000000'
  MOVWF   IOCB

;Interrupt-on-Change Port Eingeschaltet
  bsf     INTCON,RBIE

;Externe Interrupt eingeschaltet
  bsf     INTCON,INTE

;Interruptflagge ausgeschaltet, wird beim Interrupt
;gesetzt und muss in der ISR zurück gesetzt werden
  bcf     INTCON,INTF

;WEAK Pull-Up deaktiviert
  CLRF    WPUB

;Globaler Interrupt aktiviert
  bsf     INTCON,GIE

Start_
  GOTO    Start_
END


Mit diesem Code springt das Programm garnicht erst in die ISR...
Das habe ich getestet, indem ich in der Routine INTF Und RBIF gesetzt 
habe... sollte also das Programm in die ISR springen, würde ich in einer 
endlosschleife hängen. Macht es aber nicht.

Wie im code beschrieben habe ich 100k gegen masse geschaltet und setze 
den ausgang mit den 5V auf High.


Wenn ich manuel INTF in der initialisierung setze, springe ich in die 
ISR
Theoretisch müsste doch mein eingang die Flagge INTF auslösen oder?
Muss ich noch irgendwas deaktivieren, oder in der Config aktivieren, 
dass RB7 auch als interrupt erkannt wird?

von Sven S. (stepp64) Benutzerseite


Lesenswert?

IOCB liegt in Bank 1! Du bist beim Schreiben in das Register aber noch 
in Bank 0.

Der IOC Interrupt benötigt nur das Bit RBIE und natürlich GIE. INTE ist 
nur für den RB0 Interrupt (INT) zuständig. Das kannst du also raus 
nehmen.

Du solltest auch die Rettungsregister in den Bereich 0x70 - 0x7F legen. 
Du weist nicht in welcher Bank sich der µC befindet wenn er in die ISR 
springt und es kann sein, dass du deine Register in die falsche Bank 
sicherst. 0x70 - 0x7F liegen im Access-Ram und haben von allen Bänken 
aus den gleichen Inhalt.

Ich würde es so probieren:

Init:
- PortB auf digital schalten (ANSELH)
- PortB löschen
- TrisB setzen
- IOCB setzen
- eventuell WPUB setzen (Pull-Ups)
- im INTCON RBIE und GIE einschalten

ISR:
- Register retten (nach sprut)
- Routine abarbeiten
- RBIF löschen
- Register zurück schreiben
- zurück springen

Hauptprogramm:
- erst mal nur die Endlosschleife

Sven

Ach ja: WPUB liegt auch in Bank1

von Thomas B. (dertom83)


Lesenswert?

Sven Stefan.... du bist es!!
Vielen Danke!
Jetzt funktioniert es!

Hab IOCB  in Bank 1 gesetzt und die Rettungsregister auf x71 und x72 
geleget!

Da freu ich mich doch.

Gruß
Thomas

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
Noch kein Account? Hier anmelden.