Serielle einlesen + strcmp

Hallo, ich brauche mal Hilfe von Euch...

Folgendes:

Ich möchte von der Seriellen eine gewisse Anzahl von Zeichen einlesen, dann mit strcmp auf
tx.txt=, ty.txt= und tz.txt= vergleichen.
Wenn einer dieser 3 Sätze erkannt wurde, brauche ich die Zeichen die nach diesen Sätzen kommen, bis 3xFF kommen.
Dafür müsste ich die Position (Pointer) haben an welcher Stelle der Satz gefunden wurde.
Hier jedoch habe ich keine Ahnung, wie man das macht.

Mein Listing sieht so aus:

char x[] = "......................"; <-- für das LCD

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

void loop ( void )
{

  char inSerial[128];
  int i = 0;

  if (Serial.available()> 0)
  {
    while ((Serial.available() > 0) & (i < 127))
    {
      inSerial[i] = Serial.read(); 
      i++;
    }
    inSerial[i] = '\0';
    Check_Protocol(inSerial);
  }
}

void Check_Protocol(char inStr[])
{

  if (!strcmp(inStr, "tx.txt=")== 0)
  {

  // hier müssen die nächsten Zeichen aufs LCD geschrieben werden bis 3x$FF kommen

  }
  
  if (!strcmp(inStr, "ty.txt=")== 0)
  {

  // hier müssen die nächsten Zeichen aufs LCD geschrieben werden bis 3x$FF kommen

  }
  if (!strcmp(inStr, "tz.txt=")== 0)
  {

  // hier müssen die nächsten Zeichen aufs LCD geschrieben werden bis 3x$FF kommen

  }

}

was der Sender schickt sieht so aus:

tx.txt="57,998"ˇˇˇ 

ty.txt="27,198"ˇˇˇ

tz.txt="11,611"ˇˇˇ

die "57,998 27,198 11,611" sind die Daten die ich in einen String fürs LCD erhalten möchte.
diese Zeichen ˇˇˇ sind 3x$FF und sind als Datensatz-Ende-Markierungen gedacht, leider keine LF/CR Zeichen da.

Wie bekomme ich die "Positionen" im String von den Werten und den 3x$FF's?

Gruß,
Wolfram.

Bei fester Position kannst Du inSerial+länge nehmen (Pointer-Arithmetik), oder mit strchr() nach = oder " suchen, und dann noch 1 oder 2 draufaddieren.

Das sieht mir ziemlich nach Nextion aus, oder wer benutzt die drei 0xFF's noch?

