Begriff mit Wert über Serial senden/empfangen

@combie: Hab was mit substring versucht, aber irgendwie gibt er nicht das aus was ich will. Muss mal schauen, ob ich das irgendwie hinbekomme, hab da (noch) nicht so viel Ahnung von.

@ Andreas: Das Beispiel vom ersten Post läuft ohne Probleme, einfach mit Buchstaben statt Wörtern. Das Problem ist, dass ich im API Modus mit den Xbee das Packet was gesendet werden soll selbst zusammenstellen muss. Das kann ich nicht einfach so von null auf hundert aus dem Ärmel schütteln. Ich mach da Stück für Stück bis ans Ziel. Ich muss die empfangenen Daten dann ja irgendwie auswerten, da kommen ja ein paar Werte vor und nach meinen gesendeten Daten, die ich da auch noch generieren muss irgendwie. Ich weiss nicht mal, ob ich das alles hinbekomme - ist totales Neuland für mich. Sonst bleib ich beim andauernden Senden ohne Unterbruch und sobald keine Daten mehr kommen weiss ich auch, dass die Verbindung weg ist. Wäre halt nicht so elegant gelöst und braucht unnötig Strom, resp. strahlt die ganze Zeit.

Der Anwendungszweck ist zwar ein anderer, aber die Kombination aus Kennbuchstaben und Wert ist ähnlich. Schau Dir doch mal dieses Beispiel an (ganzen Thread lesen).

Gruß Tommy

Hallo Stef,

"Das Problem ist, dass ich im API Modus mit den Xbee das Packet was gesendet werden soll"

Vergesse doch einmal diesen dämlichen API-Modus. Konfiguriere die XBee im API-Modus richtig und gut ist!

Nun baust Du Dir Dein System so auf wie beschrieben. Nur die Kabel UNO-Rx/Tx <-> Mega-Tx/Rx tauscht Du gegen Deine XBee aus.

Dann schreibst Du für den UNO einen Sketch der nichts weiter macht, als ein "Hallo" sendet. Eben einen NUR "X-Text" senden. Auf dem Mega schreibst Du Dir nun einen Sketch der, nur- diesen X-Text ausgibt. Wenn Du das begriffen und hinbekommen hast, dann sendest Du mit dem UNO einen Wert. z.B. int A = 4711; float B = 47.11; Auf dem Mega schreibst Du Dir nun einen Sketch der, nur- diesen A-Wert und B-Wert ausgibt.

Wenn Du das begriffen und hinbekommen hast, dann solltest Du wissen, wie die serielle Kommunikation mit dem Arduino funktionieren könnte.

So, nun kannst Du Text und Werte mit dem Arduino/XBee senden und empfangen. Jetzt ist es an der Zeit die Sketche "Senden" & "Empfangen" hier ins Forum zu bringen.

Nun können sich die "Profis" um Deine Bit&Byte schieberei kümmern.

Wenn es nun geschafft ist, Dein 4. und 9. Byte zu selektieren, dann kannst Du Dich um das "parse" kümmern.

Ich weiß, das hier ist alles nur palaber, rababer FrittenBude- aber die serielle Kommunikation mit dem Arduino ist nicht ohne!

Ist ja schön das Tommy Dir einen RGB-Sketch zur Verfügung stellt, aber für Dich nicht zu gebrauchen. Bei Ihm leuchten RGB-Lampen, bei Dir glimmpt aber noch nicht einmal ein Glühbirne.

"selbst zusammenstellen muss. Das kann ich nicht einfach so von null auf hundert aus dem Ärmel

schütteln."

Das sagt mir, das Du noch nicht einmal weißt, was denn genau gesendet/empfangen werden soll. D.h. hier spielen alle nur "Rate mal mit Rosenthal".

Also Stef, liefer mal vernünftiges Material, dann geht es hier auch weiter. Gruß und Spaß Andreas

P.S. etwas "leichtes"

stef308: Hab was mit substring versucht, aber irgendwie gibt er nicht das aus was ich will.

"Versuchen" hört sich irgendwie nach unkoordiniertem rumprobieren an. Das ist meist wenig sinnbehaftet. Denn, selbst wenn es dann tut, weißt du immer noch nicht "warum".

stef308: Muss mal schauen, ob ich das irgendwie hinbekomme, hab da (noch) nicht so viel Ahnung von.

Das mit der "Ahnung" kannst nur du ändern. Wie kann ich dir dabei helfen? (das 1000 seitige Buch, hatte ich schon genannt, oder?)

Nebenbei: Das "keine Ahnung", oder so, musst du nicht sagen. Denn erstens, merke ich das. Da brauche ich keinen extra Hinweis.

Und zweitens, was noch viel wichtiger ist: Je öfter man Dinge wiederholt, desto fester setzen sie sich. Desto mehr stabilisiert sich der Zustand, weil man um so fester selber dran glaubt.

"Ich habe keine Ahnung" ist also eher ein böses Mantra.

Besser: "Ich lerne das!"

