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
Das mit dem delay ... das kannst du dir sparen
1 | uint8_t USART_ReveiveTimeDelay(uint8_t delay_ms) |
2 | {
|
3 | uint8_t i; |
4 | |
5 | //Mindestzeit warten
|
6 | for(i=0; i < delay_ms; i++) |
7 | _delay_ms(1); |
8 | |
9 | //Noch immer keine Daten empfangen?
|
10 | if( ! UCSRA & (1<<RXC)) |
11 | return NULL; |
12 | |
13 | return UDR; |
14 | }
|
15 | |
16 | char* USART_Gets(void) |
17 | {
|
18 | static char string[MAX_RECEIVE_STRINGSIZE]; |
19 | uint8_t i; |
20 | |
21 | //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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.