Forum: Mikrocontroller und Digitale Elektronik RS232 mehrere Bytes senden und Variablen zuordnen??


von Marcel M. (dassauerkraut)


Lesenswert?

Hallo,

im Zuge meine Ausbildung zum Elektroniker für Geräte und Systeme arbeite 
ich im Moment an einem PIC Projekt. Ich habe mir bereits angesehen wie 
ich den UART im PIC auswerte und Daten über RS232 empfange und sende.

Jetzt habe ich jedoch das Problem das ich 4 Variablen von 0-255 von 
einem PIC zum anderen übergeben möchte. Wie kann ich dem PIC beibringen 
welches empfangene Byte zu welcher Variablen gehört?

Ich habe erst wenige Monate Erfahrung mit der Programmierung weshalb ich 
mich freuen könnte wenn sich jemand kurz Zeit nimmt um mir zu erklären 
wie ich eine solche Auswertung prinzipiell zu Stande bekomme. Google 
konnte mir leider nicht wirklich helfen...

vielen Dank schon mal im voraus

von Dietrich L. (dietrichl)


Lesenswert?

Marcel Meyer schrieb:
> 4 Variablen von 0-255

Wenn es nicht um Geschwindigkeit geht, wäre ein ASCII Kodierung am 
einfachsten, z.B.:

<STX> <High-Nibble Var.1> <Low-Nibble Var.1> <High-Nibble Var.2> ....

wobei "High Nibble" und "Low Nibbel" die beiden ASCII-kodierten Stellen 
der Hexadezimalzahl der Variablen sind.

Der Empfänger wartet dann auf <STX> und die nächsten 8 Zeichen sind die 
4 Variablen.
Wenn man am Ende dann noch <CR> und <LF> sendet, kann man sich die Daten 
auch einfach mit einem Terminalprogramm in Listenform ansehen.

Gruß Dietrich

von Achim M. (minifloat)


Lesenswert?

Marcel Meyer schrieb:
> das ich 4 Variablen von 0-255 von
> einem PIC zum anderen übergeben möchte

a) Billige Möglichkeit, Vorsicht Bitfummelei und nicht erweiterbar:
Teile die Variablen auf in 8 Nibbles zu 4 Bit. Die restlichen 4 bit 
dienen der Darstellung, zu welchem Nibble jetzt die gerade gesendete 
Information gehört. Wenn zu einer 8Bit Variable zwei Nibbles 
eingetroffen sind, wird sie in die Datenhaltung übernommen. Das eine 
verbleibende Bit kann für ein Toggle genutzt werden, um einfachst 
sicherzustellen, dass die gerade gesendeten Nibbles einer Variable auch 
zum selben Zeitpunkt beim Sender gesampled wurden.

b) Ein Protokoll aufsetzen, dazu eignet sich z.B. ein vorhandenes wie 
Modbus oder ähnliches.

von Marcel M. (dassauerkraut)


Lesenswert?

OK also das mit der ASCII Kodierung hört sich sinnvoll an.

Jetzt wäre nur die Frage, wie ich so etwas in Assembler umsetzen kann.

Als erstes Stelle ich mir die Frage wie ich aus einem Nibble ein ASCII 
Zeichen erstellen kann, das ich dann ausgebe?

von Dietrich L. (dietrichl)


Lesenswert?

Marcel Meyer schrieb:
> Als erstes Stelle ich mir die Frage wie ich aus einem Nibble ein ASCII
> Zeichen erstellen kann, das ich dann ausgebe?

Google sagt mir auf die Schnelle:
http://www.piclist.com/techref/microchip/math/radix/b2ah-8b2a-sd.htm
(ohne Garantie!)

Gruß Dietrich

von Fabian O. (xfr)


Lesenswert?