Also, mal vorweg: Ich weiss was ich brauche, aber es spielt überhaupt keine Rolle, ob der Sketch nun einen Wert von nur 1 oder 1023 senden muss. Ich habe am Anfang irgendwo erwähnt, dass ich Taster (LOW, HIGH, also 0 und 1) und Joysticks (Werte von 0 bis 1023) verwenden will die die Werte an einen anderen Arduino senden. Ich habe den einfachen Sketch wo ich einfach alle Werte am Ende der Loop mit Serial.write nacheinander sende und beim Empfänger in ein Array ornde und somit in der gleichen Reihenfolge wieder empfange. Jetzt habe ich mal den Sketch vom Anfang mit Buchstaben im "case" geändert, anstatt mit Wörtern. Jetzt klappt das Senden und Empfangen, von "bestimmten" und nicht allen Werten erfolgreich, und werden mit der switch/case auch wieder erfolgreich einsortiert. Das Funktioniert aber nur mit Zahlen und Buchstaben. Theoretisch habe ich gelesen, dass es auch mit HEX Werten gehen soll, aber wenn ich z.B. unter

case 0x7E:

schreibe, anstatt

case 'A':

, dann empfängt er diesen Teil wo eigentlich nach dem 0x7E kommt nicht. Hier ist der funktionierende Sketch mit Switch/Case:

Sender:

int wert = 1023;
int wert2 = 825;

void setup() {
  Serial.begin(9600);

}

void loop() {
  Serial.print("A,");
  Serial.print(wert);
  Serial.println(",");
  Serial.flush();

  Serial.print("B,");
  Serial.print(wert2);
  Serial.println(",");
  Serial.flush();

}

Empfänger:

int eins = 0;
int zwei = 0;
char var;

void setup() {
  Serial.begin(9600);

}

void loop() {
  while(Serial.available() > 0){
    var = Serial.read();
    switch (var){
      case 'A' : eins = Serial.parseInt();
                    break;
      case 'B' : zwei = Serial.parseInt();
                    break;
    }
  }
Serial.print("eins =");
Serial.println(eins);
Serial.print("zwei =");
Serial.println(zwei);
  
}

Jetzt habe ich mal versucht ein Beispiel zu verstehen und habe es ein wenig angepasst und meiner Meinung nach fehlende Teile ergänzt. Mit diesem Sketch und dem Parser strtok empfange ich mal die gesendeten z.B. 7E als Dezimalwert 126 oder 89 als 137. Das Problem hier ist noch, dass ich die Werte nicht alle erhalte, meistens nur die ersten fünf bis zum A (A auch als Dezimalwert = 10) und mit der Zeit stimmt die Reihenfolge, resp. auch die Werte die in die Arrays gehen nicht mehr mit dem gesendeten überein. Ich sehe da nur ein "Problem", dass die if Bedingung im readSerial() wohl einen Fehler haben muss und die empfangenen Daten nicht richtig speichert, resp. zu früh oder spät überschreibt. Hier mal den Sketch den ich versucht habe zu verstehen und anzupassen:

Sender:

int wert = 1023;
int wert2 = 825;

void setup() {
  Serial.begin(9600);

}

void loop() {
  Serial.print("7E");
  Serial.print(',');
  Serial.print("89");
  Serial.print(',');
  Serial.print("00");
  Serial.print(',');
  Serial.print("01");
  Serial.print(',');
  Serial.print("A,");
  Serial.print(wert);
  Serial.print(',');

  Serial.print("B,");
  Serial.print(wert2);
  Serial.println(';');
  Serial.flush();

}

Empfänger:

const int SERIAL_BUFFER_SIZE = 20; //Speicher für 20 gesendete Werte
char serialBuffer[SERIAL_BUFFER_SIZE]; //Array serialBuffer

byte key[8]; //Array key mit 8 Elementen

int arraySize = sizeof(key)/sizeof(key[0]); //Anzahl Elemente im Array key

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if (readSerial())
  {
    parseSerial();

    for (int i = 0; i < arraySize; i++){ //wenn i kleiner als Anzahl Elemente im Array key, i+1...
      Serial.print("key ");
      Serial.print(i);
      Serial.print(" = ");
      Serial.println(key[i]); //zeige Array i
      Serial.println();
  }
  }
}

bool readSerial()
{
  static byte index;

  while (Serial.available())
  {
    char c = Serial.read();

    if (c >= 1 && index < SERIAL_BUFFER_SIZE - 1)
    {
      serialBuffer[index++] = c; //Array serialBuffer [index +1] gleich gelesene Daten c
    }
    else if (c == '\n') //wenn c gleich "Ende der Daten" erkannt...
    {
      serialBuffer[index] = '\0'; //Array auf null zurücksetzen
      index = 0;
      return true; //Daten wurden gelesen
    }
  }
  return false; //Daten wurden noch nicht gelesen
}

