Forum: Mikrocontroller und Digitale Elektronik Daten über usart empfangen/ wann Datenende erreicht?


von Chris T. (chris0086)


Lesenswert?

Hallo Leute ich habe folgendes Problem :
Ich möchte Daten von einer Steuerung über die serielle Schnittstelle 
empfangen. Soweit kein Problem bei Trockenübungen am Pc.
hier meine Empfangsroutine:
1
 void usart_gets( char* Buffer, uint8_t MaxLen )
2
    {
3
      uint8_t NextChar;
4
      uint8_t StringLen = 0;
5
      int wert = 0;
6
      NextChar = usart_getc();         // 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 != '\n' && StringLen < MaxLen - 1 )
12
      {
13
        *Buffer++ = NextChar;
14
        
15
        ende = wert;
16
        StringLen++;
17
        NextChar = usart_getc();
18
      }
19
20
                                      // Noch ein '\0' anhängen um einen Standard
21
                                      // C-String daraus zu machen
22
      *Buffer = '\0';
23
    }

Er schreibt das daten[] Array solange mit den empfangenen Zeichen bis \n 
kommt als Abschluss.

Jetzt hab ich das Problem das meine Steuerung kein Abschlusszeichen 
sendet, es hört einfach nach dem letzten "Nutzzeichen" auf und wartet 
dann auf den Bestätigungsstring.

Wie teile ich der Routine mit das die Datenübertragung zu ende ist und 
die Routine verlassen werden soll?
Könnte das über ne definierte Zeit gehen? Wenn nix innerhalb einer 
bestimmten Zeit kommt dann beende Schleife?
Wie schreib ich das???

von H.Joachim S. (crazyhorse)


Lesenswert?

genau, timeout nennt sich das.
Sollte genug Beispiele hier dafür geben.

von Peter D. (peda)


Lesenswert?

Christian Hohmann schrieb:
> Jetzt hab ich das Problem das meine Steuerung kein Abschlusszeichen
> sendet, es hört einfach nach dem letzten "Nutzzeichen" auf und wartet
> dann auf den Bestätigungsstring.

Die Übertragung muß ein Protokoll haben, mit der das Ende eines 
Datenpakets eindeutig bestimmt werden kann. Verbreitet sind 2 Methoden:
1. Endezeichen (darf dann nicht im Datenstrom vorkommen)
2. Das Paket enthält an einer festen Stelle eine Längenangabe, dann wird 
ab da runtergezählt.

Hat Dein Sender kein Protokoll, sollte man dem Entwickler ordentlich 
eins hinter die Löffel geben. Ein Timeout ist nur der absolut 
allerletzte Notnagel, für die Leute, die nicht programmieren können.


Peter

von gast (Gast)


Lesenswert?

oder macht deine steuerung nur bestimmte ausgaben ?
dann könnte man zB mit einem strncmp( , )  was machen

ansonst mal mit anderen programmen schauen ob nicht irgend ein zeichen 
kommt

hterm glaube zeigt alles an auch \r\n und so

von Chris T. (chris0086)


Lesenswert?

Ich verwende hterm und deswegen weis ich das kein weiteres Endzeichen 
geschrieben wird.
Sieht hier jemand in dem String irgend ne Prüfsumme versteckt?
4D 41 0C 49 00 1C 07 2B 5A 75 73 74 61 6E 64 04 1A
Bei den ersten 2 Zeichenketten die es schickt sah es so aus als ob das 
letzte zeichen eine Prüfsumme wär aber bei der sieht es nicht so aus 
oder hab ich mich verrechnet? Was muss denn da raus kommen?
Bei den ersten wars so, wenn ich alles addiere komme ist das Ergebnis 
das letzte Zeichen:  5261010100B5 B5 passt.
Aber wenn ich bis 255 zähle dann gehts doch bei 256 wieder bei 0 los 
oder?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Sieht hier jemand in dem String irgend ne Prüfsumme versteckt?
Jeder kann sich seine eigene Prüsfumme ausdenken. Die deint nur zur 
Sicherung des Protokolls.

