UART Zeichenkette ohne Endzeichen

Gast #3974242
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
}
Gast #3974256
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.
Moderator Persönliche Seite #3974265
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.
Gast #3974272
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.
Gast #3974285
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.
Gast #3974287
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
#3974315
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.
#3974319
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.
Gast #3974354
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?
Moderator Persönliche Seite #3974414
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.
#3974445
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.
#3974505
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
Gast #3974510
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren