Hallo,
ich tue mir gerade etwas schwer mit meinem UART Protokoll.
Nach vielem Lesen von Beiträgen habe ich mich für mein erstes Protokoll
für ASCII-Format Übertragung entschieden, da es sowieso nicht
zeitkritisch ist und es einfacher und lesbar ist. Ich denke für ein
Anfänger sicherlich nicht verkehrt, da auch alle Steuerzeichen zur
Verfügung stehen und nichts substituiert werden muss.
Mein Ziel ist es, vom PC aus Daten zu senden per RS232, die 8-bit und
16-bit Werte sind (natürlich vorher gewandelt in strings). Der µC (AVR
Atmega88) soll die Daten aufnehmen und ins EEPROM schreiben/speichern.
Implementiert habe ich die UARTlib von Peter Fleury mit FIFO Puffer.
Also Protokoll habe ich mir derzeit folgendes überlegt:
- µC Startet mit XON und gibt somit dem PC frei, dass er Daten senden
kann.
- Kommandobit: Auch case Unterscheidung, je nach Case, soll der Wert
einer bestimmten Variable zugeordnet werden, z.B. case(1) = Wert in
fooByte1, case(2) Wert in fooWord1, case(3) Wert in fooByte2 usw.
- Daten
- PC setzt seinen Status auf XOFF wartet bis er wieder ein XON erhält
vom µC erhält für den nächsten Datensatz
- µC holt die Daten aus dem Puffer und schreibt sie in das EEPROM. Wenn
dies beendet ist, sendet er wieder XON
Woher weiß der µC aber, wann aber z.B. das Kommandobit feritg übertragen
wurde und wann Daten kommen und wann Daten zu Ende sind?
Danke.
Thorben schrieb:> - µC Startet mit XON und gibt somit dem PC frei, dass er Daten senden> kann.
Das ist eigentlich nicht Sinn der Sache bei XON/XOFF
Warum soll denn der PC nicht ständig senden dürfen? Du hast doch mit der
Fleury LIb sowieso eine FIFO dazwischen, die in den kurzen Pausen, in
denen dein µC was anderes macht, die Zeichen zwischenzeitlich aufnimmt.
> - Kommandobit:
Wieso Bit?
> Auch case Unterscheidung, je nach Case, soll der Wert> einer bestimmten Variable zugeordnet werden, z.B. case(1) = Wert in> fooByte1, case(2) Wert in fooWord1, case(3) Wert in fooByte2 usw.
Du denkst schon viel zu technisch.
> Woher weiß der µC aber, wann aber z.B. das Kommandobit feritg übertragen> wurde und wann Daten kommen und wann Daten zu Ende sind?
Du bist nicht mehr mit Commandozeilen aufgewachsen, stimmts?
Da wusste jeder, dass man an der Command-Line ein Kommando eingibt und
wenn man fertig ist, drückt man auf Return. Return ist ein Zeichen wie
jedes andere auch. Aber es signalisiert dem empfangenden Programm: Jetzt
ist meine Eingabe fertig - du kannst anfangen sie auszuwerten.
Der PC sendet zb den 'Text'
Timeout=129<Return>
Der µC sieht sich den Text an (nachdem er die Zeile komplett empfangen
hat, was er am Erhalt des Return feststellt), zerlegt sie am '=' in 2
Teile, dem 'Timeout' und dem '129'. Durch Textvergleich findet er raus,
dass bei 'Timeout' eine bestimmte Variable gemeint ist und dass die
einen neuen Wert bekommen soll. Also wird der 2.te Text, "129" erst mal
in eine Zahl umgewandelt 129, und diese Zahl dann an die Variable
zugewiesen.
Und wenn der PC die LED 5 einschalten will, dann schickt er vielleicht
den Text
LEDON 5<Return>
etc. etc.
Denk dir was aus, wie die Texte aussehen sollen. Wenn der PC wissen
will, ob LED 3 eingeschaltet ist oder nicht, dann schickt er vielleicht
? LEDON 3<Return>
Und der µC anwortet mit
ON<Return>
oder
OFF<Return>
oder
0<Return>
oder
1<Return>
oder wie auch immer. Da ist deine Phantasie gefragt.
Ein HP7475 Plotter wird zb so gesteuert
PU;
PA3000,2000;
PD;
PA1000,2000;PA1000,1000;PU;
hier ist also nicht <Return> der Trenner sondern ';'.
PU bedeutet 'Pen Up'
PD bedeutet 'Pen Down'
PA bedeutet 'Position Absolut' wobei 2 Zahlenangaben zu machen sind,
nämlich die X und die Y Position, an die der Stift fahren soll.
Karl Heinz Buchegger schrieb:> Warum soll denn der PC nicht ständig senden dürfen? Du hast doch mit der> Fleury LIb sowieso eine FIFO dazwischen, die in den kurzen Pausen, in> denen dein µC was anderes macht, die Zeichen zwischenzeitlich aufnimmt.
Weil ich in das EEPROM schreiben will und das 2-4ms in Anspruch nimmt.
Um einen Array mit 200 Stellen und 16-bit (den ich unter anderem senden
will) werten zu übertragen, bräuchte ich daher doch einen großen Puffer
(der PC sendet sicherlich schneller). Um den Überlauf des Puffers zu
verhindern, wollte ich diese Flusskontrolle integrieren.
Karl Heinz Buchegger schrieb:> Du bist nicht mehr mit Commandozeilen aufgewachsen, stimmts?
Ja, das stimmt :-)
Das mit Return verstehe ich nicht ganz. Wenn ich doch Variablenwerte
sende, z.b. ein uint8_t test = 123, dann bekomme ich doch die
Zeichenfolge '1' '2' '3' '\0' vom UART. Meinst du mit Return die
abschließende 0?
Wie sollte ich das nun am besten angehen?
Hey Torben,
durch Return wird das Zeichen angehängt '\r'. Dann einfach das
Empfangsregister immer nach diesem Zeichen mit if abfragen. Wenn TRUE
dann weißt du wann er fertig ist.
Thorben schrieb:> Karl Heinz Buchegger schrieb:>> Warum soll denn der PC nicht ständig senden dürfen? Du hast doch mit der>> Fleury LIb sowieso eine FIFO dazwischen, die in den kurzen Pausen, in>> denen dein µC was anderes macht, die Zeichen zwischenzeitlich aufnimmt.>> Weil ich in das EEPROM schreiben will und das 2-4ms in Anspruch nimmt.
Ja und?
Dann schickt eben der PC das Kommando weg und wartet auf Antwort vom µC.
Der PC schickt
Timeout=129<Return>
und der µC muss das Kommando mit einem
OK<Return>
quittieren.
Und solange der PC das OK (oder ein NAK im Fehlerfall) nicht erhält,
macht er nicht weiter.
Thorben schrieb:> Um einen Array mit 200 Stellen und 16-bit (den ich unter anderem senden> will) werten zu übertragen,
Kein Mensch sagt, dass du die 200 Werte in einem Rutsch übertragen
musst.
> sende, z.b. ein uint8_t test = 123, dann bekomme ich doch die> Zeichenfolge '1' '2' '3' '\0' vom UART.
Du bekommst kein \0 von der UART.
Woher soll denn die UART wissen, wann eine Übertragung fertig ist? Auch
eine µC-UART kann nicht in die Zukunft schauen.
> Meinst du mit Return die> abschließende 0?
\r oder \n
Karl Heinz Buchegger schrieb:> Thorben schrieb:>>> Um einen Array mit 200 Stellen und 16-bit (den ich unter anderem senden>> will) werten zu übertragen,>> Kein Mensch sagt, dass du die 200 Werte in einem Rutsch übertragen> musst.
Dann gibt es eben zum Beispiel einen 'Datenblock', der mehrere Werte
umfassen kann. Zb maximal 16 Werte
Der PC schickt
BLOCK 1; 0, 129, 512, 867, 378, 93, 93, 23, 0, 0, 8, 125, 12, 18, 14,
18<Return>
Der µC empfängt die Zeile holt sich die Blocknummer vor dem ; raus (hier
Block 1), extrahiert die 16 Werte und schreibt sie ins EERPOM, wobei ihm
die Blocknummer sagt, wo die Werte hinmüssen. Wenn er damit fertig ist,
schickt er ein
OK<Return>
zum PC zurück, woraufhin der ihm den nächsten Block schickt.