Aus RN-Wissen.de
Wechseln zu: Navigation, Suche
Rasenmaehroboter Test

Bascom UART Input

An sich hat Bascom eine ganze Reihe von recht praktischen Befehle für die Daten Ein- u. Ausgabe über den UART. Solange sich Sender und Empfänger immer darüber einig sind, ob gerade ein Byte oder ein Single transferiert wird, ist man hier gut bedient.

Wenn man aber wegen anderer Beschäftigungen des Kontrollers den Empfang asynchron gestalten will, zeigen sich ein paar Widrigkeiten. Denn der Uart empfängt seine Daten immer als eine Reihe von einzelnen Bytes und es müssen daraus erst wieder die richtigen Felder zusammengesetzt werden. Verschärft wird das, wenn auch noch mehrere, womöglich verschiedenartige Felder zu empfangen sind, die erst zusammen einen Sinn ergeben, also zum Beispiel strukturierte "Messages"

Mehrere Felder (Message)

Das ist gewissermaßen die Aufgabenstellung:Bascinput1.png

DIM Msgbyte1 as Byte
DIM Msgword as Word
DIM Msgbyte2 as Byte
DIM Msglong  as Long
DIM Msgbyte3 as Byte

All diese Felder sollen hintereinander empfangen werden. Die Reihenfolge wäre nicht so schlimm, aber wie macht man z.B. aus 4 einzelnen Bytes ein "Long" ?

OVERLAY

Ein Möglichkeit ist es, den Speicherbereich, den diese 5 Felder insgesamt einnehmen, einfach ein zweitesmal zu definieren, diesmal aber als einfaches Byte-Array.

DIM Msgbyte1 as Byte
DIM Msgword as Word
DIM Msgbyte2 as Byte
DIM Msglong  as Long
DIM Msgbyte3 as Byte

DIM Buffer(9) as Byte AT Msgbyte1 OVERLAY

Dadurch entsteht: Bascinput2.png Zu dem Buffer-Array wird natürlich auch ein Index mit dem Anfangswert 1 benötigt

DIM Bufferindex as Byte
Bufferindex = 1

Wenn nun zu einem x-beliebigen Zeitpunkt ein Byte empfangen wird, wird es in den Buffer geschrieben

   IF IsCharWaiting() <> 0 then 
      Buffer(Bufferindex) = INKEY()
      incr Bufferindex 
      IF Bufferindex > 9 then
'------------- Alle Datenfelder komplett, jetzt verarbeiten oder signalisieren ----------------
         Bufferindex = 1        ' Index zurücksetzen
      End If
   End If

Es muß vor Inkey() sichergestellt sein, daß auch tatsächlich ein Zeichen eingelangt ist, denn Inkey() würde, wenn nichts da ist, 0x00 zurückgeben. Dieses 0x00 können wir aber von einem "echten" 0x00, das ja möglich wäre, nicht unterscheiden. Daher vorher "IsCharWaiting()". In einer Receive-ISR ist das natürlich nicht erforderlich, denn da ist immer ein gültiges Zeichen da.

Message-Header und Trailer

Das gezeigte Prinzip hat natürlich für eine praktische Anwendung einen gravierenden Nachteil: Wenn wegen Überlastung oder sonstigen Gründen der Empfänger auch nur ein Byte versäumt, kommt er eigentlich nie oder nur zufällig wieder zu den richtigen Daten.

  • Bei ASCII-Daten kann natürlich ein Steuerzeichen (<CR>) als Kennzeichen verwendet werden, daß als nächstes wieder eine neue Message beginnt.
  • Haben wir es aber mit "transparenten" Daten zu tun, also Bytes mit 0-255, haben wir keine solchen reservierbare Kennzeichen.

Checksum

Als erste Sicherung ist es mal gut, solche verstümmelten Messages als solche zu erkennen. Das löst zwar nocht nicht das genannte Problem, aber wenigstens ist die Gefahr falscher Daten abgewendet. Da gibt es viele Varianten, CRC, BCC und andere. Das sind Prüfziffern, die man hinten an die Message anhängt. Der Sender erstellt sie, der Empfänger prüft.

Byte-Stuffing

Das ist das Verfahren, doch irgendein Zeichen als Steuerzeichen verwenden zu können, indem der Sender gezielt Bytes in den Byte-Stream "reinstopft" (stuffing), die nur zur Kennzeichnung dienen, ob ein Byte "echt" ist oder Teil der Daten ist. Der Empfänger entfernt sie dann wieder.

Dabei gilt folgende Regel: Folgt diesem Steuerzeichen ein beliebiges anderes Zeichen, ist es 
auch wirklich ein Steuerzeichen. Wenn nicht, gehört dieses Folgebyte zu den Daten

Da jedes Zeichen recht ist, hier ein Beispiel mit dem Zeichen "A", das einfach zum Message-Beginn-Steuerzeichen erklärt worden ist.

  Die Zeichenfolge "Hello, World" ist zu übertragen. Der Sender schickt also einfach 
  "AHello, World" über die Leitung (A=Header, das andere eben irgendeine Nachricht)

Das war nun offensichtlich kein Problem, es ist kein Mißverständnis möglich
Aber nun:

  "Guten Abend"  Losgeschickt wird nun 
  "AGuten AAbend"
  Das erste "A" wird von einem "G" gefolgt, also gilt es auch als Header
  Dem zweiten "A" folgt aber ein weiteres "A", also fällt es weg und es bleibt nurmehr "Abend" übrig

Beispielscode:

Vielleicht klingt das kompliziert, ist es aber nicht

Der Sender

DIM Buffer(9) as Byte
DIM BufIdx as Byte
    PRINT chr("A");                   ' der Header wird gesendet
    for Bufidx = 1 to 9 
       if Buffer(BufIdx) = "A" then 
             PRINT chr("A");          ' ein "A" wird "reingestopft"
       End If
       PRINT Buffer(BufIdx);
    next 
Baustelle.gif An diesem Artikel arbeitet gerade Mitglied PicNick.

Am besten momentan noch keine gravierenden Ergänzungen / Änderungen vornehmen.

Dieser Hinweis verschwindet wenn der Autor soweit ist. Sollte dieser Hinweis länger als drei Tage auf einer Seite sein, bitte beim Autor PicNick per PM / Mail oder Forum nachfragen ob er vergessen wurde.

Autor

Siehe auch


LiFePO4 Speicher Test