void parseSerial()
{
  char* ptr = strtok(serialBuffer, ","); //separiert gelesenen String serialBuffer bis zum , und speichert es in ptr

  for (int i = 0; i < arraySize; i++) //für i kleiner als Anzahl Elemente im Array key, i+1...
  {
    key[i] = strtoul(ptr, NULL, 16); //Array key[i] gleich separierter String ptr, Startpunkt, Anzahl Zahlen/Buchstaben die im String gelesen werden ('0x' für HEX)
    ptr = strtok(NULL, ","); //separiert nächsten Abschnitt im String bis zum ,
  }
}

Hier ist noch der Punkt unter strtoul(ptr, NULL, 16) nicht ganz klar. Der Wert 16 habe ich wo gelesen, soll die Anzahl der Zahlen/Buchstaben im String sein, die ins Array gehen. Kann aber nicht sein, da wenn ich diesen Wert nach unten oder oben ändere, nur noch Müll empfangen wird. Ich hoffe ich bin nicht ganz auf dem Holzweg, aber ich denke ich komme der Sache schon näher und so könnte es klappen.

Zu den API Problemen die ich habe/hatte... Ich habe erfahren/gelesen, dass das Xbee das Datenpaket genau in dieser bestimmten Reihenfolge gesendet bekommen muss. Das hat mich irgendwie bisschen irritiert. Darum muss ich am Ende ja auch die empfangenen Werte aufteilen, um den für mich wichtigen Teil zu entnehmen und eine Rückmeldung zu senden. Mittlerweile verstehe ich selbst nicht mehr was unten und oben ist. Wenn die Xbees auch nur fragen, ob die Daten gesendet werden können und das Empfänger-Xbee sagt ja und empfängt die Daten, dann muss ja eine Verbindung bestehen. Wenn es nicht gesendet werden kann, dann kann das Empfänger-Xbee doch auch nichts mehr empfangen, sprich keine Rückmeldung geben. Der Sinn wäre ja darin, dass wenn das Sendemodul ausser Reichweite ist, beim Empfänger aber durch kurz vor dem Verbindungsabbruch Befehle empfangen wurden und nun ausgeführt werden, z.B. Motoren läufen, Licht ist an, ect. (ferngesteuertes Auto), dann muss ja der Empfänger das irgendwie bemerken und alles stoppen, resp. ausschalten. Irgendwie war mir das mit den Xbees klar geworden, aber momentan zweifle ich daran, dass das so überhaupt funktioniert ::)

Das Beste für heute wird sein, mal eine Pause zu machen und den Kopf frei zu kriegen.

Grüsse

Stef

Hallo, Du hast Dich wohl mächtig festgefahren... ist auch kein Wunder. Deine ReichweitenErkennung über das Senden/Empfangen von Daten fest zu machen hielt ich von Anfang an für fragwürdig.

Der sichere Weg ist, das den XBee zu überlassen. Ich habe mir einmal das Handbuch Deiner XBee angetan, nicht weil ich hier der hilfreiche Samariter bin, sondern weil ich diese XBee-Technologie sehr spannend finde.

Deine können zum einem auf eine bestimmte Sendeleistung eingestellt werden, und was für Dich zum Tragen kommt: Sie können diese auch auswerten. Zum einen können sie, vor- dem Senden von Daten feststellen wie hoch die Empfindlich ist, und zum anderem können sie das letzte Datenpaket dahin auswerten, wie hoch die Empfindlich gewesen ist. Du hast hier also 2 Parameter, an denen Du einen Abbruch aller Aktivitäten festmachen kannst. Diese Parameter kannst Du mit dem Arduino ganz bequem auswerten. Du kannst das XBee so einstellen das es diese Parameter automatich zum Arduino überträgt, oder Du läßt den Arduino diese Abfragen.

Beispiel. Nehmen wir einen Bereich von -44dBm bis -84dBm. Sagen wir ab -48dBm wird es kritisch, aber alles funktioniert noch. Wenn Dein Empfänger eine Empfindlichkeit von -48dBm feststellt, dann sendet er dem Sender eine Warnung. Du weiß jetzt also sicher, das Du Dich mit Deiner Reichweite in einem kritischen Bereich befindest. Stellt der Empfänger eine Empfindlichkeit von -45dBm fest, so kann der Arduino dem Sender das noch mitteilen, und dann den Notaus betätigen. Auf der anderen Seite kann der Sender sofort reagieren und prüfen mit welcher Empfindlichkeit er die Daten noch absetzen kann. Du kannst Dir ein ziemlich sicheres System aufbauen, das sicher abschaltet- bevor es zum BlackOut kommt. Zwei Links zum zerlegen der seriellen Daten hast Du bekommen. Eine "Anleitung" zum Versuchsaufbau hast und Software ist auch vorhanden. In der BDA Seite 64/84 kannst Du etwas über die Parameter nachlesen. Gruß und Spaß Andreas

"byte key[8]; //Array key mit 8 Elementen"

willst Du das nicht noch-einmal nachzählen?

SkobyMobil: "byte key[8]; //Array key mit 8 Elementen"

willst Du das nicht noch-einmal nachzählen?