Die XOR-Prüfsumme, die du meinst, ist die simpelste Art, ein Protokoll 
zu sichern. Mir fallen aber auf Anhieb mindestens 10 andere Arten ein, 
eine Prüfsumme zu bilden...   :-o

Zuerst solltest du wissen, was die einzelnen Zeichen darstellen, dann 
kannst du besser raten.

> Aber wenn ich bis 255 zähle dann gehts doch bei 256 wieder bei 0 los
> oder?
Ja, wenn du dich im 8-Bit-Zahlenraum bewegst...

von Chris T. (chris0086)


Lesenswert?

Ich weis was die Zahlen bedeuten:
4D410C49001C072B5A757374616E64041A bedeutet Z.Bsp.:MAI +Zustand
Das is teinfach nur die Menüstruktur, der Wert für Zustand wird erst 
später gesendet.
Das Was ich immer als Quittierung senden muss stzt sich zusammen aus:
'4D'+'abhängig vom Kommando'+'01'+'01'+'00'+'Prüfsumme welche einfach 
alle vorherigen Zeichen aufaddiert ist'.
Deswegen dacht ich das was die Steuerung schickt hat auch die Prüfsumme 
hinten dran welche einfach nur aufaddiert ist.

Nur zur Information: mit einem selbstgeschriebenen Delphiprogramm läuft 
das alles Problemlos, weil mir die Empfangsroutine den kompletten string 
liefert, sie also weis wann der String zu Ende ist. Diese hab allerdings 
nicht selbst geschrieben und weis auch nicht wie die das macht. Es 
funktionierte einfach.

Aber hier muss ich das wahrscheinlich über einen Timeout lösen...

von Chris T. (chris0086)


Lesenswert?

Da fällt mir ein, kann ich hier nicht irgend ne Abfrage reinbauen? Also 
wenn kein Zeichen mehr kommt dann tu irgendwas?:
1
uint8_t usart_getc(void)
2
    {
3
        while (!(UCSRA & (1<<RXC)))   // warten bis Zeichen verfuegbar
4
            ;
5
        return UDR;                   // Zeichen aus UDR an Aufrufer zurueckgeben
6
    }

von hmm (Gast)


Lesenswert?

Was spricht denn gegen ein richtiges Protokol ? Timeout ist eine 
schlechte Loesung ausser man hat genuegend Zeit.

von Christian J. (elektroniker1968)


Lesenswert?

Der ARM7 benutzt auch einen Timeout hardwaremässig bei 3 Perioden ohne 
Empfang, da Bytes für gewöhnlich schnell nacheinander gesendet werden. 
Diese Lösung ist sehr wohl salonfähig und sollte über dem 
Softwareprotokoll stehen.
Protokolle ohne Timeout lasse ich bei Zertifizerungen nicht durchgehen, 
die gehen gleich wieder zum Kunden zurück zur Nachbearbeitung.

von Chris T. (chris0086)


Lesenswert?

Zeit hab ich schon, ist nicht sehr zeitkritisch das ganze.
Werd das auch so machen denk ich da ich keine andere Möglichkeit sehe.

von hmm (Gast)


Lesenswert?

Ja. Ein Timeout als Notnagel, oder als Standardelement sind zwei paar 
Schuhe. Mit 3 Byte Totzeit ist man nie dabei. Es lohnt sich dazu mal 
eine Uebertragung von einem Windows PC aufm Scope anzuschauen. Wenn 
Windows etwas anderes als wichtiger betrachtet macht es etwas anderes. 
Ich hab leider die exakten Zahlen vergessen, glaube aber Aussetzer von 
einigen 100ms sind zu erwarten. Das waeren dann bei 9600 Baud einige 100 
Byte Totzeit. Ich setze die Totzeit auf eine Sekunde und drueber. Da 
spielt die Antwortzeit des Devices auch noch rein.

von spess53 (Gast)


Lesenswert?

Hi

>Da fällt mir ein, kann ich hier nicht irgend ne Abfrage reinbauen? Also
>wenn kein Zeichen mehr kommt dann tu irgendwas?:uint8_t usart_getc(void)
>    {
>        while (!(UCSRA & (1<<RXC)))   // warten bis Zeichen verfuegbar
>            ;
>        return UDR;                   // Zeichen aus UDR an Aufrufer 
>zurueckgeben
>    }