Du könntest auch ein Escape-Zeichen (z.b. 0x1B) definieren, das 
kennzeichnet, dass das darauf folgende Zeichen ein Kommando darstellt. 
Ein Kommando könnte dann bedeuten "Beginn der Übertragung" (z.B. 0x02). 
Es kann aber natürlich passieren, dass man das Escape-Zeichen 0x1B auch 
mal als Nutzdaten braucht. Ein "Kommando" muss also sein "Das 
Escape-Zeichen ist in den Nutzdaten" (z.B. 0x01).

Beispiel 1: Die Variablen sollen die Werte 0x11, 0x12, 0x13, 014 
bekommen. Die Übertragung sieht folgendermaßen aus:

0x1B (Escape-Zeichen: Das folgende Zeichen ist ein Kommando)
0x02 (Kommando: Beginn der Übertragung)
0x11 (Wert für Variable 1)
0x12 (Wert für Variable 2)
0x13 (Wert für Variable 3)
0x14 (Wert für Variable 4)

Beispiel 2: Die Variablen sollen die Werte 0x1A, 0x1B, 0x1C, 0x1D 
bekommen. Die Übertragung sieht folgendermaßen aus:

0x1B (Escape-Zeichen: Das folgende Zeichen ist ein Kommando)
0x02 (Kommando: Beginn der Übertragung)
0x1A (Wert für Variable 1)
0x1B (Escape-Zeichen: Das folgende Zeichen ist ein Kommando)
0x01 (Kommando: "Das Escape-Zeichen ist in den Nutzdaten": Wert für 
Variable 2 = 0x1B)
0x1C (Wert für Variable 3)
0x1D (Wert für Variable 4)

Beim Empfangen der Daten muss man also den Datenstrom immer auf das 
Escape-Zeichen 0x1B hin prüfen. Wenn es auftaucht, sagt das darauf 
folgende Zeichen, was zu tun ist. Nur wenn die Kombination 0x1B, 0x02 
auftaucht, handelt es sich um einen gültigen Übertragungsbeginn.

: Bearbeitet durch User
von Marcel M. (dassauerkraut)


Lesenswert?

Okay also nochmal zum Verständnis:

ich suche mir ein Escape Byte aus und ein Kommande Byte z.B ASCII STX 
und ETX. Dann sende ich meine Variablen in aufgeteilten Nibbles von 
ASCII 0-F . Damit umgehe ich das STX und ETX in den Nutzdaten vorkommt. 
Somit ist das Datenpaket immer eindeutig oder?

Und im Empfänger prüfe ich immer auf STX und habe daraufhin eine 
eindeutige Zuordnung der Daten die ankommen

Soweit alles richtig verstanden?


Macht es sinn noch ein schluss Zeichen zu senden und da nach eine kurze 
Pause einzulegen? Da ich immer genau vier Variablen übertrage brauche 
ich kein Schlussbit oder?

von Fabian O. (xfr)


Lesenswert?

Marcel Meyer schrieb:
> ich suche mir ein Escape Byte aus und ein Kommande Byte z.B ASCII STX
> und ETX. Dann sende ich meine Variablen in aufgeteilten Nibbles von
> ASCII 0-F . Damit umgehe ich das STX und ETX in den Nutzdaten vorkommt.
> Somit ist das Datenpaket immer eindeutig oder?

Das ist doppelt gemoppelt. Wenn Du die Daten in Nibbles sendest, 
brauchst Du nichts escapen. Jedes gesendete Byte besteht aus 4 Bit 
Kommando und 4 Bit Nutzdaten.

Die Kommandos könnten z.B. sein:
0x0: Variable 1, Low-Nibble
0x1: Variable 1, High-Nibble
0x2: Variable 2, Low-Nibble
0x3: Variable 2, High-Nibble
0x4: Variable 3, Low-Nibble
0x5: Variable 3, High-Nibble
0x6: Variable 4, Low-Nibble
0x7: Variable 4, High-Nibble

Wenn Du dann den Variablen die Werte 0x3A, 0x4B, 0x5C, 0x6D zuweisen 
willst, ist die gesendete Folge:

