Serielle Datenstring vom Computer im Adruino Mega einlesen und aufteilen

my_xy_projekt:

  • Du hast den Aufbau ja auch :wink:

Momentan eher nicht, da ich zwischenzeitlich verschiedene andere Themen bearbeitet habe. Außerdem hat meine Frau Urlaub, weshalb ich nicht so viel Zeit für Arduino habe. Sie steckt voller Ideen ;D

Aber ich schaue drauf, sobald es geht :smiley:

agmue:
Sie steckt voller Ideen ;D

Doch hoffentlich welchen zu Arduino & Co. :wink:

Gruß Tommy

@xy-projekt
hab Dir mal meine Ergebnisse angehangen und mein ganzes Projekt, welches ich gern verwirklichen möchte.
Nun ja, das mit dem senden kann ich wegen fehlender intelligenz :slight_smile: wohl vergessen, vielleicht nur die Zahlen für Zeiten und Runden für Spur 1 bis 6 mal schauen.....

so, mir macht die Sommerzeit zu schaffen, wird Zeit zum :sleeping:

Euch allen eine gute Nacht, und bleibt gesund !!!

Aufbau-Rennstrecke.pdf (173 KB)

Serial Ausgabe mit 9600 schnelle folge.pdf (392 KB)

Serial Ausgabe mit 9600.pdf (206 KB)

Serial Ausgabe mit 115200.pdf (206 KB)

Wenn Du so ein Rennen startest, sind doch die Infos zu den Fahrern vorher bekannt.
Die kann man einmal vor dem Rennen übertragen und abspeichern.
Dann braucht man doch eigentlich nur die 6 Rundenwerte zu übergeben oder habe ich das falsch verstanden?

Gruß Tommy

Nur kurz, weil ich es heute tatsächlich geschafft habe mal was anderes machen zu dürfen - wird morgen vermutlich wieder anders aussehen...

Ich habe meinen Code aus #67 gefüttert mit dem von heute via einem Nano-Sender.
Nur soviel: Ich hab nen netten Effekt :wink:

Das wird. Ich hab das mit den Clients gelesen. Auch das wird - die Probleme beim Einlesen ergeben sich nicht beim Aussenden. Letzteres kannst Du steuern. Ersteres nicht.

@Tommy56
Der Datensatz ist komplett.
Es ist sicher möglich den einen oder anderen Wert zu verwerfen - aber das kann nur via Vergleich letzterWert != aktuellerWert gehen.
Das geht aber erst, wenn sichergestellt ist das die Inhalte komplett und sicher verarbeitet werden.

[OT]Auf "Nordschleifennachbauten" werden die Fahrer im Rennen getauscht. ;)[/OT]

Fehlerfrei.
Sender: Nano mit Softwareserial bis 115200 getestet
[edit] Die Ausgaben um einen Zeilenumbruch ergänzt.[/edit]

// Umsetzung Daten einlesen
// Dazu gehört SendeSketch https://forum.arduino.cc/index.php?topic=694542.msg4942899#msg4942899
// Vorgaben:
const byte fahrer = 4;    // Anzahl Fahrer
const byte charName = 30; // Anzahl Stellen Fahrername

// Bxx ist ein Datensatz
unsigned int BRZvk;       // Beste Rundenzeit Vorkomma
unsigned int BRZnk;       // Nachkomma
char BRF[charName];       // Fahrername
unsigned int BRS;         // Beste Rundennummer

// AR - RZ - F werden mehrere Datensätze
unsigned int AR[fahrer];  // Runden des Fahrer
unsigned int RZvk[fahrer];// Rundenzeit Vorkomma des Fahrer
unsigned int RZnk[fahrer];// Rundenzeit Nachkomma
char F[fahrer][charName]; // Fahrername
// Ende Vorgaben Umsetzung Daten einlesen

bool ausgabe = false;     // Wartet auf Vollständigkeit

void setup()
{
  Serial.begin(115200);   // Serieller Monitor
  Serial.println(F("Start..."));
  Serial1.begin(115200);  // Eingang der Daten sicher getestet von 9600 - 115200
}

