Serielle Datenstring vom Computer im Adruino Mega einlesen und aufteilen

Hallo und guten Abend liebe Adruino Gemeinde,

vorab die Info das ich absoluter Anfänger bin was die C-Sprache betrifft. Bei mir ist es ein ehr ein ausprobieren "was passiert wenn" ja so sind die 53 Jahre alten Männer :wink:

Nun bin ich aber an einen Projekt wo sich meine Unwissenheit rächt.... Daher hoffe ich das ihr mich ein wenig unterstützt.

Zum Projekt:
Es ist ein Computer der folgenden String an einem Stück im ASCII Code an die Serielle Schnittstelle raus gibt. Unter umständen kann das jede Sekunde sein und dabei schickt er den kompletten String.

BRZ:6,777;BRF:TEXT;BRS:4;AR1:0;RZ1:0,000;F1:TEXT;AR2:0;RZ2:0,000;F2:TEXT;AR3:0;RZ3:0,000;F3:TEXT;AR4:0;RZ4:0,000;F4:TEXT;

Diesen möchte ich nun am Mega Port2 einlesen an Port 3 weitergeben sowie teilen. Im Grunde benötige ich nur die Daten nach dem Doppelpunkt. Diese können Kommazahlen sowie Text enthalten.
Als Ahnungsloser habe ich mir erst mal ein gebastelt....

#include <stdio.h>
#include <string.h>
void setup()
{
Serial.begin(9600);
Serial2.begin(9600);

char* value; 
value="BRZ:6,777;BRF:TEXT;BRS:4;AR1:0;RZ1:0,000;F1:TEXT;AR2:0;RZ2:0,000;F2:TEXT;AR3:0;RZ3:0,000;F3:TEXT;AR4:0;RZ4:0,000;F4:TEXT;";

char* token = strtok(value, ":;");
char* Wert1 = token;
token= strtok(0, ":;");
char* Wert2 = token;
token = strtok(0, ":;");
char* Wert3 = token;
token = strtok(0, ":;");
char* Wert4 = token;
token = strtok(0, ":;");
char* Wert5 = token;
token = strtok(0, ":;");
char* Wert6 = token;
token= strtok(0, ":;");
char* Wert7 = token;
token = strtok(0, ":;");
char* Wert8 = token;
token = strtok(0, ":;");
char* Wert9 = token;
token = strtok(0, ":;");
char* Wert10 = token;
token = strtok(0, ":;");
char* Wert11= token;
token = strtok(0, ":;");
char* Wert12 = token;
token = strtok(0, ":;");
char* Wert13 = token;
token = strtok(0, ":;");
char* Wert14= token;
token = strtok(0, ":;");
char* Wert15= token;

Serial.print("Bezeichnung-1 ");
Serial.println(Wert1);
Serial.print("Bezeichnung-2 ");
Serial.println(Wert2);
Serial.print("Bezeichnung-3 ");
Serial.println(Wert3);
Serial.print("Bezeichnung-4 ");
Serial.println(Wert4);
Serial.print("Bezeichnung-5 ");
Serial.println(Wert5);
Serial.print("Bezeichnung-6 ");
Serial.println(Wert6);
Serial.print("Bezeichnung-7 ");
Serial.println(Wert7);
Serial.print("Bezeichnung-8 ");
Serial.println(Wert8);
Serial.print("Bezeichnung-9 ");
Serial.println(Wert9);
Serial.print("Bezeichnung-10 ");
Serial.println(Wert10);
Serial.print("Bezeichnung-11");
Serial.println(Wert11);
Serial.print("Bezeichnung-12");
Serial.println(Wert12);
Serial.print("Bezeichnung-13 ");
Serial.println(Wert13);
Serial.print("Bezeichnung-14");
Serial.println(Wert14);
Serial.print("Bezeichnung-15");
Serial.println(Wert15);
}


void loop()
{


}

Nun meine Frage an euch, wie bekomme ich es hin das die Daten der Serielle2
im Beispiel oben "value" ersetzt.