0x0A: Variable 1, Low-Nibble  = 0xA |
0x13: Variable 1, High-Nibble = 0x3 -> Variable 1 = 0x3A
0x2B: Variable 2, Low-Nibble  = 0xB |
0x34: Variable 2, High-Nibble = 0x4 -> Variable 2 = 0x4B
0x4C: Variable 3, Low-Nibble  = 0xC |
0x55: Variable 3, High-Nibble = 0x5 -> Variable 3 = 0x5C
0x6D: Variable 4, Low-Nibble  = 0xD |
0x76: Variable 4, High-Nibble = 0x6 -> Variable 4 = 0x6D

Bei meinem Vorschlag benutzt Du dagegen ein Escape-Zeichen, um Kommandos 
wie "Übertragungsbeginn" im Datenstrom "hervorzuheben". Die Werte können 
dann (abgesehen vom Fall, dass das Escape-Zeichen in den Nutzdaten 
vorkommt) unverändert byteweise übertragen werden.

Marcel Meyer schrieb:
> Macht es sinn noch ein schluss Zeichen zu senden und da nach eine kurze
> Pause einzulegen? Da ich immer genau vier Variablen übertrage brauche
> ich kein Schlussbit oder?

Eine Kommando "Übertragungsende" kannst Du natürlich einfügen, ist aber 
nicht unbedingt nötig, genau wie eine Pause. Bei beiden Verfahren kannst 
Du in einem Datenstrom mit beliebigem Beginn ohne Zeitinformation den 
Beginn der Übertragung eindeutig erkennen. Das Ende ergibt sich von 
alleine daraus, dass Du ja weißt, dass Du genau vier Variablen befüllen 
willst.

Bei der Version mit den Nibbles könntest Du sogar nur einzelne Variablen 
ändern. Es ist allerdings schlechter um weitere Kommandos erweiterbar.

: Bearbeitet durch User
von Dietrich L. (dietrichl)


Lesenswert?

Marcel Meyer schrieb:
> Soweit alles richtig verstanden?

Ja.

> Macht es sinn noch ein schluss Zeichen zu senden und da nach eine kurze
> Pause einzulegen? Da ich immer genau vier Variablen übertrage brauche
> ich kein Schlussbit oder?

Nein, ein Schlusszeichen brauchst Du nicht.
Aber eine Pause ist ggf. ganz sinnvoll, damit der Empfänger Zeit hat das 
empfangene Telegramm auszuwerten, bevor er wieder empfangsbereit ist für 
das nächste Telegramm. Das hängt natürlich ab von 
Übertragungsgeschwindigkeit und von der Realisierung der SW (Polling, 
interruptgesteuert, ...).

Gruß Dietrich

von Marcel M. (dassauerkraut)


Lesenswert?

Ok kurzes Verständnis Problem:

wenn ich eine 8Bit breite Variable übertragen möchte, ist es doch 
notwendig diese in zwei nibbles zu zerlegen damit ich sie sinnvoll aus 
zwei ASCII Zeichen von 0-F übertragen kann. wenn ich den Wert nur als 
High Nibble sende habe ich doch nur noch einen 4Bit breiten Wert für den 
Inhalt der Variable zur Verfügung? Dann macht es doch sinn das mit 
Escape und Kommand zu machen?

von Fabian O. (xfr)


Lesenswert?

Mal ganz grundsätzlich: Du willst vier 8-Bit-Wörter übertragen und hast 
dafür einen Strom aus 8-Bit-Wörtern zur Verfügung. Das Problem ist, dass 
Du noch mindestens die Steuerinformation übertragen musst, wo Deine 
Übertragung beginnt, damit Du die vier Werte den korrekten Variablen 
zuordnen kannst. Wenn Du 8 Bit in 8-Bit-Wörtern direkt kodierst, sind 
allerdings keine freien Wörter für die Steuerdaten mehr übrig.