void loop ( void ) {
  char inSerial[128];
  int i = 0;

  if (Serial.available()> 0)

Den Buffer lokal zu loop zu machen ist ein fataler Fehler.
Du hast nur das Glück, dass der immer an der gleichen Stelle liegt.
Ausserdem wird - weil auch i lokal zu loop ist - immer nur das erste Zeichen beschrieben.

Beide müssen static werden, oder global.

ja, das sind Daten für eigentlich ein Nextion, richtig.

Das nur das erste Zeichen beschrieben wird, stimmt so nicht, denn ich bekomme in inStr ja die vollen 128Bytes und strcmp findet auch den Text tx.txt= !
Aber ich habe inSerial[128] nun als global umgändert.
Danke für den Tip!

i wird ja in der while-schleife hochgezählt:

    while ((Serial.available() > 0) & (i < 127))
    {
      inSerial[i] = Serial.read(); //read data
      i++;
    }

Aber wie bekomme ich die Position im String?
Ich brauche die Position von dem tx.txt= und die von den 3 FF's

strtok()

Eher strstr(_P) finde ich.

Auch wird wie fast immer nicht beachtet wie langsam Serial selbst mit so hohen Baudraten ist. Du kannst nicht innerhalb einer while-Schleife alle Daten einlesen wenn sie gerade gesendet werden. Da kommt ein Zeichen an und die Schleife ist zu Ende.

Die Endzeichen darfst du schon gar nicht abspeichern. Du musst solange einlesen bis das Endzeichen dreimal da war. Dann den String terminieren und verarbeiten.

Ich habe mal das Endzeichen einstellbar gemacht. Dadurch kann man das auch einfach mit dem seriellen Monitor testen. Hier ist es dreimal 'Q'

Für den Vergleich des Anfangs-Strings nimmt man strncmp(). Nicht strcmp()! Letzteres vergleicht den kompletten String. Das ist falsch. strncmp() vergleicht die ersten N Zeichen. Dann einfach Zeiger-Arithmetik, da die Länge des Kommando-Strings ja bekannt ist. Man vergleicht die ersten 7 Zeichen. Dann kommt man mit einer Addition +7 auf das Zeichen danach

const int SERIAL_BUFFER_SIZE = 30;
char serialBuffer[SERIAL_BUFFER_SIZE];

const unsigned char END_CHAR = 'Q';    //im richtigen Program 0xFF !!

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

void loop()
{
  if (readSerial(Serial) == true)
    parseSerial();
}

bool readSerial(Stream& stream)
{
  static byte index;
  static byte endLine;

  while (stream.available())
  {
    unsigned char c = stream.read();

    if (c == END_CHAR)
    {
      endLine++;
    }
    else if (c >= 32 && index < SERIAL_BUFFER_SIZE - 1)
    {
      serialBuffer[index++] = c;
    }

    if (endLine == 3)
    {
      serialBuffer[index] = '\0';
      index = 0;
      endLine = 0;
      return true;
    }
  }
  return false;
}

void parseSerial()
{
  if (strncmp_P(serialBuffer, PSTR("tx.txt="), 7) == 0)
  {
    Serial.print("tx: "); Serial.println(serialBuffer + 7);
  }
}

Beachte den Unterschied zu deinem Code. Ich habe zwar eine while-Schleife, aber die Funktion wird solange aufgerufen bis alles da ist. Wenn nichts da ist kehrt sie sofort nach loop() zurück.

Lass erst mal das Display weg und teste das so mit dem Serial Monitor :slight_smile: Da kannst du halt nicht 0xFF eingeben, aber man kann auch mal kurz ein druckbares Zeichen missbrauchen.

Wenn die Daten noch einzelne 0xFF enthalten, funktioniert das nicht so richtig.

Du müsstest endLine wieder zurücksetzen, wenn du ein anderes Zeichen vor dem dritten 0xFF siehst.

Whandall:
Wenn die Daten noch einzelne 0xFF enthalten, funktioniert das nicht so richtig.

Ich dachte alle anderen Daten sind Standard ASCII Zeichen. Da kommt 0xFF nicht drin vor.

nein, die "Ende-Kennung" sind dreimal FF!

mega-hz:
nein, die "Ende-Kennung" sind dreimal FF!

Das war Test-Code!

Ich habe es doch deutlich gemacht, dass man das einstellen kann:

const unsigned char END_CHAR = 'Q';

Wird zu:

const unsigned char END_CHAR = 0xFF;

Ich habe nur erstens mal kein Nextion Display. Also habe ich allgemeinen Code geschrieben. Zweitens ist es auch für dich erst mal praktisch dass so zu testen. Einfach einen UNO nehmen und den seriellen Monitor öffnen. Fertig. Oder du nimmst ein Terminal Program wie HTerm. Da kannst du auch Binär-Daten senden und nicht nur ASCII.

Ich verstehe sowieso nicht, wieso du das, was du aus der Nextion Message herauspulst, ans LCD schicken willst.

Ja, daß das "Q" z.Z. das Ende Zeichen ist, ist klar, aber es müsste auf 3x Q abgefragt werden!

Ich habe das eben probiert mit dem seriellen Monitor, es wird der Text tx.txt= nicht erkannt!

@Whandall:

Ich habe kein Nextion Display, aber ein Programm, welches Daten für so eins aussendet!
Ich möchte diese Daten auf einem kleinen TFT ausgeben!

(Hätte ich ein Nextion, würde das sicher alles keinen Sinn machen! :slight_smile: )

Ja, daß das "Q" z.Z. das Ende Zeichen ist, ist klar, aber es müsste auf 3x Q abgefragt werden!

Wird es ja

    if (c == END_CHAR)
    {
      endLine++;
    }

...

    if (endLine == 3)
    {
    }

Ist zugegeben sehr primitiv. Es wird nicht abgefragt ob die Zeichen wirklich dreimal direkt hintereinander kommen. Aber wenn das Endzeichen sonst im Datenstrom nicht auftaucht ist das denke ich ok. Man könnte natürlich noch abfragen ob endLine > 0 ist UND ein anderes Zeichen da ist und dann entsprechend darauf reagieren. Ich glaube aber nicht dass das unbedingt nötig ist.

Ich habe es gerade sowohl mit dem seriellen Monitor und mit HTerm mit 0xFF getestet. Es geht. Was ich aber oft habe ist dass die erste Übertragung nicht erkannt wird und danach geht es immer.

ahh, mist, war noch eine Zeile aus dem alten code mit drin, ja, das funktioniert!

Weil ich auch bedenken wegen der Geschwindigkeit des UNOs mit 115200 Baud hatte,
habe ich dies sowieso auf nem ESP8266 drauf, der kann ja mit seinen 160Mhz schon etwas mehr.
Ich probier das nun mal mit dem TFT und FF's...

mega-hz:
Ich habe kein Nextion Display, aber ein Programm, welches Daten für so eins aussendet!
Ich möchte diese Daten auf einem kleinen TFT ausgeben!

(Hätte ich ein Nextion, würde das sicher alles keinen Sinn machen! :slight_smile: )

Das erklärt es. :slight_smile:

Ich würde ein Nextion nicht auf einem Arduino simulieren wollen.

mega-hz:
Weil ich auch bedenken wegen der Geschwindigkeit des UNOs mit 115200 Baud hatte,

Das ist kein Problem. Auch 250.000 und 500.000 Baud gehen noch

Ich würde ein Nextion nicht auf einem Arduino simulieren wollen.

das will ich auch nicht....
Es ist so, Albert programmiert ein schönes Frontend für den GRBL-CNC-Controller SerialComCNC und hat 2.Serielle für ein Nextion-Display implementiert.
Über diese werden o.g. Daten verschickt.
Aber es ist auch möglich, selber Daten zu verschicken die z.B. nach nem Druck auf nen Taster kommen sollen, wie z.B. #GCG91G1X1< um die X-Achse zu verfahren.

Da sowohl die aktuellen XYZ Daten rüberkommen als auch das man selber Befehle schicken kann,
ist es ne Prima Sache um ein mobiles Hand-Einricht-Werkzeug zu realisieren!

Ich benutze ein kleine ILxxx TFT, das blöde ist, ich weiss nicht wie man eine Zeile so neu "printen" kann, ohne das der vorige Inhalt da stehen bleibt!
Immer ein tft.fillScreen(ILI9341_BLACK); ausführen flackert ganz schön....

@Serenifly:

Du hast mir sehr viel geholfen! Vielen Dank erstmal dafür!!!
Meinst Du 250.000 oder 500.000 Baud auf dem ESP oder Arduino?

mega-hz:
Ich benutze ein kleine ILxxx TFT, das blöde ist, ich weiss nicht wie man eine Zeile so neu "printen" kann, ohne das der vorige Inhalt da stehen bleibt!

Setze eine konstante Breite fest und fülle die Differenz mit Leerzeichen auf. Vor allem für Zahlen gibt es da fertige Funktionen in C. Für Integer kann man es auch leicht selbst schreiben.

Meinst Du 250.000 oder 500.000 Baud auf dem ESP oder Arduino?

Auf dem Arduino