void loop()
{
  readSerial();
  serMon();
}

void readSerial()
{
  const int breakTimeRead = 500;       // Abbruchzeit in ms
  char readChar;                       // Einzelnes Zeichen
  static byte x = 0;                   // Position im Array
  static char buf[30] = {0};           // Zwischenspeicher

  unsigned long lastmillis = millis(); // Startzeit merken...
  while (Serial1.available() > 0 && millis() - lastmillis < breakTimeRead)
  {
    readChar = Serial1.read();         // Einlesen
    Serial.print(readChar);
    if (readChar == ';')               // Feldende
    {
      buf[x] = '\0';                   // CharArray abschliessen
      teileBuf(buf);                   // Übergeben zum teilen
      x = 0;                           // Position im Array rücksetzen
    }
    else
    { if (!isControl(readChar))        // Zeichen ist kein Steuierzeichen
      {
        buf[x] = readChar;             // Dann aufnehmen
        x++;                           // neue Position setzen
      }
    }
  }
}

void teileBuf(char *buf)               // Teilt den Puffer
{
  char *c;                             // Zwischenspeicher
  c = strtok(buf, ":");                // Übernehme bis Trennzeichen 1

  if (!strncmp(c, "BRZ", 3)) {         // Feldname
    BRZvk = atoi(strtok(NULL, ","));   // Erste Zahl - Trenner ist ,
    BRZnk = atoi(strtok(NULL, ","));   // zweite Zahl
  }
  else if (!strncmp(c, "BRF", 3)) {    // Feldname
    strcpy(BRF, strtok(NULL, ":"));    // Fahrername - Trenner ist :
  }
  else if (!strncmp(c, "BRS", 3)) {    // Feldname
    BRS = atoi(strtok(NULL, ":"));     // Zahl
  }
  else if (!strncmp(c, "AR", 2)) {
    int x = c[2] - 49;
    AR[x] = atoi(strtok(NULL, ":"));
  }
  else if (!strncmp(c, "RZ", 2)) {
    int x = c[2] - 49;
    RZvk[x] = atoi(strtok(NULL, ","));
    RZnk[x] = atoi(strtok(NULL, ","));
  }
  else if (!strncmp(c, "F", 1)) {
    int x = c[1] - 49;
    strcpy(F[x], strtok(NULL, ":"));
    if (x == fahrer-1)                        // Datensatz endet mit Fahrername 4 / Array endet mit 3(!)
    {                      
      ausgabe = true;                  // Freigabe für SerMon
    }
  }
  memset(buf, 0, 30);
}

void serMon()
{
  if (ausgabe == true)  // Wenn Ausgabe frei
  {
    ausgabe = false;
    Serial.println();   // Umbruch noch eingefügt
    Serial.print("BRS: ");  Serial.print(BRS);
    Serial.print(" BRZ: "); Serial.print(BRZvk); Serial.print(" - "); Serial.print(BRZnk);
    Serial.print(" BRF: "); Serial.println(BRF);

    for (int i = 0; i < fahrer; i++)
    {
      Serial.print("AR"); Serial.print(i + 1); Serial.print(": "); Serial.print (AR[i]);
      Serial.print(" RZ"); Serial.print(i + 1); Serial.print(": "); Serial.print(RZvk[i]); Serial.print(" - "); Serial.print(RZnk[i]);
      Serial.print(" F"); Serial.print(i + 1); Serial.print(": "); Serial.println(F[i]);
    }
    Serial.println();
  }
}
17:21:55.400 -> BRZ:3,801;BRF:Friedhelm Busch;BRS:861;AR1:861;RZ1:3,801;F1:Friedhelm Busch;AR2:861;RZ2:6,342;F2:Max Jägermeister;AR3:861;RZ3:7,699;F3:Paul Mustermann;AR4:861;RZ4:7,944;F4:Thorsten Hesse;
17:21:55.400 -> BRS: 861 BRZ: 3 - 801 BRF: Friedhelm Busch
17:21:55.400 -> AR1: 861 RZ1: 3 - 801 F1: Friedhelm Busch
17:21:55.400 -> AR2: 861 RZ2: 6 - 342 F2: Max Jägermeister
17:21:55.400 -> AR3: 861 RZ3: 7 - 699 F3: Paul Mustermann
17:21:55.433 -> AR4: 861 RZ4: 7 - 944 F4: Thorsten Hesse
17:21:55.433 -> 
17:21:55.433 ->