Bin für jeden Tipp dankbar.
Thorsten der Ahnungslose :wink:

Setze Deinen Code bitte in Codetags (</>-Button oben links im Forumseditor oder [code] davor und [/code] dahinter ohne *).
Dann ist er auch auf mobilen Geräten besser lesbar.
Das kannst Du auch noch nachträglich ändern.

Ist Deine Zeichenkette mit einem Zeilenvorschub abgeschlossen? Das würde die Auswertung vereinfachen.
Dann könntest Du die Standard-Routine zum Einlesen nutzen und strtok/strtok_r zum Trennen.

Infos dazu gibt es hier.

Gruß Tommy

Hallo Tommy,

vielen Dank für dein Tipp mit den Code, hab mich schon gefragt wie das geht.
Zu der Zeichenkette, nein leider schließt sie nicht ab.
Bekomme dann Werte wie -1 in Dauerschleife rein bis der Computer neue Daten sendet.

Gruß Thorsten

In diesem Thema wurde etwas Vergleichbares gemacht.

Woher willst Du dann sicher wissen, wann Ende ist?
Kannst Du die Sendeseite anpassen?

Ansonsten bleibt Dir nur immer bis zum ; einzulesen, das zu zerlegen/auszuwerten und dann wieder den nächsten Teil bis zum ; einlesen.
Also anstelle von '\n' das ';' als Endezeichen zu betrachten.

Gruß Tommy

@agmue
Stimmt es kommt dem sehr nahe was ich suche bzw. brauche. Werde ich morgen mal en bissel mit rumspielen.Danke für den Hinweis.

@Tommy
Leider kann ich die Sendeseite nicht anpassen, wäre da nicht möglich auch das -1 als ende zu deklarieren?
Und wie fange ich es an den zweiten Datensatzt nach ; einzulesen?

Okay, es überfordert mich nun gerade ein wenig. Muss ins Bett :slight_smile: ud morgen in Ruhe mal lesen und probieren.

Jungs, habt Dank und ich komme wieder.

(deleted)

Hallo Peter,
danke für deine Mithilfe. Kann jeden Strohhalm gebrauchen. Ich habe z. Z. Nur ein XP Rechner mit HyperTernimal oder auch SerialPortMonitor zur Verfügung. Morgen kommt mein USB Adapter da kann ich gerne auch mit CoolTerm nochmal ein Bild machen.

Peter, ich Zähl auf dich. :slight_smile:
Danke

(deleted)

Hallo Peter,

ist das nach deinen Vorstellungen?

Danke, Gruß Thorsten

Computer.jpg

Ausgehend von den Daten in #0, die keine Endekennung beinhalten, kann man entsprechend #4 verfahren.

In einem ausbaufähigen Programm habe ich stellvertretend die ersten drei Werte ausgewertet:

// BRZ:6,777;BRF:TEXT;BRS:4;AR1:0;RZ1:0,000;F1:TEXT;AR2:0;RZ2:0,000;F2:TEXT;AR3:0;RZ3:0,000;F3:TEXT;AR4:0;RZ4:0,000;F4:TEXT;

const byte numChars = 15;
char buf[numChars];

float brz;
const byte brf_l = 5;
char brf[brf_l];
byte brs;

void setup() {
  Serial.begin(115200);
  Serial.println("\nStart");
  Serial1.begin(9600);
}

void loop() {
  static uint16_t ndx = 0;
  char rc;

  while (Serial1.available() > 0) {
    rc = Serial1.read();
    //Serial.print(ndx); Serial.print('\t'); Serial.print(rc, HEX); Serial.print('\t'); Serial.println(rc);
    if (rc == ';') {
      buf[ndx] = '\0';
      ndx = 0;
      auswertung();
    } else {
      buf[ndx] = rc;
      ndx = (1 + ndx) % numChars;
    }
  }
}

