Forum: Mikrocontroller und Digitale Elektronik ? zu serieller Gerätekommunikation


von Thomas P. (topla)


Lesenswert?

Hallo zusammen,

ich bräuchte mal wieder eine Anregung zur Lösung eines kleinen 
Softwareproblems.

Am Start ist ein ATMega2560@16MHz, dessen Software einen ganzen Schwung 
an Datensätzen verwaltet und anlegen, löschen und ändern ermöglicht. 
Auf Grund der beschränkten Anzeigemöglichkeiten des Geräts (LCD 20 x 2) 
ist es nicht möglich, alle Daten eines Datensatzes (ca. 1kB binär) 
gemeinsam anzuzeigen. Um etwas mehr Komfort anzubieten, soll ein PC für 
diese Funktionen genutzt werden. Die Verbindung zwischen Controller und 
PC wird über eine UART und einen FTDI FT232RL@38400bd hergestellt, über 
die auch ein Bootloader genutzt werden kann.

Die Funktionen „Löschen eines Datensatzes“ und „Übertragen eines 
Datensatzes an den PC“ habe ich umgesetzt, wobei das Übertragen in 
Richtung PC einfach durch sequentielles Lesen der Daten eines 
Datensatzes,  Umwandeln in ASCII mit Trennzeichen „;“ und 
interruptgesteuertes Senden über einen 32 Byte Sendepuffer erfolgt. 
Zeitprobleme gibt es keine, der PC wartet halt auf das Endekennzeichen, 
egal wie lange der Controller dazu braucht. Bis jetzt gibt es keine 
Sicherung der Datenübertragung durch CRC – bisher aber auch keine 
Probleme.

Nun kommt der andere Weg, also die Übertragung eines Datensatzes vom PC 
an den Controller. Die Übertragung erfolgt im gleichen Format, 
allerdings über den gleichen Puffer von 32 Byte wie beim Senden, mehr 
gibt es nicht dafür – ich kann also keinen ganzen Datensatz in ASCII 
puffern, das würde wohl auch so um die 4kB benötigen. Da der Controller 
noch mehr zu tun hat, steht auch nicht die gesamte Rechenleistung für 
die Separierung und Umwandlung zur Verfügung. Also muss ich einen 
Mechanismus implementieren, der das „Überfahren“ des Controllers durch 
den PC und den damit verbundenen Datenverlust vermeidet.

Wie fängt man das jetzt am besten an?

Entweder über eine flow control in Software (xon-xoff) oder Hardware 
(RTS/CTS) und untersuchen der Daten im Puffer, umwandeln und abspeichern 
oder zerlegt man den Datensatz von vorn herein in Häppchen, die in den 
Puffer passen? In diesem Fall könnte man auch eine einfache 
CRC-Sicherung einbauen, muss dann aber auch jeden Schnipsel einzeln 
quittieren. Wartet man den ganzen Satz ab, kann man erst am Ende 
erkennen, ob es einen Fehler gegeben hat.
Irgendwie sehe ich den Wald vor lauter Bäumen nicht und finde keine 
richtig brauchbare Lösung.

Hat da jemand eigene Erfahrung und kann ein sinnvolles Vorgehen hier mal 
kurz skizzieren?

Danke
Thomas

von Harald A. (embedded)


Lesenswert?

Wenn der Empfangspuffer so klein ist muss man halt in kleineren Häppchen 
senden. Handshake in Hardware oder Software ist ja eher so eine 
Protokoll-unabhängige Einrichtung, hat sicherlich in vielen Szenarien 
seine Berechtigung.
Wenn du sowieso von Datensätzen sprichst, kann man das Protokoll 
sicherlich in sinnvollen Häppchen aufteilen. Eine Checksumme ist auch 
eine gute Idee, wenn es einmal läuft tut die nicht weiter weh. Was ich 
immer gerne einbaue ist eine Synchronisation für die Pakete. Jedes Paket 
beginnt mit einem bestimmten Zeichen, der Empfänger wartet nach einer 
beliebigen Situation (Warte auf neues Paket, Fehler, unklarer Zustand, 
Neustart etc.) auf dieses Zeichen und definiert damit den Beginn eines 
neues Frames. Dann folgt z.B ID, Länge, Daten, Checksumme. Wichtig ist, 
dass das Zeichen für Synchronisation in JEDER Situation IMMER den Beginn 
eines neuen Frames darstellt. Also wird jedes eingehende Byte geprüft. 
Damit kann alles passieren, z.B. fehlende Zeichen durch Wackelkontakt 
oder z.B. Empfang einer ungültige Länge. Der Sync fängt das Protokoll 
stets wieder sauber ein. Falls man ohne Sync arbeitet, kann ein aus dem 
Tritt gekommenes Protokoll unter Umständen recht lange brauchen, bis es 
wieder in der Spur ist.
Bei reinen ASCII Daten ist der Sync recht einfach, man nimmt ein 
Zeichen, was sonst nicht vorkommt. Aber selbst bei binären Daten klappt 
das, dann muss man nur eine spezielle Sequenz finden, die die 
Übertragung des „speziellen Zeichens“ ermöglicht. Ein schönes Beispiel 
für so etwas findet man beim Framing Modus der XBee Funkmodule. Beim 
ersten Studium des Mechanismus mag man noch denken, dass das etwas 
kompliziert zu programmieren ist, in der tatsächlichen Umsetzung sind es 
aber dann nur sehr wenige Zeilen extra. Belohnt wird man durch ein 
extrem robustes Protokoll.
Benutze ein solches System in beide Richtungen, der Empfänger quittiert 
dann jedes korrekt empfangene Paket. Schön ist es dann auch, wenn jedes 
fortlaufende Paket einfach eine laufende Nummer zwischen 0..255 bekommt, 
dann kann der Empfänger genau mitteilen, bei welcher Paketnummer ein 
evtl. Fehler vorlag.

von Harald A. (embedded)


Lesenswert?

Hier ist der Framing Mode am Beispiel XBee beschrieben
https://www.digi.com/resources/documentation/Digidocs/90002002/Content/Reference/r_api_frame_format_900hp.htm

Ignoriere den Funkmodul-spezifischen Teil, es geht mir nur um den API 
Frame mit dem Delimiter und der Escape-Sequenz.

von A. S. (Gast)


Lesenswert?

32 Byte ist wenig, aber OK.

Wenn die Daten auch binär ausgetauscht werden können, nimm ruhig binär 
oder hexadezimal. Bei Hex hast Du sehr viele Steuerzeichen frei.

Nimm halt 32 Byte-blocke mit Start, Sequenz, anzahl, Daten, Stop, also 
14 Byte Nutzdaten.

Flow-control über HW finde ich schlecht, da nicht für alle Strecken 
verfügbar. Einfach ein paar Steuerzeichen: nochmal/von 
vorne/Pause/vorletzten Satz/weiter. Der PC wartet halt auf "weiter" etc.

von Thomas P. (topla)


Lesenswert?

Hallo Harald A.,

danke für den Hinweis, das werde ich mir mal zu Gemüte führen.
Da in meinem Anwendungsfall immer ein Bediener beteiligt ist, kann ich 
eine fehlgeschlagene Übertragung immer mit einem Fehler abbrechen, muss 
dann eben manuell neu gestartet werden.

@Achim S.
Von dem Austausch von Binärdaten war ich abgekommen, da ich Probleme mit 
notwendigen Steuerzeichen befürchte und auch ein notwendiges Debugging 
einfacher ist. Auf einer Seite muss ich Daten ohnehin umwandeln und auf 
der Controllerseite tue ich mich leichter damit.

Aber warum ist HW-flow-control schlecht?
Sicher, die Schnittstelle auf PC-Seite muss entsprechend eingestellt 
sein und  nur so kann sich doch der Controller gegen ein Überfahren 
wehren.
Bedenken hätte ich eher wegen Latenzen zwischen dem Erkennen "Puffer 
voll", Senden oder Einschalten des xoff und dessen Wirksamwerden. Keine 
Ahnung, wieviele Zeichen da noch ankommen können, bis der PC das 
geschnallt hat und das Senden einstellt.

Thomas

von Thomas (Gast)


Lesenswert?

Serielle Daten hat man auch früher schon per Upload / Download 
übertragen. Ich würde mir Mal   xmodem anschauen. Ev auch zmodem. Das 
sind standardisierte einfache Protokolle die auch  in jedem Terminal 
Programm verfügbar sind.
Thomas

von Dirk B. (Gast)


Lesenswert?

Thomas P. schrieb:
> Von dem Austausch von Binärdaten war ich abgekommen, da ich Probleme mit
> notwendigen Steuerzeichen befürchte und auch ein notwendiges Debugging
> einfacher ist.
Übliche Verfahren sind i.A. auf eine 'sparsame' Bandbreitennutzung 
ausgelegt und versuchen mit möglichst wenig Extradaten auszukommen, was 
andererseits eine etwas kompliziertere Codierung beinhaltet. In deinem 
Fall hast du aktuell ca.3-fache Bandbreite (relativ zu den Binärdaten) 
sodass eine 'großzügige'/einfach debugbare/einfach (de)codierbare 
Symbolcodierung bspw.
8-bit-binär<--> 2*(4bit-meta+4bit-nib) [ rrns.dddd r(eserved) (n)ibble 
l/h (s)start/stop (d)ata]
immer noch weniger Bandbreite (eh nur Thema in anderen 
Situationen)benötigen würde, aber vor allem extrem extrem einfach und 
µC-Last-schonend implementierbar wäre.
Praktisch keine µC-Leistung-->aufwendige/fehlerträchtige Flusssteuerung 
kann entfallen (der µC kann sicher empfangene Daten verarbeiten (evtl. 
die Leistung/Speicher für eine Tetris-Anwendung nutzen) und die Daten 
sind aufgrund der einfachen, etwas verschwenderischen Codierung immer 
noch bequem mit einfachsten Programmen decodierbar.

> Auf einer Seite muss ich Daten ohnehin umwandeln und auf
> der Controllerseite tue ich mich leichter damit.
wenn  du nicht gerade selbstgebastelte interne Formate verwendest dürfte 
die Umwandlung Wert <--> Text eine einstellige Zeilenanzahl betreffen 
und praktisch 1:1 vom µC übernommen werden können. Als Hobby kann 
debugging von Zeitabläufen natürlich Spass machen, aber leichter wird 
ein (zeitvariabler) Overhead wohl nicht wenn 'feste' (also praktisch nur 
Daten) Übertragungen ohne spezifische Zustände als Alternative möglich 
sind.

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.