Forum: Mikrocontroller und Digitale Elektronik PIC16f876A UART Puffer


von Marcel K. (sunny198828)


Lesenswert?

Hallo,
ich habe eine frage wenn ich jetzt an den PIC über rs232 2 bytes 
hintereinander sende werden die hardwaremäßig gepuffert ? und wenn ja 
wie lese ich das zweite byte aus ?

oder muss ich einfach zweimal hintereinader das RCREG auslesen und in 
zwei verschiednen ram registern speichern ?

RS232in
    btfss   PIR1,RCIF        ; sind Daten da ?
    goto    RS232in          ; nein, noch keine Daten da
    movfw   RCREG            ; RS232-Register auslesen
    movwf   Zeichen       ; und in den Speicher nach 'Zeichen' schreiben
    movfw   RCREG
    movwf   Zeichen2

könnte das so klappen ??

wenn nur ein zeichzen gesendet wird müssten dann ja in Zeichen2 nur 
nullen stehen also 0x00 , oder habe ich da jetzt einen denkfehler und 
mein programm würde an der stelle hängen bleiben ?

kanns gerade leiter nicht testen, deswegen frage ich hier mal die 
spezialisten ;-)

PS: Was ich noch vergass , der pic läuft mit 20mhz und es ist eine baud 
von 9600 eingestellt ... was mir aber gerade durch den kopf ging sollte 
ich dann für die folgenden zeichen nicht lieber eine schleife machen die 
halt nur x mal das PIR1 register abfragt ob daten da sind ?

es werden maximal 4 bytes direkt hintereinader gesendet
mfg

von Jens (Gast)


Lesenswert?

Marcel Klug schrieb:
> oder muss ich einfach zweimal hintereinader das RCREG auslesen und in
> zwei verschiednen ram registern speichern ?

Genau so. Allerdings solltest du vor jeder Leseoperation das 
Interuptflag RCIF abfragen. Wenn nur ein Zeichen empfangen wurde, wird 
es nach dem ersten Auslesen zurückgesetzt, bei zwei Bytes nach dem 
zweiten Auslesen. Was passiert, wenn du zweimal RCREG ausliest, obwohl 
nur ein Byte drin steht, kann ich dir jetzt nicht beantworten.

von W.S. (Gast)


Lesenswert?

Mach am beste den I/O-Verkehr per Interrupt und Ringpuffern:

Auszug aus der Interrupt-Routine:

          ....
          SKIP     RCIF
          GOTO     i1

;  Byte von SIO wurde empfangen
          BCF      RCIF
          MOVF     RCSTA,W     ; Test auf Rx Fehler
          ANDLW    B'00000110'
          SKIP     NZ
          GOTO     i_rxb
          BCF      CREN
          NOP
          BSF      CREN
          GOTO     i1

i_rxb:    MOVF     rx_ip,W     ; Zeichen in den
          ANDLW    7           ; Empfangs-Ringpuffer
          ADDLW    RxBuf       ; schreiben
          MOVWF    FSR
          MOVF     RCREG,W
          MOVWF    Indirect
          INCF     rx_ip,W
          ANDLW    7
          MOVWF    rx_ip

i1:       SKIP     TXIF
          GOTO     i2
;  SIO Sender kann nächstes Byte vertragen
;  (TXIF kann man nicht löschen! - nur mit TXIE=0 verbieten)
          MOVF     tx_ip,W
          XORWF    tx_op,W
          SKIP     Z
          GOTO     i_send_next
          BSF      RP0        ; Bank 1
          BCF      TXIE       ; wenn es nix zu tun gibt, löschen wir 
TXIE
          BCF      RP0
          GOTO     i2
i_send_next:
          MOVF     tx_op,W
          ADDLW    TxBuf
          MOVWF    FSR
          MOVF     Indirect,W
          MOVWF    TXREG
          INCF     tx_op,W
          ANDLW    63
          MOVWF    tx_op

i2:  ....

Und hier die UP, die vom normalen Programm aufgerufen werden:
; V.24 In/Out-Funktionen
; Test, ob empfangene Zeichen verfügbar sind.
; ZERO, wenn nix anliegt
CharAvail:
          MOVF     rx_ip,W
          XORWF    rx_op,W
          RETURN

; liefert empfangenes Zeichen
GetChar:  MOVF     rx_ip,W
          XORWF    rx_op,W
          SKIP     NZ
          GOTO     GetChar  ; wartet auf Zeichen!!
          MOVF     rx_op,W
          ADDLW    RxBuf
          MOVWF    FSR
          INCF     rx_op,W
          ANDLW    7
          MOVWF    rx_op
          MOVF     Indirect,W
          RETURN


; sendet Zeichen
PutChar:  BCF      GIE
          MOVWF    PHudl     ; Zeichen retten

__put1:   INCF     tx_ip,W
          XORWF    tx_op,W
          ANDLW    63
          SKIP     Z
          GOTO     __put2

          BSF      RP0       ; Puffer ist voll, also warten
          BSF      TXIE
          BCF      RP0
          BSF      GIE
          GOTO     __put1

