Mahlzeit Forum!
Zuerst habe ich mal eine allgemeine Frage:
Ich nutze das Programme Termite zur Übertragung an die RS232
Schnittstelle. Wenn ich jetzt unter Windows einen langen String
übertrage, liege ich dann richtg mit der Annahme dass der String zuerst
beim Sender gebuffert wird und dann erst byteweise an den Empfänger
gelangt? Der Buffer im ATmega32 ist ja nur 1 Byte groß, wenn ich mich
jetzt nicht irre.
So, nun zu meinem spezifischen Problem (sh. Code im Anhang):
Ich habe das Stringübertragungsproblem so gelöst, dass der User nach
jedem Befehl einen Strichpunkt am Ende schreiben muss. Mit Strichpunkt
passt alles wunderbar.
Aber: Alle Eingaben die hintereinander OHNE Strichpunkt am Ende
übertragen werden, werden aneinander gehängt bis eine Eingabe mit
Strichpunkt erfolgt und dann laut meinem Code ausgegeben.
Was ich nun erreichen will ist, dass wenn der User mal einen Strichpunkt
vergisst, ich den Buffer dann lösche und somit nicht die nächste Eingabe
verfälsche.
Mein Ansatz wäre: Wenn "lange" kein Zeichen mehr kommt (also während der
User seinen nächsten String eingibt), werte ich das als Syntaxfehler und
lösche den Buffer.
Aber ich finde die Methode irgendwie unsauber, fällt jemanden vielleicht
etwas Eleganteres ein?
Vielen Dank schonmal!
Mfg
Das Arbeiten mit Strings ist eigentlich immer eine Zustandsmaschine. Und
die muss das Ende richtig detektieren. Eine Metode ist mit einem
Terminator zu arbeiten, einer Null, oder sonstwas. Ich bevorzuge Stings
mit der Groesse zuerst. Voraussetzung ist, dass man weiss es folgt nun
ein String. Falls amn weiss, das es ein sogenannter Kurzstring ist, dh
die Laenge ist kuerzer als 255 byte, dann sendet man dieses Byte zuerst,
dann den String. Falls der String lenger sein kann. zB weil's ein
Textfile ist, dann wuerd ich die Groesse als 2, 3, oder 4 byte
vorspannen, und den String hinterher.
Auf diese Weise kann man einen Timeout machen, sagen wir 100 byte lang
kommt nichts, dann weiss der Empfaenger, nun ist was nicht gut, zB das
Device wurde abgezogen, hat keinen Saft mehr oder sonstwas.
Befehls-Terminierung vergessen -> Syntaxfehler (-> dem User eine
reinhauen) -> Bearbeitung abbrechen. Alles andere ist Unsinn.
Was Du noch berücksichtigen musst ist die Tatsache, dass Dein Puffer in
der Größe beschränkt ist (bzw. sein muss, die Hardware gibt halt nur
endlich viel her). Ergo wenn Du einen Pufferüberlauf erkennst (weil zwei
Befehle drin stehen), dann erst eine Fehlermeldung ausgeben (, dem User
eine reinhauen) und dann den Puffer löschen. Alles andere ist Unsinn.
Wenn zufällig zwei Befehle (ohne Terminierung dazwischen) in den Puffer
passen, dann wirst Du bei der Auswertung feststellen, dass der erste
fehlerhaft aufgebaut ist (weil hinten noch der zweite Befehl mit
dranhängt) -> Syntaxfehler, rest wie oben.
Fang nicht an zu viel Intelligenz einzubauen, das einzige worauf man
sich verlassen kann ist die Tatsache, dass es immer einen noch dümmeren
User gibt. Deswegen: Syntaxfehler -> Meldung -> nochmal.
Danke, sowas in der Richtung habe ich vermutet. Wäre ja Blödsinn sich
für immer dümmere User, noch mir Hirnschmalz in die Sache zu
verschwenden =)
Also, im Anhang der neue Code.
Vielen Dank!
Mfg
//Warten bis das erste Zeichen des Strings übermittelt wird
22
while(!(UCSRA&(1<<RXC)));
23
24
for(i=0;i<=MAX_RECEIVE_STRINGSIZE-1;i++)
25
{
26
//Maximaler Zeitabstand zwischen zwei Zeichen
27
string[i]=USART_ReveiveTimeDelay(1);
Kein Mensch kann 1000 Zeichen in der Sekunde tippen, du verlangst hier
zuviel. Timeouts macht man anders. Spars dir hier aber: Einen Benutzer
treibt man nicht ohne zwingenden Grund in einen Timeout hinein und wenn
dann ist der Timout im Minutenbereich, so 10 bis 30 Minuten. Irgendwas
in der Größenordnung. Dein Benutzer wird dir nämlich schön dankbar sein,
wenn er gerade mühsam seine Eingabe gemacht hat und kurz bevor er damit
fertig ist klingelt das Telefon. Wenn du deinem Benutzer etwas gutes tun
willst, dann ermögliche ihm einfache Editiermöglichkeiten, zb indem du
Backspace auswertest.
Ich verlange auch nicht 1000 Zeichen in der Sekunde!
Bei meinem Terminalprogramm gibt der Benutzer zuerst seinen ganzen
Befehl in einen Zeile und drückt dann auf Enter und es wird gesendet =)
Ich schätze das ist generell bei Terminalprogrammen so üblich.
Also, diese Funktion macht folgendes:
Sie wartet solange bis das erste Zeichen im Empfängerbuffer vorliegt,
dann liest sie alle 1ms ein weiteres Zeichen aus dem Buffer, was ja kein
Problem ist, da der ganze Befehl ja schon eingetippt ist. Ich stelle
hier also nur Forderungen an die Baud-Rate, und nicht an den Benutzer =)
Ich habe sie schon getestet, ich sehe eigentlich keine gravierende
Einschränkung für den Benutzer.
Mfg
Christoph
Christoph A. schrieb:> Ich schätze das ist generell bei Terminalprogrammen so üblich.
Nö. Eigentlich wird jede gedrückte Taste sofort über UART
rausgeschmissen.
Gruß
Jobst
Jobst M. schrieb:> Christoph A. schrieb:>> Ich schätze das ist generell bei Terminalprogrammen so üblich.>> Nö. Eigentlich wird jede gedrückte Taste sofort über UART> rausgeschmissen.>>> Gruß>> Jobst
Hmm, dann versuche ich das Problem anders zu lösen.
Ich hätte aber zuerst noch eine Versändnisfrage zu der Datenübertragung
über die serielle Schnittstelle :
Wenn ich jetzt also ein Wort eingebe und es wird tatsächlich jeder
Buchstabe unmittelbar nach der Eingabe gesendet, landet der erste
Buchstabe sofort im UDR-Register des Atmega32, die anderen warten noch
im Buffer des Senders oder?
Mfg
Christoph A. schrieb:> Wenn ich jetzt also ein Wort eingebe und es wird tatsächlich jeder> Buchstabe unmittelbar nach der Eingabe gesendet, landet der erste> Buchstabe sofort im UDR-Register des Atmega32, die anderen warten noch> im Buffer des Senders oder?
Vermutlich warten sie dort noch nicht, weil sie noch nicht getippt
wurden.
Bei 9600Bd z.B. ist das eingetippte Zeichen nach ca. 1ms im UDR
Gruß
Jobst
Christoph A. schrieb:> Ich verlange auch nicht 1000 Zeichen in der Sekunde!
Doch das tust du.
Du gestehst deinem Benutzer gerade einmal
1
string[i]=USART_ReveiveTimeDelay(1);
1 Millisekunde Timeout Zeit zu.
> Bei meinem Terminalprogramm gibt der Benutzer zuerst seinen ganzen> Befehl in einen Zeile und drückt dann auf Enter und es wird gesendet =)> Ich schätze das ist generell bei Terminalprogrammen so üblich.
Ist es nicht.
ABer das hat Jobst schon angesprochen.
Du solltest weniger Annahmen treffen und vor allen Dingen erst einmal
das lokale Echo in deinem Terminalprogramm abschalten.
Eine eigene Frage?
Dieser Thread ist über 16 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.