void auswertung() {
  char * bez = strtok(buf, ":");
  char * inh = strtok(NULL, ":");
  Serial.print(bez); Serial.print('\t'); Serial.println(inh);

  if(!strncmp(bez, "BRZ", numChars)){
    replace (inh, ',', '.');
    brz = atof(inh);
    Serial.print("\t\t"); Serial.print(bez); Serial.print('\t'); Serial.println(brz, 3);
  }

  if(!strncmp(bez, "BRF", numChars)){
    strncpy ( brf, inh, brf_l );
    Serial.print("\t\t"); Serial.print(bez); Serial.print('\t'); Serial.println(brf);
  }

  if(!strncmp(bez, "BRS", numChars)){
    brs = atoi(inh);
    Serial.print("\t\t"); Serial.print(bez); Serial.print('\t'); Serial.println(brs);
  }
}

void replace( char * str, const char old, const char _new )
{
  while(*str)
  {
    if( *str == old ) *str = _new;
    str++;
  }
}

Die Funktion replace habe ich mir aus dem WWW kopiert, weil std::replace nicht gefunden wird.

(deleted)

Hallo ihr netten Menschen,
vielen tausend Dank für eure Hilfe.Ich weiß es wirklich zu schätzen das Ihr mich so unterstützt.
Besonderen Dank an agmue und Peter.

So, nach den vielen Input´s von euch musste ich es erst mal verarbeiten und versuchen zu verstehen. Ehrlich... es fällt mir schwer, aber...Aufgeben ist keine Option :slight_smile:
Ich arbeite dran, versprochen.

Das ausbaufähige Programm funktioniert bis an einer Stelle perfekt.(s. BFR Wert Rot eingekreist, warum schreibt er hier was anderes als im Buffer steht?) und wenn ich noch eine Frage stellen darf,
kann ich die Werte aus z.B. aus AR1 bis AR4 in einem int übernehmen um mit den Werten zu rechnen?

@Peter 0000-0090....pdf hier nochmal die Daten aus CoolTerm.

Danke und Gruß Thorsten

0000-0090Computer-Serial-Output.pdf (17.7 KB)

Benziner:
... warum schreibt er hier was anderes als im Buffer steht?

Weil der Buffer zu klein ist, besser const byte brf_l = 9;. "Fahrer-123" benötigte dann noch mehr Feldelemente, immer einen mehr als Zeichen.

Zur Laufzeit wird die Feldlänge nicht überprüft, das muß man selbst programmieren oder die Feldlängen großzügiger wählen.

Benziner:
... kann ich die Werte aus z.B. aus AR1 bis AR4 in einem int übernehmen um mit den Werten zu rechnen?

Ja, so wie bei BRS.

(deleted)

Ich habe diese Daten aus der PDF-Datei herausgepuhlt:

const char msg[] = {"BRZ:4,032;BRF:Fahrer-1;BRS:1;AR1:8;RZ1:545,871;F1:Fahrer-1;AR2:5;RZ2:49,840;F2:Fahrer-2;AR3:9;RZ3:102,096;F3:Fahrer-3;AR4:2;RZ4:105,265;F4:Fahrer-4;"};

Hallo agmue, Hallo Peter,

ich habe mich heute intensiv mit mit dem Projekt beschäftigt.... und habe es an einigen Stellen erweitert und teiweise ans Display ausgegeben. Viel geschwitzt und dazu gelernt :slight_smile: aber ohne eure Hilfe hätte ich es nie im Leben geschafft. Ich kann mich immer wieder nur bei euch bedanken.

Jedoch habe ich noch zwei Probleme was ich nicht lösen konnte. Wenn ich als Fahrernamen z.B.
"Thorsten Hesse" am sendenen Computer eingebe, wird nichts mehr angezeigt.
Kann char BRF keine Leerzeichen darstellen?

Oder mache ich etwas falsch an den tft Print befehlen? Okay mit den TFT´S muss ich mich eh auch noch intensiver beschäfftigen. Problem 2, wie bekomme ich den eingelesenden String über Serial3 an einen weiteren MEGA gesendet?

Hier mal mein Tageswerk... :slight_smile: plus Bild vom Display

Gruß Thorsten