Warum sollte er das? Das sind 8 Elemente (Index 0 bis 7).

Gruß Tommy

Hallo zusammen

Habe heute nochmals bisschen Zeit gefunden, das Beispiel von Tommy weiter zu studieren. Das hat mir glaube ich wirklich geholfen. Ich muss nur noch den letzten Teil bei mir einbauen, wo mit switch/case die Parameter zugeordnet werden - das wollte ich ja haben. Nun aber noch ein paar Fragen dazu. Habe mal Dein Teil kopiert der mir noch fehlt und versuch zu verstehen was da passiert.

boolean auswerten() {
char *ptr, *p, *savePtr, *saveP;
const char delim[] = ",";
char first;
boolean status = false;
int wert;

// inStr zerlegen an ,
  // strtok ist nicht wiedereintrittsfähig,
  // deshalb strtok_r nehmen, um auch den Doppelpunkt auszuwerten zu koennen
  ptr = strtok_r(inStr,delim,&savePtr); //separiert String inStr bei delim und speichert es in ptr und savePtr
  while (ptr != NULL) { 
    // ist ein Doppelpunkt drin?
    if (strchr(ptr,':')) { //wenn in ptr ein : drin ist, dann...
      // mit Doppelpunkt
      // neuer Stringtokenizer
      p = strtok_r(ptr,":",&saveP); //separiere String ptr bei : und speichere es in p und saveP
      if (p != NULL) {
        // erster Teil Farbe
        first = p[0];
      }
      p = strtok_r(NULL,":",&saveP); //separiert nächsten Abschnitt im String ptr bis zum : und speichert es in p und saveP
      if (p != NULL) {
        // zweiter Teil Farbwert
        wert = atoi(p); //konvertiert separierter String p zu int
      }
    }
    else {
      // ohne Doppelpunkt
      first = ptr[0]; //speichert separierter String in first
      wert = atoi(ptr+1); //konvertiert separierter String ptr[1] zu int
    }
    // begrenzen auf 255
    if (wert > 255) {
      wert = 255;
    }
    // keine negativen Werte
    if (wert < 0) {
      wert = 0;
    }
    switch (first) {
      case 'a':   // alles aus
      case 'A':    hellRot = dunkel;
                  hellGruen = dunkel;
                  hellBlau = dunkel;
                  status = true;
                  break;
      case 'r':    // rot
      case 'R':    hellRot = wert;
                  status = true;
                  break;
      case 'g':    // gruen
      case 'G':    hellGruen = wert;
                  status = true;
                  break;
      case 'b':    // blau
      case 'B':    hellBlau = wert;
                  status = true;
                  break;
    }
    #ifdef DEBUG
    Serial.print("Farbe: ");
    Serial.print(first);
    Serial.print(" Wert: ");
    Serial.println(wert);
    #endif
    // naechster Token. NULL, wenn nichts gefunden
    ptr = strtok_r(NULL,delim,&savePtr);
  }
  return status;
}

Nun zu den Fragen: - Ich sollte in diesem Fall strtok_r anstelle wie aktuell bei mir strtok, da ich ja gewisse Buchstaben, Werten zuordnen muss und daher auch zwei Separierzeichen brauche. Was aber ist der dritte Parameter in strtok_r? Ich habe mal kommentiert "speichert zusätzlich in savePtr, aber das kann ja nicht sein, oder? Ich habe was gelesen, dass das das zweite Separierzeichen sein sollte, aber das ist es bei Dir ja nicht? - Unten bei "else", wenn kein Doppelpunkt vorhanden ist, dann wird der String zuerst in char first und dann in int wert konvertiert. Dieser String ptr besteht ja aber aus Buchstabe und Zahl (b200). Wird dann automatisch weil first als charakter definiert ist nur das b annehmen und der wert, weil in integer umgewandelt nur die Zahl?

Diesen Teil werde ich morgen bei Gelegenheit mal versuchen noch einzubauen. Mal sehen wie es dann funktioniert.

@Andreas: Dem Xbee muss aber der Befehl dafür gesendet werden, und das geschieht ja (so wie ich das verstanden habe) über die HEX Werte beginnend mit 0x7E als Startdelimeter, dann die Datenlänge, ID und was weiss ich. Wenn das nicht in dem Format gesendet wird, dann gibt der Xbee auch keine Antwort zurück. Das hiesst ich muss ihm die FramID 0x01 in der vierten Stelle vor meinen Daten mitsenden, damit ich vom anderen Xbee die Rückmeldung 0x89 und 0 bekomme, dass die Daten gesendet wurden. Die FrameID kann ja varieren, da kann ich ja dann auch was anderes mitsenden, sodass ich wie in Deinem Beispiel die Rückmeldung über Signalstärke erhalte. Wenn ich das aber nicht senden kann, dann nütz mir der API Modus rein gar nichts. Die Xbee geben nicht einfach so Rückmeldung. Das habe ich gemeint und hat mich verwirrt. Aber es wird glaube ich klarer...

