Guten morgen zusammen,
ich habe gestern meine ersten Zeichen per UART an HTerm gesendet
(Controller Atmega88 mit einem FT232RL USB->Serial Konverter).
Mein eigentliches Ziel ist es, Daten von einem Programm am PC (zunächst
erstmal manuell von HTerm) an den µC zu senden und dort dann in das
EEPROM zu speichern. Gesendet werden soll 1 Array mit 200 Stellen
(Variablen darin 16-bit signed) und ein paar kleine Konfig-Variablen
(8-bit unsigned)
Der UART kann ja nur 8-bit in einem Rutsch übertragen. Also muss ich die
Variable zerlegen durch maskieren und immer erst das MSB oder LSB senden
und dann eben das andere und am µC in der richtigen Reihenfolge durch
8faches schieben wieder durch Veroderung der beiden zusammenbasteln in
eine Variable. Soweit habe ich das aus der Suche mal verstanden. Der
Empfang geschieht natürlich per Interrupt, um nichts zu verpassen. Ich
dachte ich puffere dies und schreibe es im Hauptprogramm dann in das
EEPROM, da die Schreibzugriffe hier ja nicht sonderlich schnell sind.
Jetzt ist meine Frage, wie baue ich das Protokoll auf. Habe ich der
Suche ebenfalls richtig entnommen, dass man eine 8-bit Zahl am besten in
ein ASCII-Zeichen konvertiert, welche dann als 1 Zeichen gesendet werden
kann und der µC das wieder rückkonvertiert zu einer Zahl und diese
speichert?
Wie stelle ich fest, dass keine Zahl verloren geht bzw. wäre es ja
fatal, wenn beispielsweise ein MSB verloren geht, dann verschiebt sich
ja alles um 1 Byte. Ich habe leider keinen Portpin mehr frei um das im
Handshake zu machen, daher wäre hier enie Software Prüfung besser. Wie
macht man das in der Regel, sendet man 1 Character der signalisiert das
nächste Byte ist MSB und einen anderen der signalisiert das nächste ist
LSB?
Wie trage ich dafür sorge, dass alles an der richtigen Stelle im EEPROM
gespeichert wird? Schickt man die Stelle irgendwie passend zur Variable
mit (den Array zählt man sinnvollerweise durch hätte ich gesagt, aber
wie macht man es bei den Konfig-Variablen, die teilweise nicht
nacheinander im EEPROM liegen)?
Ich weiß, das sind jetzt vielleicht ein paar viele Fragen, aber
vielleicht hat der ein oder andere ein bisschen Zeit hier Erfahrung zu
teilen.
Danke.
Zahlen nach ASCII zu konvertieren ist Blödsinn, es sei denn, Du willst
sie auf einem PC in einem terminal-Programm anschauen.
Übertrage das Array so wie es ist. Als Kontrolle kannst Du die Länge des
Arrays mitübertragen, eine Checksum über alle Bytes anhängen, denk Dir
einfach was sinnvolles aus.
Eine Steinzeitmethode wäre z.B. ein Byte zu senden, der µC muß es
zurücksenden, danach wird erst das nächste Byte gesendet. Geht ist
langsam, aber wenns Du Angst vor Datenverlusten hast (wieso eigentlich,
wenn das Design gut ist?), dann wär das eine Methode, die beruhigt.
Hier mal zum Vergleich 2 Varianten:
1. ASCII-Kodierung
Vorteil: es lässt sich einfach ein relativ sicheres Protokoll
realisieren, da Du eindeutige Steuerzeichen zur Verfügung hast (z.B. STX
als Beginn usw.).
Nachteil: >= doppelte Länge des Datensatzes
2. Code-Transparent
Vorteil: kleine Datensatzlänge
Nachteil: ein Protokoll ist schwieriger zu realisieren. Erkennung von
Beginn des Datensatzes oder Verlust von Daten muss z.B. durch Messung
der Zeiten zwischen 2 UART-Zeichen erfolgen. Das bedeutet dann für den
Sender: zwischen 2 Datensätzen ist immer eine Pause erforderlich,
innerhalb des Datensatzes ist keine oder nur ein deutlich kleinere Pause
erlaubt.
In beiden Fällen ist aber immer eine Time-Out-Erkennung nötig, um eine
Unterbrechung des Datenstroms zu erkennen.
Weiter Datensicherungen sind dann nach Bedarf und Geschmack: Checksum
gegen Bitverfälschungen, Quittung gegen Datenverlust ... Das hängt dann
davon ab, wie störanfällig die Übertragung ist und welche Ansprüche an
die Datensicherheit gestellt werden.
Problematisch ist in jedem Fall eine variable Datensatzlänge, da Fehler
schwieriger zu erkennen sind. Sie sollte daher nach Möglichkeit
vermieden werden.
Gruß Dietrich
Martin schrieb:> Jetzt ist meine Frage, wie baue ich das Protokoll auf. Habe ich der> Suche ebenfalls richtig entnommen, dass man eine 8-bit Zahl am besten in> ein ASCII-Zeichen konvertiert, welche dann als 1 Zeichen gesendet werden> kann und der µC das wieder rückkonvertiert zu einer Zahl und diese> speichert?
Ja, am besten denkst Du Dir ein "Message" basiertes Protokoll aus, wobei
diese Message in sich geprüft werden kann. Wenn Du beispielsweise ein
Array mit 200 Integer-Werten übertragen möchtest, könnte eine zu
übertragende Message z.B. so aussehen:
Startbytes - 2 Bytes (zwei beliebige Werte nach Deiner Wahl)
Messagelänge - 2 Bytes (die Anzahl der nachfolgenden Bytes als Integer)
Nutzbytes - 400 Bytes (die 200 zu übertragenden Integer-Werte)
Prüfsumme - z.B. 4 Bytes (die 200 Integer-Werte als Long-Integer
aufsummiert)
Die Empfangsroutine lauert in Sendepausen nun immer darauf, ob die
beiden Startbyte ankommen, und danach müssen in schneller Folge alle
anderen Bytes eintreffen. Tritt ein Timeout auf, lauert der Empfänger
einfach wieder auf die nächsten Startbyte nach einer Sendepause.
Programmlogik des Empfängers dann etwa so:
- Empfange erstes Startbyte
- Wenn erstes Startbyte OK, weitermachen, sonst zurück auf Anfang
- Empfange zweites Startbyte
- Wenn zweites Startbyte OK, weitermachen, sonst zurück auf Anfang
- Empfange Längenwert und fange an zu zählen bei 0
- Empfange Nutzbytes und zähle die Zahl der empfangenen Bytes mit
- Empfange Prüfsumme und zähle die Zahl der empfangenen Bytes mit
- Wenn alle Bytes entsprechend der Länge empfangen, prüfe die Prüfsumme
- Wenn Prüfsumme OK, dann Daten einwandfrei empfangen
- Wenn Prüfsumme nicht OK oder ein Timeout beim Empfangen auftrat ==>
Daten verwerfen
Falls irgendwo beim Messageempfang ein Timeout auftritt: Zurück auf
Anfang.
Du müßtest dann eben nur die beiden Startbytes festlegen, die Art wie
die Prüfsumme (oder ein CRC-Wert) gebildet wird und wie lang der
zeitliche Abstand zwischen zwei Bytes innerhalb eines Message-Blocks
sein darf (Timeout-Zeit).