#include <Adafruit_GFX.h>    // Core graphics library
#include <MCUFRIEND_kbv.h>   // Hardware-specific library
MCUFRIEND_kbv tft;
#include <Fonts/FreeSans9pt7b.h>
#include <Fonts/FreeSans12pt7b.h>
#include <Fonts/FreeSerif12pt7b.h>
#include <FreeDefaultFonts.h>
#define BLACK   0x0000
#define RED     0xF800
#define GREEN   0x07E0
#define WHITE   0xFFFF
#define GREY    0x8410

// BRZ:6,777;BRF:TEXT;BRS:4;AR1:0;RZ1:0,000;F1:TEXT;AR2:0;RZ2:0,000;F2:TEXT;AR3:0;RZ3:0,000;F3:TEXT;AR4:0;RZ4:0,000;F4:TEXT;

// BRZ=Beste Rundenzeit               (Werte;0,000 bis 6,777)
// BRF=Beste Runde von Fahrer     (Werte;Fahrername)
// BRS=Beste Runde von Spur        (Werte;1 bis 4)

// AR1=Anzahl Runden Spur1            (Werte;0 bis 1000)
// RZ1=Beste Rundenzeit von Spur1 (Werte;0,000 bis 9999,999)
// F1 =Fahrername Spur1                   (Werte;Text z.B. Thorsten H.)

// AR2=Anzahl Runden Spur2            (Werte;0 bis 1000)
// RZ2=Beste Rundenzeit von Spur2 (Werte;0,000 bis 9999,999)
// F2 =Fahrername Spur2                   (Werte;Text z.B. Thorsten V.)

// AR3=Anzahl Runden Spur3            (Werte;0 bis 1000)
// R42=Beste Rundenzeit von Spur3 (Werte;0,000 bis 9999,999)
// F3 =Fahrername  Spur3                  (Werte;Text z.B. Thorsten Z.)

// AR4=Anzahl Runden Spur4            (Werte;0 bis 1000)
// RZ4=Beste Rundenzeit von Spur4 (Werte;0,000 bis 9999,999)
// F4 =Fahrername  Spur4                  (Werte;Text z.B. Thorsten O.)


const GFXfont *f;
const byte numChars = 15;
char buf[numChars];

float brz;
float rz1;
const byte brf_l = 16;
char brf[brf_l];
const byte f1_l = 16;
char f1[f1_l];

byte brs;
byte ar1;

void setup(void) 

{  
    Serial.begin(9600);
    Serial1.begin(9600);
    uint16_t ID = tft.readID();
    if (ID == 0xD3) ID = 0x9481;
    tft.begin(ID);
    tft.setRotation(1);
    tft.fillScreen(BLACK);
    tft.setCursor(110,300);
    tft.setTextColor(GREEN,BLACK);
    tft.setTextSize(2);
    tft.println ("Spurauswertung Spur-1");
    
}


void loop(void) 
{
  static uint16_t ndx = 0;
  char rc;
         
    while (Serial1.available() > 0) {
    rc = Serial1.read();
    if (rc == ';') {
      buf[ndx] = '\0';
      ndx = 0;
      auswertung();
    } else {
      buf[ndx] = rc;
      ndx = (1 + ndx) % numChars;
      
    }
  }
}