__put2:   BCF      GIE
          MOVF     tx_ip,W
          ANDLW    63
          ADDLW    TxBuf
          MOVWF    FSR
          MOVF     PHudl,W
          MOVWF    Indirect
          INCF     tx_ip,W
          ANDLW    63
          MOVWF    tx_ip
          BSF      RP0
          BSF      TXIE
          BCF      RP0
          MOVF     PHudl,W    ; Zeichen zurück nach W
          BSF      GIE
          RETURN


So, das sollte ausreichen.

W.S.

von Sascha (Gast)


Lesenswert?

Wie wärs, wenn man sich im Datenblatt die Funktionsweise des USART 
Receivers durchliest? Sie befindet sich im Kapitel 10.2.2.

von Anja (Gast)


Lesenswert?

Marcel Klug schrieb:
> wenn ich jetzt an den PIC über rs232 2 bytes
> hintereinander sende werden die hardwaremäßig gepuffert ?

Nö der 16f876a hat nur ein Schieberegister für den Empfang und ein 
Datenregister. Er kann also maximal 1 Byte gerade Empfangen während das 
vorherige von der Software weiterverarbeitet wird.

Marcel Klug schrieb:
> wenn nur ein zeichzen gesendet wird müssten dann ja in Zeichen2 nur
> nullen stehen also 0x00 , oder habe ich da jetzt einen denkfehler
Du liest 2  hintereinander das Datenregister aus also 2 denselben 
Wert.

Marcel Klug schrieb:
> es werden maximal 4 bytes direkt hintereinader gesendet
Da ist eine Interruptroutine mit Ringpuffer und eine Statemachine für 
den Empfang nicht verkehrt.

Gruß Anja

von Marcel K. (sunny198828)


Lesenswert?

@ Anja
okay aber im Datenblatt steht dass das RCREG ein doppelter puffer ist.
Würde ich so verstehen dass das RCREG 2 bytes speichern kann.
Weiter steht noch im Datenblatt wenn das 3. byte kommt und das stop bit 
angekomment ist und dabei der RCREG noch nicht leer ist , dass das 3 
byte verloren ist und das OERR bit gesetzt wird. dieses OERR bit kann 
nur gelöscht werden indem man die UART resetet (CREN)

So da ich ja weiß das maximal 4 bytes nacheinander ohne pause kommen 
werde ich das einfach so machen :

RS232in
   btfss   PIR1,RCIF     ; sind Daten da ?
   goto    RS232in       ; nein, noch keine Daten da
   movfw   RCREG         ; RS232-Register auslesen
   movwf   Zeichen       ; und in den Speicher nach 'Zeichen' schreiben

   MOVLW    20           ; 20 ins Arbeitsregister laden
   MOVWF    0x20         ; die 20 wird in die Speicherzelle 0x20 kopiert
byte2                    ; eine Einsprungmarke
   btfss   PIR1,RCIF     ; sind Daten da ?
   goto    byte2_no       ; nein, noch keine Daten da
   movfw   RCREG         ; RS232-Register auslesen
   movwf   Zeichen2      ; und in den Speicher nach 'Zeichen' schreiben
   goto    byte_3
byte2_no
   DECFSZ   0x20,1  ;der Wert in der Sp.Zelle 20h wird um 1 verringert
   GOTO     byte2   ; Sprung zur Marke LOOP
   goto     Main    ; hier geht das eigtl. Programm weiter
byte_3
   MOVLW    20           ; 20 ins Arbeitsregister laden
   MOVWF    0x20         ; die 20 wird in die Speicherzelle 0x20 kopiert
byte3                    ; eine Einsprungmarke
   btfss   PIR1,RCIF     ; sind Daten da ?
   goto    byte3_n       ; nein, noch keine Daten da
   movfw   RCREG         ; RS232-Register auslesen
   movwf   Zeichen3      ; und in den Speicher nach 'Zeichen' schreiben
   goto    byte_4
byte3_no
   DECFSZ   0x20,1  ;der Wert in der Sp.Zelle 20h wird um 1 verringert
   GOTO     byte3   ; Sprung zur Marke LOOP
   GOTO     Main

byte_4

 .....

da schreibe ich jetzt mal nicht weiter ^^

so müsste das ja klappen und dauert bei einem PIC tackt von 20mhz ja 
eigentlich auch nicht lange

Mit Freundlichen Grüßen

von W.S. (Gast)


Lesenswert?

Marcel BesondersKlug schrieb:

> So da ich ja weiß das maximal 4 bytes nacheinander ohne pause kommen
> werde ich das einfach so machen :

Hmm.. wozu fragst du eigentlich nach Rat?

W.S.

von Marcel K. (sunny198828)


Lesenswert?

@ W.S.
entschuldige da habe ich mich falsch ausgedrückt !
eigentlich wollte ich wissen ob man das so machen kann ...

von Marcel K. (sunny198828)


Lesenswert?

Hi,
falls es jemanden interessiert, ich habe mal selbst ein bisschen 
überelegt und gelesen und habe mir jetzt auch dank eurer tollen hilfe 
hier im forum eine kleine Interrupt routine gebastelt.