Bei 6 Fahrern aber nur 4 Datenfeldern (Erste Zeile im Code von 4 auf 6 geändert)
Dazu die Ausgabe in Zeile 90 auf x=3 setzen.

17:27:22.468 -> BRZ:5,220;BRF:Friedhelm Busch;BRS:926;AR1:926;RZ1:5,220;F1:Friedhelm Busch;AR2:926;RZ2:7,416;F2:Max Jägermeister;AR3:926;RZ3:6,683;F3:Paul Mustermann;AR4:926;RZ4:8,776;F4:Thorsten Hesse;
17:27:22.468 -> BRS: 926 BRZ: 5 - 220 BRF: Friedhelm Busch
17:27:22.501 -> AR1: 926 RZ1: 5 - 220 F1: Friedhelm Busch
17:27:22.501 -> AR2: 926 RZ2: 7 - 416 F2: Max Jägermeister
17:27:22.501 -> AR3: 926 RZ3: 6 - 683 F3: Paul Mustermann
17:27:22.501 -> AR4: 926 RZ4: 8 - 776 F4: Thorsten Hesse
17:27:22.501 -> AR5: 0 RZ5: 0 - 0 F5: 
17:27:22.501 -> AR6: 0 RZ6: 0 - 0 F6: 
17:27:22.501 -> 
17:27:22.501 ->

Guten Abend zusammen,

ich hoffe Ihr habt auch mal die Nase in die Sonne halten können. Mir tat´s gut... nach den Rückschlägen von gestern. :wink: Das fantastische Werk von Xy-projekt hat mir heute den A-Tritt verpasst den ich brauchte um nicht aufzugeben.

Tausenddank an xy-projekt du haust echt tief in die tasten für mich. Bewundere Dich und zieh zugleich meinen Hut vor Dir.

Absolut 100% Fehlerfrei, auch der Renncomputer ist nicht in der Lage den Sketch aus der Ruhe zu bringen.
@Tommy
Die ersten drei Werte im Datensatz könnten sich im Laufe des Rennen verändern, aber nur wenn ein Fahrer besser ist als der darin enthaltene Wert. Die Zuweisung der Fahrer auf eine feste Spur ist leider nicht möglich, da wie xy-projekt schon angedeutet hat, die Fahrer die Spuren nach x-Zeit wechseln so das jeder Fahrer jede Spur fährt.

Benziner:
ich hoffe Ihr habt auch mal die Nase in die Sonne halten können.

Absolut 100% Fehlerfrei, auch der Renncomputer ist nicht in der Lage den Sketch aus der Ruhe zu bringen.

Die Finger sind trotz Handschuhe schwarz vor Erde geworden :wink:
Naja, wenn man es mit dem informell vollständigen Ansatz macht, geht das auch.

Nach dem Blockbild weiss ich jetzt auch, was Du vor hast - das wird...
Da ist die NRF-Geschichte das kleinste Übel.

Aber teste das erstmal richtig aggressiv aus.
Dann erklär ich ggfls. auch, wo mein Denkfehler war.

Guten Tag, mein Name ist Erwin Lottemann und ich bin 56 Millionen Jahre alt.....

Nun ja, fast soviele Datensätze sind bis jetzt durch die Leitungen geflogen, sprich er lief seit gestern Abend bis jetzt durch.
Und was soll ich sagen.... 100%( Okay hab jetzt nicht jeden einzelen kontrolliert :wink: ) aber er macht noch immer was er soll und das ohne offensichtliche Fehler.

Für Erklärungen bin ich immer zu haben, darf nur nicht kompliziert werden :grinning:

Benziner:
Und was soll ich sagen… 100%( Okay hab jetzt nicht jeden einzelen kontrolliert :wink: ) aber er macht noch immer was er soll und das ohne offensichtliche Fehler.

Ja, das habe ich erwartet und wäre hochgradig enttäuscht gewesen, wenn das nicht mit meinem Sendesketch funktioniert hätte…

Für Erklärungen bin ich immer zu haben, darf nur nicht kompliziert werden :grinning:

Du wolltest es nicht anders!
Ich werde mich versuchen zu beschränken!
Darum gehe ich nicht auf das verkürzte in der Auswertung ein, sondern nur und ausschliesslich auf die Datenerfassung:

Ok. Fangen wir mit dem Code aus #67 an.

void readSerial()
{
  const int breakTimeRead = 500; // Abbruchzeit in ms
  char readChar;                 // Einzelnes Zeichen
  byte x = 0;                    // Position im Array
  char buf[30] = "\0";           // Zwischenspeicher

  unsigned long lastmillis = millis(); // Startzeit merken...
  while (Serial.available() > 0 && millis() - lastmillis < breakTimeRead)
  {
    readChar = Serial.read();
    if (readChar == ';')
    {
      ausgabe = true;
      Serial.print("Teile "); Serial.println(buf);
      teileBuf(buf);
      x = 0;
    }
    else
    {
      buf[x] = readChar;
      x++;
    }
  }
}

Das ist schick. Vorgesehen ist, das solange gelesen wird, bis ein ; kommt und dann ausgewertet.
Zu dem Zeitpunkt, als dieser Code entstand war ich einem Aufbau noch nicht habbar und hab das trocken gemacht - also sowohl senden als auch empfangen auf dem Serial-Port getestet und zugleich habe ich den Inhalt bei der Übergabe auf einen Datensatz beschränkt und alle nacheinander “händisch” übergeben.

Das funktioniert auch.

Was jetzt aber dazu kommt, sind zwei Faktoren:
a) Die Gesamtzahl der zu empfangenen Daten “am Stück”
b) Während der Übertragung ein Serial.available < 1 - sprich, wenn schneller ausgelesen, als Daten reinkommen.

Fange ich mit b) an:
Im Gegensatz zu agmue habe ich mich auf die lokale Verarbeitung konzentriert und meinen Puffer auch nur lokal deklariert.

char buf[30] = "\0";           // Zwischenspeicher

In dem Moment, wo die Leseroutine schneller ist als die einkommenden Daten, wird die Funktion verlassen.
Mit dem Verlassen der Funktion verlieren die Variablen aber auch ihren Inhalt.
Das bedeutet, das buf schon einen Teil aufgenommen hat und dieser Teil gelöscht wird.
Beim nächsten Umlauf wird neu gefüllt, aber der erste Teil ist verloren.
Das heisst, das die Daten niemals zur Auswertung kommen.
Das ist Dein

17:15:02.839 → RZ3:0,0 hier müsste jetzt 5,5 stehen

in #76

Das vermeide ich, in dem ich jetzt sage, das der Puffer zwar noch immer lokal läuft, aber der Inhalt beim verlassen der Funktion erhalten bleibt:

static char buf[30] = {0};           // Zwischenspeicher

Gleichzeitig mit dem static für den Puffer muss natürlich auch die Position gemerkt werden:

static byte x = 0;                   // Position im Array

Soweit - so gut.
Was jetzt passiert:
Es wird gelesen - ggfls. auch mit Unterbrechung - bis der Satz komplett da ist.
Davor und danach passiert was, was ich bei der Übergabe im SerMon nicht habe:
Es werden Steuerzeichen mit eingelesen.

Das heisst, wenn das letzte Feld (F4) inhaltlich übergeben wurde, folgen Steuerzeichen.
Wird die Übertragung vorher angestossen OHNE Inhalt, kommen nur Steuerzeichen.
Diese Steuerzeichen bewirken, das Serial.available() > 0 erfüllt ist.
Und weil die Zeichen auch gelesen werden können readChar = Serial.read();        // Einlesen werden die auch in den Puffer übernommen:

buf[ x ] = readChar;             // Dann aufnehmen

