www.mikrocontroller.net

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


Autor: Chris Tian (chris0086)
Datum:

Bewertung
0 lesenswert
nicht 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:
 void usart_gets( char* Buffer, uint8_t MaxLen )
    {
      uint8_t NextChar;
      uint8_t StringLen = 0;
      int wert = 0;
      NextChar = usart_getc();         // Warte auf und empfange das nächste Zeichen

                                      // Sammle solange Zeichen, bis:
                                      // * entweder das String Ende Zeichen kam
                                      // * oder das aufnehmende Array voll ist
      while( NextChar != '\n' && StringLen < MaxLen - 1 )
      {
        *Buffer++ = NextChar;
        
        ende = wert;
        StringLen++;
        NextChar = usart_getc();
      }

                                      // Noch ein '\0' anhängen um einen Standard
                                      // C-String daraus zu machen
      *Buffer = '\0';
    }

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???

Autor: H.Joachim Seifert (crazyhorse)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
genau, timeout nennt sich das.
Sollte genug Beispiele hier dafür geben.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Chris Tian (chris0086)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Chris Tian (chris0086)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Chris Tian (chris0086)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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
    }

Autor: hmm (Gast)
Datum:

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

Autor: Christian J. (elektroniker1968)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Chris Tian (chris0086)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: hmm (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Chris Tian (chris0086)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: hmm (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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/

Autor: Chris Tian (chris0086)
Datum:

Bewertung
0 lesenswert
nicht 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:
while( (UCSRA & (1<<RXC)) && StringLen < MaxLen - 1 )
      {
        *Buffer++ = NextChar;
        wert = checksumme(NextChar,wert);
        ende = wert;
        StringLen++;
        NextChar = usart_getc();
      }

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Chris Tian (chris0086)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Woran scheitert es jetzt?
uint8_t usart_getc(void)
    {
        while (!(UCSRA & (1<<RXC)))   // warten bis Zeichen verfuegbar
            ;
        return UDR;                   // Zeichen aus UDR an Aufrufer zurueckgeben
    }


    void usart_gets( char* Buffer, uint8_t MaxLen )
    {
      uint8_t NextChar;
      uint8_t StringLen = 0;

      NextChar = usart_getc();         // Warte auf und empfange das nächste Zeichen

                                      // Sammle solange Zeichen, bis:
                                      // * entweder das String Ende Zeichen kam
                                      // * oder das aufnehmende Array voll ist
      wert = checksumme(NextChar,wert);
      *Buffer++ = NextChar;
      ende = wert;
      while( (UCSRA & (1<<RXC)) && StringLen < MaxLen - 1 )
      {
      NextChar = usart_getc();
        *Buffer++ = NextChar;

        wert = checksumme(NextChar,wert);
        ende = wert;
        StringLen++;

      };



    }

anweisungen:
  usart_gets( daten, sizeof( daten ) );


    USART_Transmit(ende);
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

Autor: hmm (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: oho (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Ordentliche Protokolle brauchen kein Timeout.

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

MfG Spess

Autor: Chris Tian (chris0086)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.