-
        

Ergebnis 1 bis 7 von 7

Thema: Seriell-RF mehrere Bytes übertragen und auswerten (Gcc)

  1. #1
    Erfahrener Benutzer Roboter Genie Avatar von oderlachs
    Registriert seit
    17.05.2010
    Ort
    Oderberg
    Alter
    67
    Beiträge
    1.118
    Blog-Einträge
    1

    Seriell-RF mehrere Bytes übertragen und auswerten (Gcc)

    Anzeige

    Hallo Kenner der Materie !

    Ich habe wieder mal das, von mir oft zitierte Brett, irgendwie vorm K...

    Ich möchte einige Byte nacheinander übertragen, zuerst einmal 3 Byte nacheinander, aber ich weiss nicht wie ich es anstellen kann das dieses auch richtig getrennt von der Gegenseite ausgewertet wird. Das also der Wert des entsprechenden Bytes auch dahingehend ausgewertet wird , wo er auch hingehört.

    Irgendwie finde ich nicht recht den Anfang, einen Frame von erst mal zBsp. 3 Byte zu senden und die einzelnen Werte auf der Empfangsseite dementsprechend auszuwerten.
    Ich erwarte hier keinen fertigen Quellcode der mir in den Schoss gelegt wird, ein paar Hinweise, vielleicht auch Anschaungsbeispiele zur Realisierung meines Projektes würden mich schon sehr erfreuen

    Gruss und Dank

    Gerhard
    Arduinos, STK-500(AVR), EasyPIC-40, PICKIT 3 & MPLABX-IDE , Linux Mint

  2. #2
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    20.08.2008
    Ort
    Kandel
    Alter
    29
    Beiträge
    1.220
    Es gibt verschiedene Möglichkeiten, die auch ein Stück weit davon abhängen, wie komplex das Protokoll werden soll. Ich will dir Mal zwei Möglichkeiten aufzeigen:

    Option 1: Zustandsautomat
    Auf Empfängerseite definierst du für jedes Byte einen Zustand, zum Beispiel B1_Lesen, B2_Lesen, B3_Lesen. Wenn du ein Byte empfängst, wechselst du über eine Fallunterscheidung (switch/case) in den aktuellen Zustand und verarbeitest dort das Empfange Byte. Danach wechselst du in den nächsten Zustand (Zustandsvariable inkrementieren) und wenn die Routine dann das nächste Mal aufgerufen wird, wechselt die Fallunterscheidung so in den nächsten Zustand. B3_Lesen muss nach Abschluss der Auswertung dann aber nicht in B3_Lesen+1 sondern in Zustand B1_Lesen überleiten.

    Option 2: Puffer/struct/union
    Wenn du ein ausreichend strukturiertes Protokoll hast (wovon ich fast ausgehe), kannst du die Daten auch erst einmal in einen Puffer (Byte-Array) einlesen und solange den Inhaltszähler inkrementieren bis du drei Bytes empfangen hast. Für deinen Frame hast du dir ein passendes struct definiert, mit dem du bequem auf die Inhalte zugreifen kannst. Jetzt kannst du den Puffer entweder über einen cast in einen Zeiger auf den struct-Datentyp verwandeln, oder du hast dir einen union-Datentyp definiert in dem sowohl ein Byte-Array als auch der struct liegen, und kommst so komplett ohne casts aus.

    Dazu ein Codebeispiel:
    Code:
    typedef struct {
        uint8_t a;
        int8_t b;
        uint16_t c;
    } frame_t;
    
    typedef union {
        frame_t frame;
        uint8_t buffer[sizeof(frame_t)];
    } frame_union_t;
    
    
    void someFunction() {
        frame_union_t buf;
    
        // irgendwie mit Daten befüllen, hier nicht sehr sinnvoll ...
        buf.buffer[0] = 0xaa;
        buf.buffer[1] = 0xbb;
        buf.buffer[2] = 0xcc;
        buf.buffer[3] = 0xdd;
    
        foo = buf.frame.c; // was das wohl gibt?!
    }
    mfG,
    Markus
    Tiny ASURO Library: Thread und sf.net Seite

  3. #3
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    7.551
    Zitat Zitat von markusj Beitrag anzeigen
    ... verschiedene Möglichkeiten ... abhängen, wie komplex das Protokoll ...
    Schöne Erklärung Markus, danke. Irgendwann muss ich mich wohl wirklich mit Sinn, Zweck, Anwendungs- und (allgemein) Möglichkeiten der struct´s und union´s beschäftigen. Ich finde, dass die einfache Reihenfolge mehrerer Bytes aber eine Stolperstelle sein könnte. Ich habe mein Protokoll dran aufgehängt, dass ich eine führende Kennung bei mehreren Bytes verwende, wobei für sehr wichtige Aktionen die Kennung als Information alleine (also NUR EIN Byte senden!) ausreicht.

    Beispiele:
    Code:
    // ============================================================================== =
    // ==   Lies den Puffer rx_buff[RX0_SIZE]
    // ============================================================================== =
      void u0st1 (void)     // Schreib+Les RX-Tx-UART0(PD) z Einstellen + FUnktionswahl
     {                                      //
      #define   KOMMANDO_APPS       'A'     // Anwendungsprogramme fahren, diverse
      #define   KOMMANDO_APPS_LEN     7     //   Annkkkk
                                            //    nn =:   01..99 - Programmnummer
                                            //      kkkk  Parameter für Prog
    //...
      #define   KOMMANDO_NORM       'N'     // Normposition der Servos anfahren
      #define   KOMMANDO_NORM_LEN     1     // Kommandolänge´
    //...
      #define   KOMMANDO_POSER      'P'     // Positionierbefehl Servo
      #define   KOMMANDO_POSER_LEN    6     //   Pn3600 {1-9, j, z} 10 Servo
                                            //    n =:  1..9, j=10, z=alle
    //...
    //      Muss nur das laengste Kommando aufnehmen koennen.
      #define   KOMMANDO_BUFFER_LAENGE   14
    //...
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //      Diese for-Schleife ist das eigentliche UART0-Stellprogramm.
      for (;;)
      {
    // ...
         /* Auch wir nutzen diese GoTo-Variante um auf Inhalt im FIFO zu warten. */
         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_NORM)   // Servo Normposition
             telegrammlaenge = KOMMANDO_NORM_LEN;   //   anfahren
    //...
                                                    // Beispiel für korrekten Befehl
           if (zeichen_aus_fifo == KOMMANDO_POSER)  // Pn3250: n{1-9, j, z} Servo,
             telegrammlaenge = KOMMANDO_POSER_LEN;  //          j=10, z alle Servos
    //...
         }
         /*  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)
         {
    //...
           /* 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
    //      13      Alle Lider auf, SlowMo 50
    //...
          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;
    //...
            default:
              break;
          }                         // Ende switch (nmbr)
        }        // Ende if (mein_rx_buff [0] == KOMMANDO_APPS)
    
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //      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)
    
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //...
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //      Wurde "KOMMANDO_POSER" erkannt ?   (PO sition SER vo stellen)
        if (mein_rx_buff [0] == KOMMANDO_POSER)     // Pa3250 ... a-j=ServoNr, z=alle
        {                                           //
    //      Mal sehen, ob ALLE zehn Servos gemeint sind:
          if ( (mein_rx_buff[1] == GRZ) || (mein_rx_buff[1] == klz) )
                                    // Alle zehn Servos ??
          {                         // ja, alle zehn Servos auf Wert ansteuern
            for ( u8 all = 1; all <= 10; all++ )
            {                       //
              mein_rx_buff[1]  = all;       // Servonummer ist 1 .. 10
              do_poser (mein_rx_buff);      // Alle zehn Servos ansteuern
            }               // Ende von for ( u8 all = 1; all..
          }                         // weiter mit else
          else                      // NUR ein einziger Servo ist dran
          {                         // Dekodiere Servonummer
            nsrv      = mein_rx_buff[1] - '0';
            if ( mein_rx_buff[1] == 'j' ) nsrv  = 10;
            if ( mein_rx_buff[1] == '0' ) nsrv  = 10;
            mein_rx_buff[1]  = nsrv;        //
            do_poser (mein_rx_buff);        // z.B.: 3250 : neuen Position          rUn
          }         // ENDE if ( (mein_rx_buff[1] == GRZ) ||..
    
        }        // Ende if (mein_rx_buff [0] == KOMMANDO_POSER)
    
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //...
    // - - - - - - - - - - - - - - -
         }          // Ende if (zeiger == telegrammlaenge)
    
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       }            // Ende for (;;) ...
    // - - - - - - - - - - - - - - -
      return;       // Ende von void u0st1 (void)
     }                              //
    // ============================================================================== =
    (Hoffentlich sind diese Auszüge meines funktionierenden PC-Controller-Schriftwechsels nicht zuuu stark gekürzt und unverständlich . . . .)

    So ist das gesendete Byte "D" eine Aufforderung, den aktuellen Zustand bestimmter Variablen über UART zu senden (DISPLAY), ein "N" stellt den NORMAL-Zustand (sozusagen Default- bzw. Startwerte) her. Um den Servo 10 (oder drei) auf die Position 3247 zu stellen funke ich eben:
    für Servo 10: P03247
    für Servo 03: P33247
    für alle ......: Pz3247
    Geändert von oberallgeier (22.09.2013 um 10:08 Uhr)
    Ciao sagt der JoeamBerg

  4. #4
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    20.08.2008
    Ort
    Kandel
    Alter
    29
    Beiträge
    1.220
    Zitat Zitat von oberallgeier Beitrag anzeigen
    Ich habe mein Protokoll dran aufgehängt, dass ich eine führende Kennung bei mehreren Bytes verwende, wobei für sehr wichtige Aktionen die Kennung als Information alleine (also NUR EIN Byte senden!) ausreicht.
    Und das ist ein sehr interessanter Fall, weil man hier nämlich mit einer Kombination aus beiden Techniken arbeiten kann/muss. Du hast einen Protokollkopf (bei dir ein Byte), der mitteilt was für einen Datagrammtyp eigentlich gesendet wird. Der Zustandsautomat müsste folglich das erste Mal eine Prüfung starten, wenn der Protokollkopf vollständig ist. Danach könnte der Code dann warten bis das Datagramm komplettiert wurde. Das reduziert die Anzahl der Zustände auf Datagrammanzahl + 1 anstelle der max. Datagrammlänge bei der reinen Zustandsautomatenlösung.

    Übrigens: In einem union können mehrere Datenstrukturen überlagert werden. Zum Beispiel besagter Protokollkopf, Datagrammtyp1, Datagrammtyp2 etc., womit du gleich auf alles bequem zugreifen kannst.

    Grüße,
    Markus
    Tiny ASURO Library: Thread und sf.net Seite

  5. #5
    Erfahrener Benutzer Roboter Genie Avatar von oderlachs
    Registriert seit
    17.05.2010
    Ort
    Oderberg
    Alter
    67
    Beiträge
    1.118
    Blog-Einträge
    1
    Danke für Eure Unterstützung, versuche jetzt zu verstehen.. aber was ich dar nicht erst begreiffe ,wie bekomme ich den Datenframe in die Serielle Übertragung, da hängt bei mir der Hase im Pfeffer, da tue ich mir mit schwer...
    Ich will auch offenlegen was damit geschehen soll:
    ein JoyStick gibt analogX und analogY , jeweils 0...255 aus, das wären 2 Byte, dann muss nochmal 0x00 oder 0xFF als "Bool" übetragen werden. die Ersten zwei Byte sollen 2 Motore steuern(PWM) der "boolsche Wert" stopt oder startet die Motoren....aber irgendwie klemme ich da fest...
    Na ja ich werde mal ein Prog anfangen und kann es dann zur Diskussion stellen..
    Vorerst vielen Dank Euch allen

    Gerhard
    Arduinos, STK-500(AVR), EasyPIC-40, PICKIT 3 & MPLABX-IDE , Linux Mint

  6. #6
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    20.08.2008
    Ort
    Kandel
    Alter
    29
    Beiträge
    1.220
    Zitat Zitat von oderlachs Beitrag anzeigen
    Danke für Eure Unterstützung, versuche jetzt zu verstehen.. aber was ich dar nicht erst begreiffe ,wie bekomme ich den Datenframe in die Serielle Übertragung, da hängt bei mir der Hase im Pfeffer, da tue ich mir mit schwer...
    Auch da funktioniert die union/struct-Variante: Anstatt den Puffer zu beschreiben und dann den struct auszulesen befüllst du auf Senderseite den struct mit deinen Daten und iterierst dann beim Senden über den byte-Puffer.

    Grüße,
    Markus
    Tiny ASURO Library: Thread und sf.net Seite

  7. #7
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    7.551
    ... In einem union ... mehrere ... überlagert ... womit du gleich auf alles bequem zugreifen kannst ...
    Bequem? Kannst? Bei mir liest sich das "könntest" - wenn ich verstünde was ein union ist. Ok, ein Anfang ist gemacht, ich habe gerade im Kernighan/Ritchie-Sachverzeichnis das union (struct, Struktur) gesucht, gefunden und die Seite aufgeschlagen *ggg*.

    Zitat Zitat von markusj Beitrag anzeigen
    ... Zustandsautomat ... Prüfung starten, wenn der Protokollkopf vollständig ist. Danach ...
    Genau, das ist das Schicke daran:
    Code:
    //...
         }
         /*  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)
         {
    //...
           /* 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")
    Geändert von oberallgeier (22.09.2013 um 17:00 Uhr)
    Ciao sagt der JoeamBerg

Ähnliche Themen

  1. Mega8 slave transmitter, 2 bytes übertragen mit i2c
    Von wobachm im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 1
    Letzter Beitrag: 21.01.2012, 23:21
  2. Wie mehrere Bytes über TWI / I2C übertragen?
    Von Teslafan im Forum C - Programmierung (GCC u.a.)
    Antworten: 9
    Letzter Beitrag: 21.01.2012, 23:15
  3. 5 Bytes per UART zwischen 2 µCs übertragen...
    Von Willa im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 9
    Letzter Beitrag: 18.09.2010, 08:09
  4. UART mehrere Bytes empfangen
    Von homedom im Forum Assembler-Programmierung
    Antworten: 1
    Letzter Beitrag: 01.08.2007, 13:37
  5. Seriell empfangene Bytes zählen, wie geht das?
    Von Toxic im Forum Controller- und Roboterboards von Conrad.de
    Antworten: 1
    Letzter Beitrag: 14.02.2006, 19:30

Berechtigungen

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