Bei jedem Zeichen einen Timer anschubsen. Bei Überlauf abbrechen.

Die Delphi-Komponenten für serielle Kommunikation, die ich kenne, haben 
alle einen programmierbaren Timeout. Ist aber eigentlich schon in der 
Windows-SDK verankert.

MfG Spess

von Chris T. (chris0086)


Lesenswert?

Nochmal fürs verständnis, wenn ich den timer anschubse arbeitet er aber 
das Programm weiter ab oder?? er wartet nicht bis der Timer dann 
durchgelaufen ist.
Müsste ich dann irgendwie mit nem Interrupt lösen wenn er überläuft 
oder?

In delphi habe ich die Komponente SerialNG benutzt.
Die Funktion ReadNextClusterAsString : String; liefert mir einfach den 
kompletten String zurück und ich brauchte mich um nix weiter zu 
kümmern...

von hmm (Gast)


Lesenswert?

>habe ich die Komponente SerialNG benutzt...

Unter windows hat man wenig Zugriff. Ich empfehle speziell fuer Delphi 
TPApro, da es unter anderem auch den besten Upgrade ueber die diversen 
Delphi und Windows Versionen gewaehrleitet.

http://sourceforge.net/projects/tpapro/

von Chris T. (chris0086)


Lesenswert?

Kann mir mal jemand genau diese Zeile erklären(auch die Zeichen)
while (!(UCSRA & (1<<RXC)))   ich wollte das so in meine Schleife 
einbauen:
1
while( (UCSRA & (1<<RXC)) && StringLen < MaxLen - 1 )
2
      {
3
        *Buffer++ = NextChar;
4
        wert = checksumme(NextChar,wert);
5
        ende = wert;
6
        StringLen++;
7
        NextChar = usart_getc();
8
      }

von spess53 (Gast)


Lesenswert?

Hi

>Nochmal fürs verständnis, wenn ich den timer anschubse arbeitet er aber
>das Programm weiter ab oder?? er wartet nicht bis der Timer dann
>durchgelaufen ist.

Ja.

>Müsste ich dann irgendwie mit nem Interrupt lösen wenn er überläuft
>oder?

So in etwa. Ich bin nicht sehr firm in C (eigentlich gar nicht). Aber in 
der ISR eine Variable (igendwie global) setzen und in 'while (!(UCSRA & 
(1<<RXC)))' mit abfragen. Nach Verlassen der while-Schleife kann man 
dann an Hand der Variable entscheiden.

@hmn
>Unter windows hat man wenig Zugriff.
Mit den entsprechenden API-Funktionen kommt man ganz schön weit.
Eine recht ausgefeilte Serielle Komponente gibt es auch von der 
Zeitschrift 'Toolbox'.

MfG Spess

von Chris T. (chris0086)


Lesenswert?

Woran scheitert es jetzt?
1
uint8_t usart_getc(void)
2
    {
3
        while (!(UCSRA & (1<<RXC)))   // warten bis Zeichen verfuegbar
4
            ;
5
        return UDR;                   // Zeichen aus UDR an Aufrufer zurueckgeben
6
    }
7
8
9
    void usart_gets( char* Buffer, uint8_t MaxLen )
10
    {
11
      uint8_t NextChar;
12
      uint8_t StringLen = 0;
13
14
      NextChar = usart_getc();         // Warte auf und empfange das nächste Zeichen
15
16
                                      // Sammle solange Zeichen, bis:
17
                                      // * entweder das String Ende Zeichen kam
18
                                      // * oder das aufnehmende Array voll ist
19
      wert = checksumme(NextChar,wert);
20
      *Buffer++ = NextChar;
21
      ende = wert;
22
      while( (UCSRA & (1<<RXC)) && StringLen < MaxLen - 1 )
23
      {
24
      NextChar = usart_getc();
25
        *Buffer++ = NextChar;
26
27
        wert = checksumme(NextChar,wert);
28
        ende = wert;
29
        StringLen++;
30
31
      };
32
33
34
35
    }