Die Seiten 64 ist die Einstellung des PowerLevels, das ist klar, muss ich dann einstellen was für mich funktioniert (muss ich dann versuchen was noch geht und was nicht), und Seite 84 die DB Werte.... Das ist ja noch in den normalen Einstellungen ohne API! Das bedeutet, ich könnte vermutlich den Wert vom Xbee erhalten und muss den erhaltenen HEX Wert dann einfach so programmieren, dass wenn er so und so ist, der letzte mögliche Befehl gesendet wird damit alles stoppt und ich mein Notaus habe. Muss ich dann nochmals genauer lesen, wie dieser Wert automatisch an den Arduino gegeben wird. => Dann brauche ich diesen doofen API Modus ja gar nicht und muss da nicht unnötige Daten generiern und mitsenden!

Müsste dann nicht eigentlich mein erster Sketch mit switch/case und den Probewerten A und B ausreichen? Die Frage wäre dort nur, warum kann ich keine HEX Werte in case schreiben und dann unter einem definierten int speichern? Ich erhalte da immer 0. Oder ist mein jüngster Sketch ohnehin besser geeignet? Ich werde morgen mal den letzten Teil versuchen zu ergänzen.

Grüsse

Stef

Ja, der savePtr ist ein Pointer der Art -- wo war ich bisher, wo muss ich weiter machen. Die verschiedenen Versionen rühren daher, dass das Format ziemlich frei gehalten wurde. Das ist als Kommentar oben drin beschrieben.

Das muss man nicht so frei halten. Man kann auch festlegen, dass immer ein Doppelpunkt drin sein muss oder andere Festlegungen.

Wichtig ist, dass man weiß, wie man das Format aufgebaut haben will.

Gruß Tommy

Ja, das habe ich schon gelesen. Wenn ich diesen Sketch (von mir bisschen abgeändert wie im letzten Post auf Seite eins, zweiter Sketch) so brauche, dann würde ich die HEX Werte mit Leerschlag oder Komma trennen und meine Werte die ich mit Buchstaben sende mit einem anderen Trennzeichen. Aber zum Testen könnte ich natürlich auch einfach nur alles mit einem Trennzeichen trennen - ist ja auch einfacher zu schreiben... stimmt schon! Dann schau ich mir das morgen mal an, ob es dann läuft wies soll.

Den anderen Sketch mit switch/case habe ich hinbekommen, HEX zu senden und empfangen und Buchstaben mit Zahlenwerten. Vom Gefühl her, braucht das länger als die Methode im anderen Sketch, sprich wie bei Dir, Tommy. Oder täusche ich mich da? Auch finde ich bei Deinem Sketch elegant gelöst, dass es nicht einfach immer im Empfagsmodus steckt, sondern nur wenn wirklich Daten reinkommen - ob das dann so wichtig ist, da die Loop ja eh weiterläuft wenn keine Daten kommen, aber sicherlich eleganter :)

Hier noch der aktualisiert Sketch switch/case mit HEX und Buchstaben/Zahlenwerte.

Sender:

int wert = 1023;
int wert2 = 825;

void setup() {
  Serial.begin(9600);

}

void loop() {
  Serial.write(0x7E);
  Serial.println(wert);
  Serial.flush();

  Serial.print("B");
  Serial.println(wert2);
  Serial.flush();

}

Empfänger:

int eins = 0;
int zwei = 0;
char var;

void setup() {
  Serial.begin(9600);

}

void loop() {
  while(Serial.available() > 0){
    var = Serial.read();
    switch (var){
      case 0x7E : eins = Serial.parseInt();
                    break;
      case 'B' : zwei = Serial.parseInt();
                    break;
    }
  }
Serial.print("eins =");
Serial.println(eins);
Serial.print("zwei =");
Serial.println(zwei);
  
}

Grüsse

Stef

Ob Du HEX (0xff) oder dezimal (255) benutzt, ist dem prozessor sowas von egal. Für ihn ist beides B11111111, also ein Byte, bei dem alle Bits 1 sind.
Alle anderen Darstellungen sind nur zum Verständnis für die Nase vor dem Monitor.

Gruß Tommy

Stimmt schon, aber gemäss Handbuch der Xbees müsste im Hex Format gesendet werden, damit die eine Rückmeldung geben. Wenn ich das jetzt aber ohne API gedöns über den DB Wert machen kann, dann sendet mir das Xbee ja den Wert und da weiss ich er sollte in Hex das und das haben, dann spielt es keine Rolle, muss nur richtig definiert sein. Der Einfachheit halber wäre aber Hex auch besser, dann kann man nachvollziehen was das für Werte sind und warum und kann mit dem Handbuch abgleichen.

Grüsse

Stef

aber gemäss Handbuch der Xbees müsste im Hex Format gesendet werden,

Nein! Im Handbuch wurde die hexadezimale Repräsentation/Darstellung der Daten gewählt. Damit du sie leicht lesen kannst.

Bitte unterscheide zwischen Daten und Repräsentation. (Dein Xbee kann es nicht, für den sieht alles gleich aus) Hier wird dir jeder Buchstabe in den üblichsten Repräsentationen vorgeführt Keine Sorge, es gibt noch viel mehr.

Hallo

Ja, stimmt! Ist eigentlich alles 0 und 1, aber allein wegen der Lesbarkeit des Sketchs wäre es von Vorteil. Aber das ist ja auch egal, am Ende muss er ja was senden und das selbe wieder Empfangen.

Ich habe heute mal den Sketch von mir statt mit strtok, mit strtok_r abgeändert. Nun empfange ich gar nichts mehr. Ich sehe momentan grad nicht was fehlt. Könnte da mal jemand einen Blick drüber werfen? Ich schau mir das ganze morgen nochmals an, hab für heute genug :neutral_face:

Sender:

int wert = 1023;
int wert2 = 825;

void setup() {
  Serial.begin(9600);

}

void loop() {
  Serial.print(0x7E);
  Serial.print(' ');
  Serial.print(0x89);
  Serial.print(' ');
  Serial.print(0x00);
  Serial.print(' ');
  Serial.print(0x01);
  Serial.print(' ');
  Serial.print("A");
  Serial.print(',');
  Serial.print(wert);
  Serial.print(' ');

  Serial.print("B");
  Serial.print(',');
  Serial.println(wert2);
  
  Serial.flush();

}

Ich habe überall Serial.print drin gelassen. Habe mal gelesen, dass Serial.print in Serial.write umgewandelt wird? Spielt aber nicht so eine Rolle, oder? Ist ja doof im Sendeteil Für HEX write zu nehmen und für die Zeichen dann wieder print...

Empfänger:

const int SERIAL_BUFFER_SIZE = 20; //Speicher für 20 gesendete Werte
char serialBuffer[SERIAL_BUFFER_SIZE]; //Array serialBuffer

int startDelimeter;
int lengthByte;
int apiIdentifier;
int apiFrameId;
int A;
int B;

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if (readSerial())
  {
    parseSerial();

      Serial.print("serialBuffer = ");
      Serial.println(serialBuffer);
      Serial.print("startDelimeter = ");
      Serial.println(startDelimeter);
      Serial.print("lengthByte = ");
      Serial.println(lengthByte);
      Serial.print("apiIdentifier = ");
      Serial.println(apiIdentifier);
      Serial.print("apiFrameId = ");
      Serial.println(apiFrameId);
      Serial.print("A = ");
      Serial.println(A);
      Serial.print("B = ");
      Serial.println(B);
  
  }
}

bool readSerial()
{
  static byte index;

  while (Serial.available())
  {
    char c = Serial.read();

    if (c >= 0 && index < SERIAL_BUFFER_SIZE - 1)
    {
      serialBuffer[index++] = c; //Array serialBuffer [index +1] gleich gelesene Daten c
    }
    else if (c == '\n') //wenn c gleich "Ende der Daten" erkannt...
    {
      serialBuffer[0] = '\0'; //Array auf null zurücksetzen
      index = 0;
      return true; //Daten wurden gelesen
    }
  }
  return false; //Daten wurden noch nicht gelesen
}

void parseSerial()
{
  char* ptr, * p, * savePtr, * saveP;
  char first;
  char def;
  int wert;
  
  ptr = strtok_r(serialBuffer, ' ', &savePtr); //separiert gelesenen String serialBuffer bis zum Leerschlag und speichert es in ptr und savePtr

  while(ptr != NULL){
    if (strchr(ptr,',')){ //wenn in ptr ein , drin ist, dann...
      p = strtok_r(ptr,',',&saveP); //separiert String ptr beim , und speichert es in p und saveP
      if (p != NULL){
        def = p[0]; //erster Teil Bezeichnung
      }
      p = strtok_r(NULL, ',', &saveP); //separiert nächsten Abschnitt im String p bis zum , und speichert es in p und saveP
      if (p != NULL){
        wert = atoi(p); //konvertiert zweiten Teil des separierten Strings p zu int
      }
    }
    else { //wenn kein , vorhanden
    first = ptr; //speichert separierten String ptr in first (HEX Werte)
  }

  switch (first, def){

    case 0x7E: startDelimeter = first;
               break;
    case 0x89: lengthByte = first;
               break;
    case 0x00: apiIdentifier = first;
               break;
    case 0x01: apiFrameId = first;
               break;
    case 'A':  A = wert;
               break;
    case 'B':  B = wert;
               break;

  }

    ptr = strtok_r(NULL, ' ', &savePtr); //separiert nächsten Abschnitt im String ptr bis zum Leerzeichen
    
  }
}

Grüsse

Stef

Wenn Du die Daten vor dem Lesen vernichtest, kann er auch nichts empfangen:

serialBuffer[0] = '\0'; //Array auf null zurücksetzen

Das darfst Du erst machen, wenn Du alles ausgewertet hast.

Gruß Tommy

