Forum: Mikrocontroller und Digitale Elektronik UART Zeichenkette ohne Endzeichen


von Jakob (Gast)


Lesenswert?

Hallo, nur ne Frage bevor ich damit anfange.
Ich bekomme über'n Rs232 eine Zeichenkette, diese hat aber kein 
Endzeichen, sondern es kommt kein Zeichen mehr.

Ich hab mir überlegt mit ner Schleifen die Zeichen hintereinander in ein 
Arry zu schreiben. Somit wäre es gelöst aber umständlich, weil ich es 
später wieder aus geben möchte.

Funktioniert dies auch mit net geänderten Version von :
1
void uart_gets( char* Buffer, uint8_t MaxLen )
2
{
3
  uint8_t NextChar;
4
  uint8_t StringLen = 0;
5
  
6
  NextChar = uart_getchar();         // Warte auf und empfange das nächste Zeichen
7
  
8
  // Sammle solange Zeichen, bis:
9
  // * entweder das String Ende Zeichen kam
10
  // * oder das aufnehmende Array voll ist
11
  while( NextChar != '\r' && StringLen < MaxLen - 1 ) {
12
    *Buffer++ = NextChar;
13
    StringLen++;
14
    NextChar = uart_getchar();
15
  }
16
  
17
  // Noch ein '\0' anhängen um einen Standard
18
  // C-String daraus zu machen
19
  *Buffer = '\0';
20
}

von npn (Gast)


Lesenswert?

Jakob schrieb:
> diese hat aber kein Endzeichen, sondern es kommt kein Zeichen mehr.

Nie mehr?
Sorry, aber die Frage drängt sich auf. Denn irgendwann mußt du doch mal 
entscheiden, was zu tun ist mit den bisher empfangenen Zeichen. Es kann 
ja auch sein, daß der sendende Part einfach mal paar Sekunden mit etwas 
anderem beschäftigt ist und dann anschließend noch der Rest der 
Zeichenkette kommt. In meinen Augen muß es entweder ein Ende-Zeichen 
geben (0x00) oder die Länge der Zeichenkette muß mit übergeben werden 
(wie bei Pascal-Strings). Nur so kann man sagen, daß die Zeichenkette 
komplett übertragen wurde.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

npn schrieb:
> In meinen Augen muß es entweder ein Ende-Zeichen
> geben (0x00) oder die Länge der Zeichenkette muß mit übergeben werden
> (wie bei Pascal-Strings).

Naja, es muss ja nicht 0x00 sein. Die Beispielfunktion oben testet auf 
'\r', was in vielen Fällen auch sinnvoll ist.

Wenn man kein Ende-Zeichen bekommt, muss man es mit einem Timeout 
machen.

Also:

  - Timer aufsetzen, Zähler hochzählen.
  - Wenn Zähler einen Grenzwert erreicht -> Timeout!
  - Wenn Timeout, dann String terminieren und Return.

von spontan (Gast)


Lesenswert?

@jakob. Die Software hängt im Abfragen des UART. Was soll passieren, 
wenn das Endekriterium nicht erfüllt wird?

Im Augenblick passiert nix, der Prozessor hängt in der Schleife.

@npn: Es gibt viele Übertragungsprotokolle, die mit einem Timeout 
arbeiten. Kommt eine gewisse Zeit (protokollabhängig) kein Zeichen, so 
ist das Telegramm übertragen, oder fehlerhaft, das entscheidet dann die 
Decoder-Software.

von Peter II (Gast)


Lesenswert?

spontan schrieb:
> @npn: Es gibt viele Übertragungsprotokolle, die mit einem Timeout
> arbeiten.

nenn doch mal ein paar Beispiele?

von npn (Gast)


Lesenswert?

Frank M. schrieb:
> npn schrieb:
>> In meinen Augen muß es entweder ein Ende-Zeichen
>> geben (0x00) oder die Länge der Zeichenkette muß mit übergeben werden
>> (wie bei Pascal-Strings).
>
> Naja, es muss ja nicht 0x00 sein. Die Beispielfunktion oben testet auf
> '\r', was in vielen Fällen auch sinnvoll ist.
>
> Wenn man kein Ende-Zeichen bekommt, muss man es mit einem Timeout
> machen.
>
> Also:
>
>   - Timer aufsetzen, Zähler hochzählen.
>   - Wenn Zähler einen Grenzwert erreicht -> Timeout!
>   - Wenn Timeout, dann String terminieren und Return.

