Inhaltsverzeichnis
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:
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: 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
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. |