36
37
anweisungen:
38
  usart_gets( daten, sizeof( daten ) );
39
40
41
    USART_Transmit(ende);
42
goto anweisungen;
wenn ich in hterm 20(hex) schicke kommt 00 zurück obwohl ja 20 kommen 
müsste.
wenn ich 20 20 20(also alles eingeben und auf einmal schicken) eingebe 
dann kommt 00 60 raus. also das 60 stimmt ja(lasse alle empfangenen 
Zeichen aufaddieren) aber warum kommt vorher 00 was wird hier zu oft 
durchlaufen oder was ist hier schief???
Ich verzweifle an so einer einfachen Sache

von hmm (Gast)


Lesenswert?

>>>Unter windows hat man wenig Zugriff.
>Mit den entsprechenden API-Funktionen kommt man ganz schön weit.

Es war mir bisher nicht moeglich eine unterbruchsfreie Uebertragung von 
groesseren Datenmengen hinzubekommen. Einen Buffer macht windows noch 
unterbruchsfrei, aber sobald man mehrere Buffer verwendet, zB bei mehr 
als 64kbyte, gibt's Unterbrueche von hunderten von millisekunden.

von Peter D. (peda)


Lesenswert?

Christian J. schrieb:
> Protokolle ohne Timeout lasse ich bei Zertifizerungen nicht durchgehen,
> die gehen gleich wieder zum Kunden zurück zur Nachbearbeitung.

Was soll den dieser Quatsch?
Man muß schon dem Entwickler überlassen, wie er die Übertragung 
absichert.
Ordentliche Protokolle brauchen kein Timeout.

Ich habe oft Stringprotokolle, die 0x0D oder 0x0A als Endekennzeichen 
benutzen. Zum Testen nimmt man ein Terminalprogramm und dann wäre ein 
Timeout Blödsinn, so schnell kann ich nicht tippen.
Wenn ein Kommando unvollständig ist und das Endekennzeichen fehlt, nützt 
ein Timeout absolut garnichts.


Für eine Zertifizierung ist dagegen wichtig, daß ein gestörtes Kommando 
keinen Schaden anrichtet, d.h. durch das Protokoll ein 
Übertragungsfehler mit hoher Warscheinlichkeit erkannt wird. Mit nem 
Timeout erreicht man das nicht, daher ist ein Timeout völlig sinnfrei.


Peter

von oho (Gast)


Lesenswert?

Ein Timeout macht was ganz anderes. Nimm ein normales Protokol, das als 
Zustandsmaschine ablaeuft. Da geht nun einmal ein einzelnes Zeichen 
verloren. Der Empfaenger wartet ewig. Daher hat man einen langen Timeout 
und startet die Zustandsmaschine neu. Macht man vor allem auf der Master 
seite. Kann aber auch bei einem Slave Sinn machen.

von spess53 (Gast)


Lesenswert?

Hi

>Ordentliche Protokolle brauchen kein Timeout.

Aber nur, wenn die Gegenstelle immer vorhanden und bereit ist. Wenn 
nicht greift kein Protokoll.

MfG Spess

von Chris T. (chris0086)


Lesenswert?

also ich hätte es ja fasst hinbekommen ohne irgendwelche Timeouts oder 
Protokolle wenn mir mal jemand sagen würde warum da oben Anweisungen 
zweimal ausgeführt werden statt nur einmal...

von Peter D. (peda)


Lesenswert?

oho schrieb:
> Ein Timeout macht was ganz anderes. Nimm ein normales Protokol, das als
> Zustandsmaschine ablaeuft. Da geht nun einmal ein einzelnes Zeichen
> verloren. Der Empfaenger wartet ewig.

Und wen störts?
Der SRAM für den Empfangspuffer ist ja permanent reserviert, daher 
fressen einige Bytes eines gestörten Pakets kein Brot.
Irgendwann kommt aber wieder ein neues Paket und dann ist er wieder 
synchron.

Der Master kann auch zu Anfang oder nach längeren Pausen ein spezielles 
Sync-Paket schicken. Dann weiß der Slaver sicher, das eventuelle Reste 
im Empfangspuffer Müll sind.


Peter

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.