Es gibt jetzt verschiedene Möglichkeiten, diese Steuerinformation mit in 
den Datenstrom zu kodieren:

1) Du kodierst ein 8-Bit-Wort in 8 Bit. Für die Kommandos nutzt Du ein 
Escape-Zeichen mit besonderer Bedeutung. Wenn dieses Zeichen in den 
Nutzdaten auftritt, muss es gesondert behandelt werden. Das habe ich im 
Beitrag um 16:37 beschrieben.

2) Du kodierst ein 8-Bit-Wort in zwei 8-Bit-Worten.

2a) Du nutzt jeweils 4 Bit innerhalb eines Bytes für das Kommando und 
die anderen 4 Bit für die Daten. Man braucht dann keine zusätzlichen 
Steuerzeichen, weil die Kommandos in 4 Bit jedes übertragenen Bytes 
stehen. Das habe ich im Beitrag um 17:08 beschrieben.

2b) Du überträgst jeweils 4 Bit als ASCII-Zeichen (das 8 Bit braucht). 
Dann hast Du noch eine Menge anderer Zeichen als Steuerzeichen zur 
Verfügung. Eine Übertragung könnte also aus einem Startzeichen und 8 
ASCII-Zeichen ('0' bis 'F') bestehen.

Es gibt bestimmt auch noch viele andere Möglichkeiten. Welche Du nimmst, 
musst Du entscheiden. Der Platzbedarf auf dem Bus ist unterschiedlich, 
aber für Dich vermutlich nicht relevant. Der Programmieraufwand ist bei 
allen recht ähnlich. Im Prinzip also reine Geschmackssache.

von Marcel Meyer (Gast)


Lesenswert?

Ok ich denke jetzt habe ich verstanden wie du es gemeint hast. =) Ich 
werde mich morgen mal an den Quellcode geben und das gannze mal testen. 
Sollte ich dabei noch auf weitere Probleme stoßen muss ich nochmal 
fragen an sonnsten gebe ich zeitnah nochmal Feedback ob alles geklappt 
hat =)

Auf jedenfall schonmal vielen Dank für die detailierte Beschreibung!

von chris (Gast)


Lesenswert?

Normalerweise benutzt man dazu 9bit uart.
bit9 gesetzt ist Addresse, sprich FSR und nicht gesetzt ist Daten,
sprich INDF

von Marcel M. (dassauerkraut)


Lesenswert?

So,

also das hier wäre jetzt mein Quellcode:

mainloop

      call    PWM_R_ASCII
      call    PWM_G_ASCII
      call    PWM_B_ASCII
      call    DMX_Adress_ASCII
      call    RS232senden
      goto     mainloop

PWM_R_ASCII
      movfw    PWM_R
      call    umwandeln_B2ASCII
      movwf    PWM_RL
      movfw    high_nibble_senden
      movwf    PWM_RH
      return

PWM_G_ASCII
      movfw    PWM_G
      call    umwandeln_B2ASCII
      movwf    PWM_GL
      movfw    high_nibble_senden
      movwf    PWM_GH
      return

PWM_B_ASCII
      movfw    PWM_B
      call    umwandeln_B2ASCII
      movwf    PWM_BL
      movfw    high_nibble_senden
      movwf    PWM_BH
      return

DMX_Adress_ASCII
      movfw    DMX_Adress
      call    umwandeln_B2ASCII
      movwf    DMX_AdressL
      movfw    high_nibble_senden
      movwf    DMX_AdressH
      return

RS232senden
      btfss    PIR1,TXIF       ; Prüfe ob senden erlaubt
      goto    RS232senden
      movlw    D'2'        ; Entspricht dem ASCII "STX"
      movwf    TXREG
      movfw    PWM_RH
      movwf    TXREG        ; Register zur Ausgabe auf UART
      movfw    PWM_RL
      movwf    TXREG
      movfw    PWM_GH
      movwf    TXREG        ; Register zur Ausgabe auf UART
      movfw    PWM_GL
      movwf    TXREG
      movfw    PWM_BH
      movwf    TXREG        ; Register zur Ausgabe auf UART
      movfw    PWM_BL
      movwf    TXREG
      movfw    DMX_AdressH
      movwf    TXREG        ; Register zur Ausgabe auf UART
      movfw    DMX_AdressL
      movwf    TXREG
      return