Danke, habe dort eigentlich “serialBuffer[index] = ‘\0’;” als Abschlusszeichen drin gehabt.
Habe jetzt als Abschluss ein ‘\n’ drin und unten eine if-Abfrage, sobald ‘\n’, dann soll er den Buffer zurücksetzen. Funktioniert jetzt auch, dass ich Daten erhalte, aber sie werden nicht zugeordnet. Auch stimmt der Empfangene Datensatz nicht immer überein. Wo liegt da noch der Hund begraben, dass die getrennten Strings nicht zugewiesen werden?

Empfänger sieht jetzt so aus:

const int SERIAL_BUFFER_SIZE = 30; //Speicher für 20 gesendete Werte
char serialBuffer[SERIAL_BUFFER_SIZE]; //Array serialBuffer

int startDelimeter;
int lengthByte;
int apiIdentifier;
int apiFrameId;
int A;
int B;

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if (readSerial())
  {
    parseSerial();

      Serial.print("serialBuffer = ");
      Serial.println(serialBuffer);
      Serial.print("startDelimeter = ");
      Serial.println(startDelimeter);
      Serial.print("lengthByte = ");
      Serial.println(lengthByte);
      Serial.print("apiIdentifier = ");
      Serial.println(apiIdentifier);
      Serial.print("apiFrameId = ");
      Serial.println(apiFrameId);
      Serial.print("A = ");
      Serial.println(A);
      Serial.print("B = ");
      Serial.println(B);
  
  }
}

bool readSerial()
{
  static byte index;

  while (Serial.available())
  {
    char c = Serial.read();

    if (c >= 0 && index < SERIAL_BUFFER_SIZE - 1 && c != '\n')
    {
      serialBuffer[index++] = c; //Array serialBuffer [index +1] gleich gelesene Daten c
    }
    else if (c == '\n') //wenn c gleich "Ende der Daten" erkannt...
    {
      serialBuffer[index] = '\n';
      index = 0;
      return true; //Daten wurden gelesen
    }
  }
  return false; //Daten wurden noch nicht gelesen
}

void parseSerial()
{
  char* ptr, * p, * savePtr, * saveP;
  char first;
  char def;
  int wert;
  
  ptr = strtok_r(serialBuffer, ' ', &savePtr); //separiert gelesenen String serialBuffer bis zum Leerschlag und speichert es in ptr und savePtr

  while(ptr != NULL){
    if (strchr(ptr,',')){ //wenn in ptr ein , drin ist, dann...
      p = strtok_r(ptr,',',&saveP); //separiert String ptr beim , und speichert es in p und saveP
      if (p != NULL){
        def = p; //erster Teil Bezeichnung
      }
      p = strtok_r(NULL, ',', &saveP); //separiert nächsten Abschnitt im String p bis zum , und speichert es in p und saveP
      if (p != NULL){
        wert = atoi(p); //konvertiert zweiten Teil des separierten Strings p zu int
      }
    }
    else { //wenn kein , vorhanden
    first = atoi(ptr); //speichert separierten String ptr in first (HEX Werte)
  }

  switch (first, def){

    case 0x7E: startDelimeter = first;
               break;
    case 0x89: lengthByte = first;
               break;
    case 0x00: apiIdentifier = first;
               break;
    case 0x01: apiFrameId = first;
               break;
    case 'A':  A = wert;
               break;
    case 'B':  B = wert;
               break;

  }

    ptr = strtok_r(NULL, ' ', &savePtr); //separiert nächsten Abschnitt im String ptr bis zum Leerzeichen
    
  }

  if (ptr == '\n' && p == '\n'){
    serialBuffer[0] = '\0'; //Array auf null zurücksetzen
  }
}

Grüsse

Stef

Wo liegt da noch der Hund begraben, dass die getrennten Strings nicht zugewiesen werden?

Vermutlich ein Fehler im Parser. Oder noch tiefer, schon in der Grammatik.

Und genau diese Grammatik, welche du da verwenden möchtest, ist mir noch nicht klar.

Falls dir nicht klar ist, was ich hier mit "Grammatik" meine: In natürlichen/menschlichen Sprachen ist eine Grammatik/Satzbau einzuhalten, damit Sprecher und Hörer erfolgreich kommunizieren können. Auch ist ein gemeinsames Vokabular unabdingbar.

Menschen können eine fehlerhafte Grammatik und Schreibfehler teilweise korrigieren. Arduinos können das nicht.

Die Lösung deiner Probleme beginnt also erstmal damit, eine Glas harte, messerscharfe Grammatik zu erfinden! Zu definieren.

Diese Definition muss dann für Sender und Empfänger identisch sein.

Diese Definition hätte ich jetzt mal gerne gesehen, um prüfen zu können, ob dein Parser diese abarbeiten kann.

(fertige Alternativen interessieren dich nicht, oder?)

Hier nochmals mein Sender:

int wert = 1023;
int wert2 = 825;

void setup() {
  Serial.begin(9600);

}

