- 12V Akku mit 280 Ah bauen         
Ergebnis 1 bis 10 von 18

Thema: UART ohne CrLf?

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Erfahrener Benutzer Roboter Genie Avatar von malthy
    Registriert seit
    19.04.2004
    Ort
    Oldenburg
    Beiträge
    1.379
    Hey!

    Ich kenne das Problem auch. Die simpel-Lösung die ich bisher verwende, ist die Daten in ASCII hexcodiert zu übertragen. Damit kann man dann immernoch die klassischen Steuerzeichen verwenden (CR/LF), hat aber den Vorteil das 1.) die Übertragung im Mittel etwas effizienter ist als ASCII dezimalcodiert und 2.) die Zahlen eine feste Breite von zwei ASCII Zeichen haben. Das ist für meinen Geschmack ein großer Vorteil bei der Nachrichtenauswertung, die wird dann zu einem einfachen hex2dec oder dec2hex (je nach Sprache).

    Natürlich könnte man das Prinzip weitertreiben und ein eigenes Zahlenformat verwenden, das 254 Datenzeichen und 1 Steuerzeichen (zB Nachricht Ende) verwendet. Bisher war ich zu faul das mal zu implementieren.

    Gruß
    Malte

  2. #2
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    04.09.2011
    Ort
    Hessen
    Beiträge
    707
    Hallo,

    habe da schon verschiedene Protokolle gesehen:

    Zum Beispiel STX Datenbytes ETX, wenn in den Datenbytes die Werte der Steuerzeichen vorkommen wird z.B. ESC STX, ESC ETX und ESC ESC gesendet. STX (Start of Transmission) usw. findet man in einer ASCII Tabelle.

    Dann eine Variante von ISO-TP angepasst an UART: STX Framennummer-Byte Anzahl-Datenbytes-Byte Datenbytes Checksum-Byte.
    http://de.wikipedia.org/wiki/ISO_15765-2

  3. #3
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    20.08.2008
    Ort
    Karlsruhe
    Alter
    37
    Beiträge
    1.225
    Es steht dir vollkommen frei, ein beliebiges Protokoll zu entwickeln und zu implementieren, bei dem die ASCII-Steuerzeichen wie CR und LF kein oder eine komplett andere Bedeutung haben. Der primäre Einsatzzweck von CR/LF ist die Ausgabe auf einer Textkonsole, da verbessert der Zeilenumbruch die Lesbarkeit. Für ein Binärprotokoll ist das aber komplett irrelevant.

    mfG
    Markus
    Tiny ASURO Library: Thread und sf.net Seite

  4. #4
    Erfahrener Benutzer Robotik Einstein Avatar von Geistesblitz
    Registriert seit
    15.03.2011
    Ort
    Dresden
    Alter
    37
    Beiträge
    1.937
    Danke schonmal für die Anregungen. Hex-Strings hören sich schonmal ganz gut an, mich würde trotzdem mal interessieren, wie man da noch weiter gehen könnte. Ich hab auch schonmal ein Testprogramm in Bascom geschrieben, das nicht erst auf CrLf warten soll, sondern direkt das jeweils empfangene Byte aufnimmt, allerdings kam so keine Kommunikation zustande.
    AI - Artificial Idiocy

  5. #5
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.707
    ... ein Testprogramm in Bascom geschrieben, das nicht erst auf CrLf warten soll ... allerdings kam so keine Kommunikation zustande.
    Schon klar dass es so nicht geht. Die üblichen Bibliotheken warten eben auf einen Standard-Abschluss. Da muss man schon selbst aktiv werden. Bei mir stehen die empfangenen Daten noch dazu in einem FIFO und die Kommunikation läuft "im Hintergrund" interruptgesteuert. Geht recht fix.

    Mal ein paar rausgeschnibbelte Code-Zeilen um das Vorgehen zu skizzieren:

    Code:
         // ==================================================
         /* ... auf Inhalt im FIFO ... wartem */
         if ( ! ukbhit0 () )
           continue;
    
    
         // ==================================================
         /* EIN EINZIGES Zeichen aus FIFO lesen.    */
         zeichen_aus_fifo = ugetchar0();
    
    
         // ==================================================
         /* Wenn noch kein Kommando bekannt ist, muessen wir erst einen 
            Kommando-Buchstaben erkennen.
    
            Randbemerkung
            Hier ist auch ein switch/case-Dingsda erlaubt, da zeichen_aus_fifo und
            auch der Define genau ein char-Zeichen bzw. ein numerisch auswertbarer
            einfacher Datentyp sind.                     */
         if (zeiger == 0)
         {                                          //
           if (zeichen_aus_fifo == KOMMANDO_APPS)   // Fahre Anwendungsprogramme
             telegrammlaenge = KOMMANDO_APPS_LEN;   //   mit und ohne Parameter
    
           if (zeichen_aus_fifo == KOMMANDO_DATS)   // Servo Daten von allen
             telegrammlaenge = KOMMANDO_DATS_LEN;   //   Servos anzeigen
    
           if (zeichen_aus_fifo == KOMMANDO_NORM)   // Servo Normposition
             telegrammlaenge = KOMMANDO_NORM_LEN;   //   anfahren
    
           if (zeichen_aus_fifo == KOMMANDO_OFFA)   // Offsetwert A nzeigen
             telegrammlaenge = KOMMANDO_OFFA_LEN;   //   von Servo x
    ....
         }
    
    
         // ==================================================
         /* Wenn keine Telegrammlaenge bekannt ist, dann ist auch kein Kommando
           bekannt, dann muss auch nichts weiter gemacht werden, als auf das 
           naechste Zeichen zu warten bzw. es abzuholen und dann wieder auf 
           einen Kommando-Buchstaben zu testen                      */
         if (telegrammlaenge == 0)
           continue;
    
         // ==================================================
         /* Wenn ein erkanntes Kommando seine Telegrammlaenge angegeben hat, dann
           muessen wir nun die EINZELN aus dem FIFO abgeholten Zeichen in den BUFFER
           schreiben. Da ja schon der erkannte Kommando-Buchstabe in der Variablen 
           "zeichen_aus_fifo" steht, und "zeiger" noch nicht veraendert wurde, wird 
           auch zum Glueck der Kommando-Buchstabe direkt als erstes Zeichen in
           unserem BUFFER landen.
           Und alle weiteren Zeichen werden dank "zeiger++" dahinter geschrieben. */
         mein_rx_buff [zeiger] = zeichen_aus_fifo;
         zeiger++;
    
         // ==================================================
         /*  Und jetzt das geniale Ergebnis:
           Wenn nun "zeiger" und "telegrammlaenge" gleich sind,
           dann haben wir ein fertig empfangenes Kommando mit
           seiner erwarteten Laenge.        */
         if (zeiger == telegrammlaenge)
         {
           /*  DIESE INITIALISIERUNGEN SIND LEBENSWICHTIG  */
           zeiger          = 0;
           telegrammlaenge = 0;
    
           /*  Die Funktionen koennen nun gemuetlich das
               Telegramm auswerten.       */
    
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //    Fahre verschiedene Anwendungsprogramme, je nach Nummer 
        if (mein_rx_buff [0] == KOMMANDO_APPS)      // Tastatur-Eingabe "Annkkkk"
        {                                   //   Annkkkk
                                            //    nn =:  01..99 - Programm-Casenummer
                                            //      kkkk  Parameter für Prog
    //      Dekodiere Programmkennziffer im Byte mein_rx_buff 1 und 2
          for ( u8 i=0; i<=1; i++) { s[i] = mein_rx_buff [i + 1]; }
          s[2]  = 0;                        // Markiere Stringende "0"
          nmbr  = atoi ( s );               //
    
    // - - - - - - - - - - - - - - -
    //    case
    //      10      Augen rollen k mal (erstes "k")
    //      11      Alle Lider auf, full speed
    //      12      Alle Lider  zu, full speed
    ....
    //                  Fahrgeschwindigkeit "Servo-Standard+SloMo"
    //      43      Augenprogramm AuP43 = ähnlich 42, eher langsamer
    
    // - - - - - - - - - - - - - - -
          switch (nmbr)     // Fahre gewählte Aktionen
          {                         //
            case 10:                // Augen rollen k-mal
              s[0]  = mein_rx_buff [3]; s[1] = 0;   // Dekodiere 1stes k
              npar1 = atoi ( s );   //
              AuRoll ( npar1 , 100 );       // Augen rollen mit Standard-slow
              for ( u8 i=1; i<=6; i++) {mein_rx_buff [i]  =  '9'; }
              mein_rx_buff [7]  =  0;       // Hilft das bei unvollständiger Eingabe ?
              break;
    
            case 11:                // Alle Lider auf, full speed
    //        s[0]  = mein_rx_buff [3]; s[1] = 0;   // Dekodiere 1stes k
    //        npar1 = atoi ( s );   //
              Srv_tm [ 5]   =  2400;
              Srv_tm [ 6]   =  4800;
              Srv_tm [ 8]   =  5400;
              wms (  500);          //
              break;                //
    .....
            case 51:        // NUR ANSCHLUSS SERVO 1 mit TasteA/3 auf- und abdrehen
    //        AuP51 ( );                    // Fahre AuP51                         r4n
              N1Srvo ();                    // Fahre Servo-Einzel-Einrichtung      r2n
              break;                        //
    
    // - - - - - - - - - - - - - - -
            default:
              break;
          }                         // Ende switch (nmbr)
        }        // Ende if (mein_rx_buff [0] == KOMMANDO_APPS)
    
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //      Wurde "KOMMANDO_DATS" = "D" erkannt ?   DatenAusgabe Servos
        if (mein_rx_buff [0] == KOMMANDO_DATS)      // Tastatur-Eingabe "D"
        {                                           //
    //    Daten für ALLE zehn Servos ausgeben
          uputs0 ("\r\tServodaten");   //
          dat_aus ();               // Servodaten ausgeben
        }        // Ende if (mein_rx_buff [0] == KOMMANDO_DATS)
    
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //      Wurde "KOMMANDO_NORM" = "N" erkannt ?   Normposition der Servos anfahren
        if (mein_rx_buff [0] == KOMMANDO_NORM)      // Tastatur-Eingabe "N"
        {                                           //
          uputs0 ("\r\tServonormposition,");       //
          kal_0();                          // Initialiswerte einstellen           kal
          uputs0 ("\tneue Servodaten :");   //
          dat_aus ();                       // Servodaten ausgeben
    
        }        // Ende if (mein_rx_buff [0] == KOMMANDO_NORM)
    
    
    und so weiter
    Ist das so (andeutungsweise) verständlich ?
    Ciao sagt der JoeamBerg

  6. #6
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    08.09.2007
    Ort
    Berlin
    Alter
    32
    Beiträge
    1.578
    Hi,

    ich hab auch vor einiger Zeit mein eigenes Protokoll entwickelt (mittlerweile gibts ein paar Verbesserungen, aber das wäre zuviel).
    Es ging damals darum, ein Byte-Array von einem µC auf einen PC und andersrum zu übertragen. Da ich aber nichtmehr soviel Platz auf dem µC hatte, dachte ich mir, jedes einzelne Byte, das gespart werden kann, wird gespart!
    Also hab ich mir die Situation rausgesucht, bei der die meisten Byte übertragen werden müssen und diese Byte-Anzahl als Norm-Länge verwendet.
    Nun wird einfach immer ein Array dieser Länge (bei mir sind 132 Byte) übertragen, incl. Erkennungsbytes (damit der Empfänger weiß, was er mit den Daten machen soll).
    Um niemals die Synchronisation zu verlieren, frage ich regelmäßig die Anzahl der bereits empfangenen Daten ab und kucke mir die Zeit an, seit der sich die Anzahl nicht mehr verändert hat. Wird eine bestimmte Zeit überschritten, gehe ich davon aus, dass Daten verlorengegangen sind und setze die Zähler zurück.
    Das ganze läuft bei mir auf dem µC per DMA, so wird sogut wie keine Zeit für das Empfangen verschwendet.
    Neuerdings schwirren mir wieder ein paar Verbesserungen im Kopf rum, welche ich demnächst wohl mal einpflegen werde.
    Zum Beispiel will ich von der festen Array-Länge weg, da es in manchen Fällen vorkommen kann, dass nur 10% von den 132 Bytes effektiv genutzt werden. Das ist zwar grundsätzlich egal, sieht aber nicht schön aus.
    Auch wäre eine Verbindung verschiedener µCs untereinander nicht schlecht, sodass am Anfang eines Arrays zuerst der Empfänger, dann der Sender, dann die Anzahl der folgenden Bytes und anschließend evtl. noch eine Checksumme integriert sind. Außerdem wäre es eine schicke Idee, die Daten sozusagen Seitenweise zu übertragen, heißt:
    Eine Seite ist z.b. 10Bytes lang, in ihr befinden sich alle relevanten Informationen für die Übertragung ansich, ebenso wie die zu übertragenden Daten selbst. Unter den für die Übertragung relevanten Daten finden sich noch zwei Werte, die akt. Seitenzahl und die Gesamtseitenzahl. So liesen sich mit nur 10Bytes Speicher große Datenmengen übertragen.
    Das Alles noch mit einem ACK abgerundet, fertig ist ein High-Level-Protokoll.

    Es kommt aber eben darauf an, WAS du willst. Willst du Daten schnell austauschen, störsicher, große Datenmengen, etc ... ?

    Gruß
    Chris

  7. #7
    Erfahrener Benutzer Roboter Genie Avatar von malthy
    Registriert seit
    19.04.2004
    Ort
    Oldenburg
    Beiträge
    1.379
    Ich denke man braucht dedizierte Steuerzeichen (das heißt Zeichen, die nur Steuerzeichen sind). Ob das nun historische wie LF oder CR sind, ist dabei natürlich erstmal wurscht.

    Um jetzt bei einem reinen binären Datenstrom noch zusätzlich Steuerzeichen zu gewinnen, arbeitet man mit einem Escape-Zeichen.
    Gerne wird dafür der Wert 0x1B (ESC) verwendet.
    Will man ein Steuerzeichen einfügen sendet man zuerst ein ESC und dann das Steuerzeichen.
    Da der Wert 0x1B aber auch in den Daten vorkommen kann, sendet man in diesem Falle zwei mal ESC.
    Die Logik verstehe ich nicht ganz. Wenn der Wert des Steuerzeichens auch in den Daten vorkommen kann, wie kann man dann ausschließen, dass es sich bei einem "scheinbaren" Steuerbefehl nicht zufällig um zwei Datenwerte handelt, die aussehen wie ein Steuerbefehl. Also konkret: wenn 0x1B einen Befehl markieren würde und ein 0x50 würde zB die Ausgabe von der folgenden drei Bytes (binary) auf einem LCD bedeuten, wie wäre der Fall davon zu unterscheiden, dass einfach zufällig dezimal 27 und 80 in einem anderen Zusammenhang aufgetaucht sind? Sich nämlich darauf zu verlassen, dass man immer sicher im Leseraster ist (was natürlich eine Lösung wäre), finde ich etwas gewagt ... Oder habe ich da irgendwo einen Denkfehler?

    Ich hab auch schonmal ein Testprogramm in Bascom geschrieben, das nicht erst auf CrLf warten soll, sondern direkt das jeweils empfangene Byte aufnimmt, allerdings kam so keine Kommunikation zustande.
    Hm, verstehe ich nicht ganz ... Ich verwende zwei Varianten. Die eine ist im Hauptloop - also quasi durch permanentes Polling - mit

    Code:
    If Ischarwaiting() = 1
    jeweils zu gucken ob was im UART Puffer für mich zum abholen liegt, und falls ja, es mit

    Code:
    Uart_buf(uart_buf_i) = Inkey()
    abzuholen. Meist schreibe ich die Zeichen in einen Ringpuffer, den ich dann nach jedem neuen Byte nach der Sequenz absuche, die das Ende der Nachricht signalisiert (bei mir idR CR/LF, das kann definitionsgemäß nicht als Datenwerte vorkommen). Wenn das Ende erreicht ist, wird eine Anzahl Bytes vorher im Ringpuffer, die der Nachrichtenlänge entspricht ausgewertet. Das heißt in meinem Falle von Hex (String) nach Dezimal (oder wie auch immer man die Variable dann interpretiert) umgewandelt. Meist schleppe ich noch einen 8 bit CRC Wert mit, der dann noch ausgewertet wird.

    Die andere Varainte geht fast genauso, da verwende ich dann allerdings den urxc Interrupt, dh mit

    Code:
    On Urxc Rxc_isr
    wird bei jedem neuen Zeichen die entsprechende ISR angesprungen, die dann die Auswertung wie eben gesagt macht.

    Ist methodisch nicht sehr intellektuell und die Codierung ist auch "far from optimal", aber es funktioniert stumpf

    Gruß
    Malte
    Geändert von malthy (08.08.2014 um 17:20 Uhr) Grund: typos

  8. #8
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    27.08.2013
    Ort
    Region Basel
    Alter
    67
    Beiträge
    2.435
    Hallo,
    Die Logik verstehe ich nicht ganz. Wenn der Wert des Steuerzeichens auch in den Daten vorkommen kann, wie kann man dann ausschließen, dass es sich bei einem "scheinbaren" Steuerbefehl nicht zufällig um zwei Datenwerte handelt, die aussehen wie ein Steuerbefehl. Also konkret: wenn 0x1B einen Befehl markieren würde und ein 0x50 würde zB die Ausgabe von der folgenden drei Bytes (binary) auf einem LCD bedeuten, wie wäre der Fall davon zu unterscheiden, dass einfach zufällig dezimal 27 und 80 in einem anderen Zusammenhang aufgetaucht sind? Sich nämlich darauf zu verlassen, dass man immer sicher im Leseraster ist (was natürlich eine Lösung wäre), finde ich etwas gewagt ... Oder habe ich da irgendwo einen Denkfehler?
    Also: 27 80 als Daten wird als 27 27 80 gesendet.

    Sobald 27 im Datenstrom auftaucht wird dieses beim Empfänger entfernt und das nächste Byte auch, weil dies der Befehl ist. Das folgende 80 ist dann der Befehl fürs LCD ...

    Der Befehl 27 bedeutet dann, füge 27 in den Ausgabestrom ein.

    In Pseudocode:
    Code:
    z1 = LeseZeichen()
    If (z1 = 27) then
      Z2 = Lese Zeichen()
      if (z2 =  0) then .....
      if (z2 =  1) then .....
      if (z2 = ..) then .....
      if (z2 = ..) then .....
      if (z2 = 27) then SchreibeZeichen(27)
      if (z2 = ..) then .....
      if (z2 = 80) then SchreibeLCD()
      if (z2 = ..) then .....
    else
      Schreibe Zeichen(z1)
    endif
    MfG Peter(TOO)
    Manchmal frage ich mich, wieso meine Generation Geräte ohne Simulation entwickeln konnte?

  9. #9
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    04.09.2011
    Ort
    Hessen
    Beiträge
    707
    Zitat Zitat von malthy Beitrag anzeigen
    Die Logik verstehe ich nicht ganz. Wenn der Wert des Steuerzeichens auch in den Daten vorkommen kann, wie kann man dann ausschließen, dass es sich bei einem "scheinbaren" Steuerbefehl nicht zufällig um zwei Datenwerte handelt, die aussehen wie ein Steuerbefehl.
    Das ist genauso wie mit den Escape-Sequenzen in C. Man schreibt da ja z.B. "\r\n" für das CR LF. Wenn man einen Backslash schreiben will, schreibt man "Dies ist ein \\". Der Backslash ist hier das Escape Zeichen.

    - - - Aktualisiert - - -

    Zitat Zitat von Che Guevara Beitrag anzeigen
    Hi,
    Zum Beispiel will ich von der festen Array-Länge weg, da es in manchen Fällen vorkommen kann, dass nur 10% von den 132 Bytes effektiv genutzt werden. Das ist zwar grundsätzlich egal, sieht aber nicht schön aus.
    Auch wäre eine Verbindung verschiedener µCs untereinander nicht schlecht, sodass am Anfang eines Arrays zuerst der Empfänger, dann der Sender, dann die Anzahl der folgenden Bytes und anschließend evtl. noch eine Checksumme integriert sind. Außerdem wäre es eine schicke Idee, die Daten sozusagen Seitenweise zu übertragen, heißt:
    Eine Seite ist z.b. 10Bytes lang,
    Was du da beschreibst, machen z.B. Automobil Steuergeräte häufig mit dem oben schon erwähnten abgewandelten ISO-TP.

    Beispiel:

    Es sollen die Daten 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 übertragen werden. In der Praxis natürlich viel mehr Daten, aber ich will nicht so viel schreiben.

    Entweder die beteiligten Geräte wissen, welche maximale Paketgröße die jeweilige Gegenstelle verträgt, oder sie handeln das auch noch mit dem Protokoll aus. Das lasse ich hier aber mal weg.


    Fall 1 ein großer Controller akzeptiert alle Daten auf einmal:
    Der Sender sendet 0x02 0x01 0x08 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 yy. Das sind ein STX, die Framenummer 1, Datenzahl 8, die Daten und irgendeine Prüfsumme yy.
    Der Empfänger bestätigt z.B. 0x02 0x01 0x06 yy . Das sind STX, Framenummer, ACK und Prüfsumme.


    Fall 2 ein kleine Controller akzeptiert maximal 4 Datenbytes auf einmal:
    Der Sender sendet 0x02 0x01 0x04 0x00 0x01 0x02 0x03 yy
    Der Empfänger bestätigt mit 0x02 0x01 0x06 yy
    Der Sender sendet 0x02 0x02 0x04 0x04 0x05 0x06 0x07 yy ( STX; 2. Frame; 4 Bytes; Daten; Prüfsumme )
    Der Empfänger bestätigt mit 0x02 0x02 0x06 yy

    Hoffe jetzt wird es etwas klarer.
    Geändert von Mxt (08.08.2014 um 17:35 Uhr) Grund: Erklärung

  10. #10
    Erfahrener Benutzer Roboter Genie Avatar von malthy
    Registriert seit
    19.04.2004
    Ort
    Oldenburg
    Beiträge
    1.379
    Das ist genauso wie mit den Escape-Sequenzen in C
    Gutes Stichwort Hast natürlich vollkommen Recht, das habe ich übersehen.

Ähnliche Themen

  1. Antworten: 4
    Letzter Beitrag: 13.06.2012, 18:22
  2. Soft-Uart - Intergerzahlen ohne ext. Quarz übermitteln
    Von #fritz# im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 4
    Letzter Beitrag: 10.10.2011, 19:31
  3. Übertrageung zwischen PC/µC und µC aber ohne Uart
    Von Michael 123 im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 10
    Letzter Beitrag: 18.06.2006, 09:15
  4. Software-UART ohne Start-, Stop- und Paritybit
    Von TurboFischer im Forum C - Programmierung (GCC u.a.)
    Antworten: 4
    Letzter Beitrag: 05.06.2006, 22:07
  5. Ohne mampf kein Kampf (ohne strohm geht nichts)
    Von Andal im Forum Elektronik
    Antworten: 21
    Letzter Beitrag: 26.11.2004, 19:40

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Solar Speicher und Akkus Tests