;RS232-Empfänger-Interrupt?
    btfss    PIR1,RCIF
    goto     intEnde       ; Interrupt kam von wo anders

    movfw    RCREG         ; RS232-Register auslesen
    movwf   temp
  goto   Ringpuffer       ; und in den Speicher nach 'Zeichen' schreiben
Ringpuffer_fertig
    bsf      DatenSindDa,0 ; Kennzeichen für gültige Daten setzen
    bcf      PIR1,RCIF     ; interrupt-Flag löschen
  goto   intEnde
Ringpuffer
  movlw  5
  subwf  puffer_zähler, w
  btfsc  STATUS,Z
  goto  Zeichen_0
  movlw  4
  subwf  puffer_zähler, w
  btfsc  STATUS,Z
  goto  Zeichen_1
  movlw  3
  subwf  puffer_zähler, w
  btfsc  STATUS,Z
  goto  Zeichen_2
  movlw  2
  subwf  puffer_zähler, w
  btfsc  STATUS,Z
  goto  Zeichen_3
  movlw  1
  subwf  puffer_zähler, w
  btfsc  STATUS,Z
  goto  Zeichen_4

Zeichen_0
  movfw  temp
  movwf  Zeichen0
  decf  puffer_zähler, 1
  goto  Ringpuffer_fertig
Zeichen_1
  movfw  temp
  movwf  Zeichen1
  decf  puffer_zähler, 1
  goto  Ringpuffer_fertig
Zeichen_2
  movfw  temp
  movwf  Zeichen2
  decf  puffer_zähler, 1
  goto  Ringpuffer_fertig
Zeichen_3
  movfw  temp
  movwf  Zeichen3
  decf  puffer_zähler, 1
  goto  Ringpuffer_fertig
Zeichen_4
  movfw  temp
  movwf  Zeichen4
  movlw  5
  movwf  puffer_zähler
  goto  Ringpuffer_fertig

intEnde                    ; geretteten Status wieder zurückschreiben
    swapf    status_temp,w
    movwf    STATUS
    swapf    w_temp,f
    swapf    w_temp,w
    retfie

Bei der Init meines pics lade ich natürlich 5 in den puffer_zähler.
Jetzt will ich noch die DTR line an RB0 anschliesen (natürlich über 
MAX232) und RB0 auch auf Interrupt stellen und wenn jetzt die RB0 High 
geht soll die 5 in den puffer_zähler laden. Ich weiß das ist umständlich 
aber der Puffer funktioniert so schon mal für mich ganz gut.

Im Hauptprogramm frage ich jetzt einfach immer DatenSindDa ab wenn das 
bit gesetzt ist gebe ich dem pic noch ein paar ms zeit damit der 
empänger interrupt in ruhe weiter arbeiten kann und ich alle empfangenen 
zeichen sicher um puffer habe und dann geht mein eigentliches programm 
weiter.

von K. J. (Gast)


Lesenswert?

Hm bis auf das Call besser ist als goto und du in der schleife den ISR 
nicht deaktivierst ist es ok.

z.b. wie im Anhang.

edit: http://grautier.com/temp/fifo.txt

von Marcel K. (sunny198828)


Lesenswert?

okay mit dem goto habe ich gedacht mache ich es lieber so weil er ja 
sonst nachdem er zeichen0 geschrieben hat mit einem call befehl wieder 
in den puffer_zähler zurück springt und unnötig weitere befehle ausführt 
... das war mein gedanlke !

Was meinst du mit ich deaktiviere die ISR nicht ??

mfg

von Marcel K. (sunny198828)


Angehängte Dateien:

Lesenswert?

Was ich noch wissen wollte in MPLAB bekomme ich beim kompelieren diesen 
fehler
 Register in operand not in bank 0.  Ensure that bank bits are correct.

wo er ja uach recht hat ADCON1 ist in BANK 1 und ich schalte ja auch 
vorher mit bsf STATUS, RP0 in Bank1 ich hänge mal mein programm an was 
ich bis jetzt habe ...
Trozdem baut er die Hex und sie läuft auch

von Dieter W. (dds5)


Lesenswert?

Marcel Klug schrieb:
> Was ich noch wissen wollte in MPLAB bekomme ich beim kompelieren diese
> fehler
>  Register in operand not in bank 0.  Ensure that bank bits are correct.

Das ist keine Fehlermeldung (error) sondern nur ein Hinweis (message). 
Leider eine unglückliche Lösung die schon bei vielen Leuten für 
Verwirrung gesorgt hat.

von Marcel K. (sunny198828)


Lesenswert?

aaahh okay danke aber kannst du mir erklären warum das so ist ? muss ja 
irgendwie an mir liegen , denn wenn ich von sprut ein programm nehme 
zeigt er mir es nicht an ...

mfg

von Marcel K. (sunny198828)


Lesenswert?

Hy,
ich habe die antwort auf meiner Frage selbst gefunden !

Ich muss einfach am anfang meines Assemblercodes das hier eintragen

ERRORLEVEL -302 ;remove message about using proper bank

hatte ich auch hatte es aber deaktiviert

;ERRORLEVEL -302 ;remove message about using proper bank

mfg sunny

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.