Ja, okay. Klar geht auch jedes andere Zeichen, was sonst nicht im String 
vorkommt. Das mit dem 0x00 war nur ein Beispiel, weil es ja naheliegend 
ist, es als c-String zu übertragen.
Und mit dem Timeout kann man lediglich sagen: "Ich höre jetzt auf zu 
warten". Aber anschließend kann ja vom Sender trotzdem noch der Rest der 
Zeichenkette kommmen, der eigentlich noch dazu gehört. Da würde ich den 
Timeout nur als "Reißleine" sehen, damit die gesamte Kommunikation nicht 
hängenbleibt, wenn die Übertragung abreißt oder für eine bestimmte Zeit 
unterbrochen wird. Diese Reißleine sollte man schon mit einbauen, das 
ist klar. Aber sie stellt keine Erkennung des String-Endes dar.

von Jakob (Gast)


Lesenswert?

Das mit dem Timer setzten klingt gut. dies werde ich dann ausprobieren.

Aber auch mal :
1
  while( NextChar != '0x00' && StringLen < MaxLen - 1 ) {
2
    *Buffer++ = NextChar;
3
    StringLen++;
4
    NextChar = uart_getchar();

Dann schreibt er ja nur dann in den String wenn Zeichen ankommen, sobald 
dann kein Zeichen kommt müsste er aufhören Zeichen zulesen und den 
String "Ausgeben"

Danke für die Tipp's

von Karl H. (kbuchegg)


Lesenswert?

Jakob schrieb:

>
1
  while( NextChar != '0x00' && StringLen < MaxLen - 1 ) {
2
>     *Buffer++ = NextChar;
3
>     StringLen++;
4
>     NextChar = uart_getchar();
>
> Dann schreibt er ja nur dann in den String wenn Zeichen ankommen,

Auch ein Zeichen mit dem ASCII Wert 0 ist ein Zeichen.

So etwas wie ein Zeichen, dass kein Zeichen darstellt, gibt es nicht. 
Entweder es ist ein Zeichen angekommen oder es ist keines angekommen. 
Wenn aber eines gekommen ist, dann war es ein Zeichen.

D.h. wenn schon, dann muss die uart_getchar Funktion bereits diese 
Unterscheidung machen und dem Aufrufer mitteilen: es ist kein Zeichen 
eingetroffen. Die Fleury UART Funktionen machen das zum Beispiel.

> dann kein Zeichen kommt müsste er aufhören Zeichen zulesen und den
> String "Ausgeben"
und nein. das ist im allgemeinen keine gute Idee. Denn dann muss es eine 
vereinbarten Zeitraum zwischen Empfänger und Sender geben. Der Sender 
muss garantieren, dass er in einem bestimmten Zeitraum mit der Antwort 
beginnt und er muss garantieren, dass zwischen der Übertragung 2-er 
Zeichen nicht mehr als x Zeiteinheiten vergehen. Da die eigentliche 
Übertragung sehr viel langsamer geht, als ein µC rechnet kannst du nicht 
einfach sagen: wenn mit dem nächsten getchar() nichts gekommen ist, dann 
erkläre ich den String als beendet. Das ist als ob du mittels berittenem 
Boten zwischen Wien und Moskau kommunizierst. 5 Sekunden nachdem ein 
Reiter eingetroffen ist erklärst du die Übertragung als beendet, dabei 
hängt der nächste Reiter einfach nur in einem Vorort fest und dessen 
Teil der Nachricht müsste auch noch mit  dazu gehören. Du musst da schon 
angemessene Zeiträume benutzen. Bei berittenen Reitern werden das wohl 
ein paar Tage sein, die du einräumen musst.

Wenn du auf das Protokoll noch Einfluss nehmen kannst, dann dräng auf 
ein Ende-Zeichen, dass dir unmissverständlich mitteilt: Jetzt ist die 
Übertragung vollständig.

von Steffen R. (steffen_rose)


Lesenswert?

npn schrieb:
> Und mit dem Timeout kann man lediglich sagen: "Ich höre jetzt auf zu
> warten". Aber anschließend kann ja vom Sender trotzdem noch der Rest der
> Zeichenkette kommmen, der eigentlich noch dazu gehört. Da würde ich den
> Timeout nur als "Reißleine" sehen, damit die gesamte Kommunikation nicht
> hängenbleibt, wenn die Übertragung abreißt oder für eine bestimmte Zeit
> unterbrochen wird. Diese Reißleine sollte man schon mit einbauen, das
> ist klar. Aber sie stellt keine Erkennung des String-Endes dar.

Bei einer zeitlichen Unterbrechung der Übertragung kann man nicht sicher 
sagen, ob der später empfangene Rest noch zum bereits empfangenen Anfang 
gehört oder ob es der Rest einer späteren Übertragung ist.
Die ungeplante Unterbrechung muss einen Grund haben und man sollte hier 
auch mit Störungen rechnen. Und es ist somit nicht nur eine Reißleine um 
das Programm am Laufen zu halten.

von Michael K. (Gast)


Lesenswert?

Frank M. schrieb:
> Wenn man kein Ende-Zeichen bekommt, muss man es mit einem Timeout
> machen.

Immer, oder ?
Was wenn das Ende Zeichen nicht kommt weil es verloren geht, oder wegen 
CRC Fehler die Information über die Telegrammlänge unzuverlässig ist ?
Wie entscheide ich dann wann eine neuer String kommt ?

von Steffen R. (steffen_rose)


Lesenswert?

Michael Knoelke schrieb:
> Wie entscheide ich dann wann eine neuer String kommt ?

Häufig wird nicht nur ein Ende-Zeichen, sondern auch ein Anfangszeichen 
definiert.

Edit:
Da es hier um ASCII zu gehen scheint, verweise ich mal auf STX und ETX.
http://de.wikipedia.org/wiki/Steuerzeichen

von npn (Gast)


Lesenswert?

Jakob schrieb:
> Ich bekomme über'n Rs232 eine Zeichenkette, diese hat aber kein
> Endzeichen, sondern es kommt kein Zeichen mehr.

Die Frage ist ja erstmal, wo kommen die Zeichen her? Welches Gerät 
sendet die? Hast du die Möglichkeit, auf das Sendeformat Einfluß zu 
nehmen? Wenn ja, dann würde ich auf jeden Fall ein "String-Ende-Zeichen" 
einbauen. Oder noch besser, wie es Steffen vorgeschlagen hat, mit 
Steuerzeichen wie <stx> und <etx> arbeiten.

Wenn du diese Möglichkeit nicht hast, kannst du dann eine Aussage 
treffen, wann eine Zeichenkette als "beendet" erklärt werden kann? Das 
heißt, wenn kein Zeichen mehr kommt, nach welcher Zeit man davon 
ausgeht, daß später kommende Zeichen dann schon zu einer neuen 
Zeichenkette gehören?

von Jakob (Gast)


Lesenswert?

Ich bekomme das Gerät erst später und es nicht möglich etwas dran zu 
ändern.
Ich wollte nur Infos sammeln, denn dies wäre eine Möglichkeit die 
eintreffen könnte. Kann auch sein das nur eine bestimmt Anzahl an 
Zeichen gesendet wird, das wäre dann sehr praktisch.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Michael Knoelke schrieb:
> Frank M. schrieb:
>> Wenn man kein Ende-Zeichen bekommt, muss man es mit einem Timeout
>> machen.
>
> Immer, oder ?

Wenn kein Ende-Zeichen vorgesehen ist, bleibt nur noch eine 
Timeout-Behandlung. Nichts anderes habe ich gesagt.

> Was wenn das Ende Zeichen nicht kommt weil es verloren geht,

Das ist doch eine ganz andere Situation. Ich habe auf die Situation 
geantwortet, dass es kein Ende-Zeichen im Protokoll gibt.

Du beschreibst aber nun die Situation, dass es ein Ende-Zeichen gibt, 
dieses aber verloren gehen kann. Nebelkerze?

Glücklicherweise ist die Methode des Timeouts dann trotzdem anwendbar - 
mit einem Unterschied: Bei einem Protokoll ohne Ende-Zeichen bedeutet 
ein Timeout die Validierung des Strings. Wenn es aber ein Ende-Zeichen 
gibt, das aber verloren gegangen ist, ist keine Validierung möglich. 
In diesem Fall muss die empfangene Nachricht verworfen und neu 
angefordert werden.

> oder wegen
> CRC Fehler die Information über die Telegrammlänge unzuverlässig ist ?

nicht validieren, verwerfen.

> Wie entscheide ich dann wann eine neuer String kommt ?

Sorry, bezieht sich Deine Frage jetzt auf ein Protokoll mit Ende-Zeichen 
oder ohne? Deine Nebelkerze oben lässt da keine eindeutigen Schlüsse zu.

von npn (Gast)


Lesenswert?

Jakob schrieb:
> Kann auch sein das nur eine bestimmt Anzahl an
> Zeichen gesendet wird, das wäre dann sehr praktisch.

Du meinst, eine bestimmte (feste) Anzahl, dann eine längere Pause, dann 
wieder diese feste Anzahl usw...?

von Peter II (Gast)


Lesenswert?

Jakob schrieb:
> Ich bekomme das Gerät erst später und es nicht möglich etwas dran zu
> ändern.

was denn für ein Gerät? Gibt es dazu keine Bezeichnung?

von Jakob (Gast)


Lesenswert?

Es wird eine Frequenz über den Bus mitgeteilt.

@ npn, ja es gibt feste Pause aber ob es nun feste Anzahl an Zeichen 
gibt ist die Frage.

Werde jetzt mal warten und mich dann wenn ich damit anfange melden.

von Karl H. (kbuchegg)


Lesenswert?

Jakob schrieb:
> Es wird eine Frequenz über den Bus mitgeteilt.
>
> @ npn, ja es gibt feste Pause aber ob es nun feste Anzahl an Zeichen
> gibt ist die Frage.
>
> Werde jetzt mal warten und mich dann wenn ich damit anfange melden.


Wenn das Teil kommt und es im Protokoll tatsächlich ausser Timeout keine 
Möglichkeit zur Synchronisation gibt, würde ich mal heftig fluchen und 
mich nach einem anderen Teil umsehen.

Absichtlich und ausschliesslich per Timeout zu synchronisieren ist die 
schlechteste aller Möglichkeiten und eigentlich nur mit dem Hintergrund 
der Faulheit der Programmierer zu verstehen, die den Sendecode 
geschrieben haben. Denn damit bürdet man dem Empfangscode eine Menge 
Stolpersteine auf. Ein Protokolldesigner hat immer beides im Auge: 
Sender und Empfänger. Wer auf Timeout setzt, ignoriert ganz einfach den 
Empfänger.

von Martin S. (led_martin)


Lesenswert?

Also bei RS485-Kommunikation ist das mit dem Time Out recht gängig. Da 
geht es oft um kurze Telegramme mit Binärdaten, bei Telegramm-Längen von 
4 - 8 Bytes will man nicht mit einer Codierung anfangen, die einem Werte 
'freischaufelt', die dann in den Nutzdaten nicht mehr vorkommen, und als 
Ende-Kennung genutzt werden können. Allerdings ist das letzte Byte meist 
ein Prüf-Byte, so daß der Empfänger prüfen kann, ob das Telegramm 
vollständig, und fehlerfrei ist. Bei ASCII würde ich aber auch mit einem 
Ende-Zeichen arbeiten, Auswahl gibt es da ja genug. Aber wenn der Sender 
gegeben, und nicht änderbar ist ...

Mit freundlichen Grüßen - Martin

von Peter II (Gast)


Lesenswert?

Martin Schlüter schrieb:
> Also bei RS485-Kommunikation ist das mit dem Time Out recht gängig. Da
> geht es oft um kurze Telegramme mit Binärdaten, bei Telegramm-Längen von
> 4 - 8 Bytes will man nicht mit einer Codierung anfangen, die einem Werte
> 'freischaufelt', die dann in den Nutzdaten nicht mehr vorkommen, und als
> Ende-Kennung genutzt werden können

auch dort wird das Timout für den Fehlerfall verwendet und nicht für die 
Endeerkennung. Man kann sonst den Bus zu wenig auslasten weil man immer 
Zwangspausen einhalten muss.

Und man muss auch kein wert freischaufeln, dafür kann man ein einfaches 
"escapen" verwenden.

von Peter II (Gast)


Lesenswert?

> Also bei RS485-Kommunikation ist das mit dem Time Out recht gängig
nachtrag:

dort wird aber dafür oft ein Startzeichen + Länge + CRC verwendet, dann 
braucht man auch kein Endezeichen.

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.