void auswertung() {
  char * bez = strtok(buf, ":");
  char * inh = strtok(NULL, ":");
    
// *** Auswertung  Beste Rundenzeit ***

  if(!strncmp(bez, "BRZ", numChars)){
    replace (inh, ',', '.');
    brz = atof(inh);
    tft.setTextColor(GREEN, BLACK);
    tft.setFont(f);
    tft.setTextSize(2);
    tft.setCursor(0, 10);
    tft.println(brz, 3);
}

// *** Auswertung Beste Runde von Fahrer x  ***

  if(!strncmp(bez, "BRF", numChars)){
    strncpy ( brf, inh, brf_l );
    tft.setTextColor(GREEN, BLACK);
    tft.setFont(f);
    tft.setTextSize(2);
    tft.setCursor(0, 40);
    tft.println("            "); 
    tft.setCursor(0, 40);
    tft.println(brf);// Fahrername darf kein leerzeichen enthalten, sonst wird nichts angezeigt
}

// *** Auswertung Beste Runde von Spur-X ***

  if(!strncmp(bez, "BRS", numChars)){
    brs = atoi(inh);
    tft.setTextColor(GREEN, BLACK);
    tft.setFont(f);
    tft.setTextSize(2);
    tft.setCursor(0, 80);
    tft.print("Schnellste Runde auf Spur:");
    tft.setCursor(310, 80);
    tft.println(brs);
}

// *** Auswertung Anzahl Runden Spur 1 ***

  if(!strncmp(bez, "AR1", numChars)){
    ar1 = atoi(inh);
    //tft.println(0, 120, 2, &FreeSevenSegNumFont,ar1);// Anzeige in der Schriftart funktioniert leider nicht, zeigt nichts an.
    // vermutlich den wert am komma bzw. punkt aufteilen und einzeln darstellen.
    tft.setTextColor(GREEN, BLACK);
    tft.setFont(f);
    tft.setTextSize(2);
    tft.setCursor(0, 120);
    tft.print("Anzahl Runden:");
    tft.setCursor(310, 120);
    tft.println("        "); 
    tft.setCursor(310, 120);
    tft.println(ar1);
}

// *** Auswertung Beste Rundenzeit von Spur 1 ***

  if(!strncmp(bez, "RZ1", numChars)){
    replace (inh, ',', '.');
    rz1 = atof(inh);
    tft.setTextColor(RED, BLACK);
    tft.setFont(f);
    tft.setTextSize(8);
    tft.setCursor(90, 190);
    tft.println("        "); 
    tft.setCursor(90, 190);   
    tft.println(rz1, 3),("sek.");// Anzeige sek. direkt dahinter funktioniert leider nicht, zeigt nichts an.
}

// *** Auswertung Fahrer von Spur 1 ***

  if(!strncmp(bez, "F1", numChars)){
    strncpy ( f1, inh, f1_l );
    tft.setTextColor(RED, BLACK);
    tft.setFont(f);
    tft.setTextSize(2);
    tft.setCursor(100, 10);
//    tft.println("        "); 
//    tft.setCursor(100, 10);   
    tft.println(f1);
}
}

void replace( char * str, const char old, const char _new )
{
  while(*str)
  {
    if( *str == old ) *str = _new;
    str++;
  }
}

void showmsgXY(int x, int y, int sz, const GFXfont *f, const char *msg)
{
    int16_t x1, y1;
    uint16_t wid, ht;
    //tft.drawFastHLine(0, y, tft.width(), WHITE);
    tft.setFont(f);
    tft.setCursor(x, y);
    tft.setTextColor(GREEN,BLACK);
    tft.setTextSize(sz);
    tft.print(msg);
   
}

CoolTerm Capture 2020-07-11 06-40-11.txt (568 Bytes)

(deleted)

Peter-CAD-HST:
hier kommt der Sequenzer

Ich erhalte die Meldung "warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]"

Benziner:
Wenn ich als Fahrernamen z.B. "Thorsten Hesse" am sendenen Computer eingebe, wird nichts mehr angezeigt.

Mit dem Leerzeichen hat das nichts zu tun, "Uwe Max" funktioniert, oder?

Bitte überprüfe die Länge der Felder, "Thorsten Hesse" ist länger als "Text". Wie lang ist der längste Name?

Hallo agmue,

ich habe es heute versucht, auch bei Uwe Max wird nichts mehr angezeigt.Leerzeichen sowie Sonderzeichen wie + - / etc. verhindern auch ein anzeigen.Bis max. Zeichenanzahl in Buchstaben läuft alles wunderbar.
Hatte heute mal versucht alle Daten auf einem Bildschirm anzeigen zu lassen.....

Was soll ich dir sagen, ab dem 5´ten Wert wird ignoriert? Ich muss jetzt leider ne Woche pause machen.
Darf ich dich wenn es weiter geht nochmal ansprechen?

Danke Gruß Thorsten