;-----------------------------------------------------------------------
; Konvertiert ein byte in w in zwei ASCII Zeichen von 0-F! Gibt das 
obere
; Nibble in char_hi aus und das untere Nibble in W
;-----------------------------------------------------------------------
umwandeln_B2ASCII
      movwf  high_nibble_senden
         swapf  high_nibble_senden,w
         andlw  0x0f

        addlw  6
        skpndc
         addlw   'A'-('9'+1)
        addlw    '0'-6

         xorwf  high_nibble_senden,w
        xorwf  high_nibble_senden,f
        xorwf  high_nibble_senden,w

        andlw  0x0f

        addlw  6
        skpndc
         addlw   'A'-('9'+1)
        addlw    '0'-6
      return



Jetzt denke ich mir das das so eigentlich klappen müsste.

Anzumerken habe ich nur das ich keine Idee gefunden habe mehrere 
Variablen mit einer Funktion auszugeben. Ich habe mich ja hier im 
Quellcode oft wiederholt. Gibt es da eine Möglichkeit der Vereinfachung?

Was sagt das ExpertenAuge zu meinem Programm. Ist wie gesagt die 
Variante mir ESCAPE Byte am Anfang...

von Marcel M. (dassauerkraut)


Lesenswert?

das ganze scheint auch irgendwie nicht zu funktionieren =( HyperTerminal 
zeigt nur LLLLL..... an

von chris (Gast)


Lesenswert?

Wieso du aber binary mit ascii mischt, ist mir unverstàndlich.
Da kannst du genausogut die Daten direkt senden, und wenn du die
Daten mit 0xAA (anstelle von 2, ist sicherer) veroderst, dann kommt auch
kein 0xAA in den Daten vor.
so z.B.
sendrs232
    movlw 0xAA
    call rs232TX
    movfw data
    xorlw 0xaa
    call rs232TX
 ...
und beim empfang, machst du
    ;empfang von Zeichen in W
    xorlw 0xaa
    bz  stx_empfangfen
    movwf INDF
    btfss FSR,?? ; verhindert overflow, man muss aber
                 ; dazu die Variablen planen
    incf  FSR


Du kònntest genauso z.B. '\n' als Endzeichen nehmen.
Es setzte dir den Pointer wieder auf null und nach
RS232senden
      btfss    PIR1,TXIF       ; Prüfe ob senden erlaubt
      goto    RS232senden
      movwf    TXREG
      return

DatensatzSenden
      movlw    D'2'        ; Entspricht dem ASCII "STX"
      call     RS232senden
      swapf    PWM_B,w
      call     nibble2hex
      call     RS232senden
      movfw    PWM_B
      call     nibble2hex
      call     RS232senden
...   return
;-----------------------------------------------------------------------
; Konvertiert ein byte in w in zwei ASCII Zeichen von 0-F! Gibt das
obere
; Nibble in char_hi aus und das untere Nibble in W
;-----------------------------------------------------------------------
nibble2hex
         andlw  0x0f
        addlw  6
        skpndc
         addlw   'A'-('0'-6)
        addlw    '0'-6
        return

von Marcel Meyer (Gast)


Lesenswert?

OK also das Grundprogramm läuft jetzt soweit Fehlerfrei. Ich muss mich 
jetzt nochmal damit befassen wie ich das ganze mit dem FSR und INDF 
etwas kompakter gestalten kann. Wenn da jemand einen Tipp hat wäre ich 
froh, werde mich aber parallel da mal einlesen

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.