Und genau hier(!) findet sich wieder, was Du auch in #76 beschrieben hast.

17:15:02.792 → BRZ: 0,0 zeigt keine Werte an.

Das habe ich bei der Übergabe mit dem Seriellen Monitor nicht.

Da kommen also VOR dem eigentlichen Set, sowie danach Steuerzeichen, die nicht aufgenommen werden dürfen. Denn sonst geht das:

 if (!strncmp(c, "BRZ", 3)) {

definitiv in die Hose.

Der Puffer fängt mit Steuerzeichen an - nicht mit ‘BRZ’ - damit ist ein Vergleich IMMER falsch.

Das lässt sich lösen, indem keine Steuerzeichen in den Puffer genommen werden:

if (!isControl(readChar))

es geht alles an Zeichen und Zahlen, solange sie keine Steuerzeichen sind.

Jetzt könnte man fragen, warum nicht isPrintable - also alles was druckbar ist.

???

Versuch es selbst.
Es behindert oder verändert die Lesefunktionalität nicht.
Nur der Inhalt des Puffers wird anders gehandhabt…

Hier meine Funktion aus #86, deren Inhalt Du jetzt von !isControl nach isPrintable ändern sollst (edit: extra nochmal markiert)

void readSerial()
{
  const int breakTimeRead = 500;       // Abbruchzeit in ms
  char readChar;                       // Einzelnes Zeichen
  static byte x = 0;                   // Position im Array
  static char buf[30] = {0};           // Zwischenspeicher

  unsigned long lastmillis = millis(); // Startzeit merken...
  while (Serial1.available() > 0 && millis() - lastmillis < breakTimeRead)
  {
    readChar = Serial1.read();         // Einlesen
    Serial.print(readChar);
    if (readChar == ';')               // Feldende
    {
      buf[x] = '\0';                   // CharArray abschliessen
      teileBuf(buf);                   // Übergeben zum teilen
      x = 0;                           // Position im Array rücksetzen
    }
    else
    { if (!isControl(readChar))        // Zeichen ist kein Steuierzeichen
      {
        buf[x] = readChar;             // Dann aufnehmen
        x++;                           // neue Position setzen
      }
    }
  }
}

Schreibe, was Du erkannt hast.

Beste Grüße!

Schöne Erkenntnisse!

Mir fehlt noch eine Überprüfung, die Feldgrenze von buf nicht zu Überschreiten. Außerdem kann man früher das Ende-Steuerzeichen setzen.

void readSerial()
{
  const int breakTimeRead = 500;       // Abbruchzeit in ms
  char readChar;                       // Einzelnes Zeichen
  static byte x = 0;                   // Position im Array
  static char buf[30] = {0};           // Zwischenspeicher

  unsigned long lastmillis = millis(); // Startzeit merken...
  while (Serial1.available() > 0 && millis() - lastmillis < breakTimeRead)
  {
    readChar = Serial1.read();         // Einlesen
    Serial.print(readChar);
    if (readChar == ';')               // Feldende
    {
      teileBuf(buf);                   // Übergeben zum teilen
      x = 0;                           // Position im Array rücksetzen
    }
    else
    { if (!isControl(readChar))        // Zeichen ist kein Steuierzeichen
      {
        buf[x] = readChar;             // Dann aufnehmen
        if (x < 29) x++;               // ◄ neue Position setzen
        buf[x] = '\0';                 // ◄ CharArray abschliessen
      }
    }
  }
}

agmue:
Schöne Erkenntnisse!

Ja. Das ist so das Ding mit T und P.

Mir fehlt noch eine Überprüfung, die Feldgrenze von buf nicht zu Überschreiten. Außerdem kann man früher das Ende-Steuerzeichen setzen.

ach… machbar ist da noch einiges… :wink:
Ich hab mich auf das konzentriert, was ich als Ausgangslage habe.

F1:Vorname Nachname; Mögliche Werte: Bis zu 25 Buchstaben

Das ist bisher der größte Wert.

Theoretisch brauche ich das Ende-Steuerzeichen gar nicht setzen.
Es ist nur drin geblieben…

PS: Ich kann mehr Runden fahren als Du :wink:

my_xy_projekt:
Theoretisch brauche ich das Ende-Steuerzeichen gar nicht setzen.
Es ist nur drin geblieben.....

Da buf static ist, wird der Inhalt immer wieder überschrieben. Für teileBuf(buf); muß klar sein, wo die aktuellen Zeichen aufhören und der alte Müll anfängt. Das Ende-Steuerzeichen wird daher benötigt. Alternativ müßtest Du die Länge von buf mit übergeben.

my_xy_projekt:
PS: Ich kann mehr Runden fahren als Du :wink:

Klar doch, ich bin ja kein Rennfahrer :grin:

agmue:
Da buf static ist, wird der Inhalt immer wieder überschrieben. Für teileBuf(buf); muß klar sein, wo die aktuellen Zeichen aufhören und der alte Müll anfängt. Das Ende-Steuerzeichen wird daher benötigt. Alternativ müßtest Du die Länge von buf mit übergeben.

Die Lösung liegt in teileBuf in der letzten Zeile.
:slight_smile: :slight_smile: :slight_smile:

Nachtrag: Ja der ist wirklich fies und sollte eigentlich durch und mit einem globalen const ergänzt sein.
In meiner Gesamt-Version ist das auch schon vorgesehen...

my_xy_projekt:
Die Lösung liegt in teileBuf in der letzten Zeile.

Stimmt, habe ich übersehen :-[

my_xy_projekt:
In meiner Gesamt-Version ist das auch schon vorgesehen...

PC → Sender mit NRF24 → Empfänger mit NRF24 → Anzeige

Dann sollte in der Gesamt-Version wegen der Längenbeschränkung bei NRF24 die Aufteilung in Daten-Häppchen schon im Sender erfolgen. Wir wollen ja nicht, daß jemand über Kabel stolpert ;D

agmue:
Dann sollte in der Gesamt-Version wegen der Längenbeschränkung bei NRF24 die Aufteilung in Daten-Häppchen schon im Sender erfolgen.

Das hatte ich gemeint, als ich an anderer Stelle schrub, den buffer zu versenden.
Ich habe 32bytes Platz.
Der Name wäre mit 25Char das grösste Feld. Bleiben mindest 6Byte für die Signalisierung um was für einen Inhalt es sich handelt.
Selbst wenn ich "F1:"noch voranstelle, bleiben mindest 3Bytes für den Begin der Sendung.

Und wenn wirklich nicht anders, wird der Fahrername am SPACE aufgeteilt...

Hast Du NRF24 zum Probieren?

Wenn ich mir die ganze Stückelung so anschaue, wäre da nicht UDP Multicast wesentlich einfacher?

Gruß Tommy

agmue:
Hast Du NRF24 zum Probieren?

Nicht mehr.
Ich hab nur noch 2x 905er in meiner Variowand. Und das wird die Tage nichts. Da fehlt mehr als nur die Baufläche.
Ich hab nicht grundlos nach "aktuelle Lieferzeiten vom fC?" gefragt :wink: - Ich könnte jetzt endlich wieder am heimischen was tun.. Nu mach ich Erdarbeiten :wink:

Tommy56:
Wenn ich mir die ganze Stückelung so anschaue, wäre da nicht UDP Multicast wesentlich einfacher?

Nimm das UDP weg, es fehlt an IP, dann ist es genau das was ich vor hätte. :wink:

Ich bin Willens mit den Vorgaben zu arbeiten und nichts neues anzufangen.

my_xy_projekt:
Nimm das UDP weg, es fehlt an IP, dann ist es genau das was ich vor hätte. :wink:

Ein ESP8266 kann ein eigenes Netz aufspannen. Aber wenn es mit den angegebenen Mitteln weiter gehen soll, nicht mein Problem.
Ich verstehe aber immer noch nicht, warum solche statischen Infos, wie Fahrernamen nicht nur dann übertragen werden, wenn sich da etwas ändert und sonst nur die Rundenzeiten.

Gruß Tommy