void loop() {
  Serial.print(0x7E);
  Serial.print(' ');
  Serial.print(0x89);
  Serial.print(' ');
  Serial.print(0x00);
  Serial.print(' ');
  Serial.print(0x01);
  Serial.print(' ');
  Serial.print("A");
  Serial.print(',');
  Serial.print(wert);
  Serial.print(' ');

  Serial.print("B");
  Serial.print(',');
  Serial.println(wert2);
  
  Serial.flush();

}

und Empfänger:

const int SERIAL_BUFFER_SIZE = 30; //Speicher für 20 gesendete Werte
char serialBuffer[SERIAL_BUFFER_SIZE]; //Array serialBuffer

int startDelimeter = 0;
int lengthByte = 0;
int apiIdentifier = 0;
int apiFrameId = 0;
int A = 0;
int B = 0;

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if (readSerial())
  {
    parseSerial();

      Serial.print("serialBuffer = ");
      Serial.println(serialBuffer);
      Serial.print("startDelimeter = ");
      Serial.println(startDelimeter);
      Serial.print("lengthByte = ");
      Serial.println(lengthByte);
      Serial.print("apiIdentifier = ");
      Serial.println(apiIdentifier);
      Serial.print("apiFrameId = ");
      Serial.println(apiFrameId);
      Serial.print("A = ");
      Serial.println(A);
      Serial.print("B = ");
      Serial.println(B);
  
  }
}

bool readSerial()
{
  static byte index;

  while (Serial.available())
  {
    char c = Serial.read();

    if (c >= 0 && index < SERIAL_BUFFER_SIZE - 1 && c != '\n')
    {
      serialBuffer[index++] = c; //Array serialBuffer [index +1] gleich gelesene Daten c
    }
    else if (c == '\n') //wenn c gleich "Ende der Daten" erkannt...
    {
      serialBuffer[index] = '\n';
      index = 0;
      return true; //Daten wurden gelesen
    }
  }
  return false; //Daten wurden noch nicht gelesen
}

void parseSerial()
{
  char* ptr, * p, * savePtr, * saveP;
  char first;
  char def;
  int wert;
  
  ptr = strtok_r(serialBuffer, ' ', &savePtr); //separiert gelesenen String serialBuffer bis zum Leerschlag und speichert es in ptr und savePtr

  while(ptr != NULL){
    if (strchr(ptr,',')){ //wenn in ptr ein , drin ist, dann...
      p = strtok_r(ptr,',',&saveP); //separiert String ptr beim , und speichert es in p und saveP
      if (p != NULL){
        def = p; //erster Teil Bezeichnung
      }
      p = strtok_r(NULL, ',', &saveP); //separiert nächsten Abschnitt im String p bis zum , und speichert es in p und saveP
      if (p != NULL){
        wert = atoi(p); //konvertiert zweiten Teil des separierten Strings p zu int
      }
    }
    else { //wenn kein , vorhanden
    first = atoi(ptr); //speichert separierten String ptr in first (HEX Werte)
  }

  switch (first, def){

    case 0x7E: startDelimeter = first;
               break;
    case 0x89: lengthByte = first;
               break;
    case 0x00: apiIdentifier = first;
               break;
    case 0x01: apiFrameId = first;
               break;
    case 'A':  A = wert;
               break;
    case 'B':  B = wert;
               break;

  }

    ptr = strtok_r(NULL, ' ', &savePtr); //separiert nächsten Abschnitt im String ptr bis zum Leerzeichen
    
  }

  if (ptr == '\n' && p == '\n'){
    serialBuffer[0] = '\0'; //Array auf null zurücksetzen
  }
}

Alternativen gehen schon auch, sofern ich sie gebrauchen kann. Ich habe hier eigentlich die ganze Grammatik definiert, dass es funktionieren müsste - ich sehe nichts mehr was nicht stimmen könnte.

Du solltest den Abschluß sauber machen (mit '\0' abschließen, nicht mit '\n'): serialBuffer[index] = '\0';

Gruß Tommy

Das habe ich gemacht, aber dann bekomme ich noch komischere Werte eingelesen. Switch/Case funktioniert aber trotzdem nicht, erhalte die Werte nur am Stück eingelesen.

Hier mal die Ausgabe aus dem Seriellen Monitor:

serialBuffer = 126 137 0 1 A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 137 0 1 A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 137 0 1 A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 137 0 1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 137 0 1 A,1A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 137 0 1 0 1 A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 26 137 0 1 A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 126 137 0 1 A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 26 137 0 1 A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 126 137 0 1 A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 26 137 0 1 A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 126 137 0 1 A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 26 137 0 1 A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 26 137 0 1 A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 126 137 0 1 A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 26 137 0 1 A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 126 137 0 1 A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 26 137 0 1 A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 126 137 0 1 A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 26 137 0 1 A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0
serialBuffer = 126 26 137 0 1 A,1023 B,825

startDelimeter = 0
lengthByte = 0
apiIdentifier = 0
apiFrameId = 0
A = 0
B = 0

Das stimmt: serialBuffer = 126 137 0 1 A,1023 B,825, dann setzt er Werte ein die es nicht gibt oder macht Zusatzwerte in die Folge.