Serielle Daten einlesen und parsen

Hallo Zusammen,

für ein kleines Projekt möchte ich gerne nachfolgende Werte von der seriellen Schnittstelle einlesen und dann parsen und jeweils in einzelne Variablen zerlegen.

Ich habe mir viele Code-Schnippsel angeschaut… Allerdings sind die empfangenen Daten eben nicht durch ein Komma oder andere Zeichen getrennt.
Jede Zeile endet mit CR und beginnt mit E.
Nach dem Datum kommen jeweils die Zeile E1 bis E8. Dann geht es wieder von vorne los mit E und Uhrzeit.

Hat jemand eine Idee, wie ich das am Besten anstelle?
Danke!

E16:47    Sa, 17.09.
E1 (Rx ) +423  mV
...
E8 (pH )07.82  pH

VG,
Yosh76

Die Zeit/Datum Zeile brauchst du nicht direkt. Höchstens um zu wissen, wann das letzte Mal was empfangen wurde? Ansonsten ist - Das 2. Zeichen die Kanal-Nummer 1 .. 8 ? - Das 8. Zeichen ist immer ')' ? - Der Wert immer 5 Zeichen in den Spalten 9 .. 13 ? - Der Name am Anfang und die physikalische Einheit danach eigentlich egal ? (und muss nicht ausgewertet werden)

Meine Idee wäre, das dann auch so (primitiv) auszuwerten.

Falls du Zeit/Datum auswerten willst: Werden vormittags führende Nullen mitgeschickt? Ist die Zeit immer die Zeile nach E8.... ?

Hallo Michael, wow - das ging schnell :)

michael_x: Die Zeit/Datum Zeile brauchst du nicht direkt. Höchstens um zu wissen, wann das letzte Mal was empfangen wurde?

Die Zeit wäre schon wichtig/ Datum wäre schon wichtig. Wollte die Werte später in ein Textfile auf SD speichern.

Ansonsten ist - Das 2. Zeichen die Kanal-Nummer 1 .. 8 ?

Stimmt - 1-8 außer eben die Uhrzeit. Und genau daran hänge ich gedanklich - Es kommen dadurch auch die Kombinationen E1 und E2 (E10:00 bspw. oder E21:00) vor.

  • Das 8. Zeichen ist immer ')' ?

Jep - außer eben bei der Uhrzeit

  • Der Wert immer 5 Zeichen in den Spalten 9 .. 13 ?

Leider nein - es gibt auch Textwerte (Wasser, Luft etc.)

  • Der Name am Anfang und die physikalische Einheit danach eigentlich egal ? (und muss nicht ausgewertet werden)

Der Name am Anfang bezeichnet den Sensor - Name oder Nummer (E"x") benötige ich, dann kann ich die Einheit dazu bauen.

Falls du Zeit/Datum auswerten willst: Werden vormittags führende Nullen mitgeschickt? Ist die Zeit immer die Zeile nach E8.... ?

Eine führende Null wird mitgesendet und die Werte wiederholen sich immer wieder von vorne (E8 > EDatum...E8>EDatum usw.)

Vielen Dank für Deine Mühe! VG, Yosh76

Das sieht nach genau der gleichen Anwendung wie hier aus:

https://forum.arduino.cc/index.php?topic=329748.msg2337935#msg2337935

Die Ausgabe da ist für ein 4x20 LCD. Man kann mehrere Seiten einstellen die dann wechseln. Enthält einen Parser für die Sensor Daten und die Uhrzeit. Das alles wird dann in eine Art Bildpuffer geschrieben

EDIT: Link versaut :(

In Post #97 gibt es noch eine stark vereinfachte Version die die Daten direkt anzeigt wie sie kommen

Hi Sernifly,

Danke!!! Das ist genau die gleich Anwendung! Ich habe jetzt echt tagelang gesucht ;)

Schaue ich mir gleich mal an.

VG, Yosh76

Dass Zeilen per CR oder LF abgeschlossen werden ist übrigens der normale Anwendungsfall für die serielle Schnittstelle.

In dem Code muss man halt anpassen was die E-Nummern bedeuten. z.B.:

  else if (strncmp(str, "E2 ", 3) == 0)
  {
    parse_value(1, "Temp:", str, 4, "\xDF""C");
  }
  else if (strncmp(str, "E3 ", 3) == 0)
  {
    parse_value(5, "Leitwert:", str, 6, NULL);
  }

Hier ist E2 eine Temperatur und nach der Zahl wird "°C" angezeigt. E3 ist ein Leitwert ohne Einheit. Daher NULL als letzter Parameter (was die anderen Parameter bedeuten steht bei parse_value() dabei)

Das kann und wird bei dir natürlich anders sein

Dabei das Leerzeichen beim Vergleichsstring nicht vergessen! Es werden 3 Zeichen vergleichen. Alles andere wird ganz primitiv und ohne Plausibilitätsüberprüfung als Uhrzeit interpretiert.

Wie gesagt, der Code in #97 ist einfacher und hat nicht so viele Sachen die man per Hand einstellen muss

Wenn du doch selber knobeln willst: Mein Vorschlag wäre, nach der Zeile E8 immer die folgende Datumszeile zu lesen und dann die weiteren Zeilen "gleich": die Ziffer nach dem 'E' für eine switch-case Unterscheidung hernehmen. Text-Werte lesen bis zu einer max-Länge oder Zeilenende ist auch keine Zauberei.

Das Problem bei der Sache ist wirklich die absolut bescheuerte Formatierung der Uhrzeit. Fängt einfach mit 'E' an und dann kommt direkt eine Ziffer. Das heißt "E1" kann entweder eine Uhrzeit sein oder ein Sensor.

Man kann es aber einfach unterscheiden wenn man als erstes schaut ob ein Doppelpunkt drin vorkommt. So habe ich es in der anderen Version gemacht:

  if (strchr(str, ':'))  //Uhrzeit
  {
    parse_time(0, str);
    parse_time(4, str);
  }

Eine Zeile die einen Doppelpunkt hat wird da als Uhrzeit interpretiert und in Index 0 und 4 des Zeilenpuffers geschrieben. Das heißt sie steht immer in der ersten Zeile.

Alles andere kann man dann anders behandeln. switch/case ist eine gute Idee. Darauf hätte ich auch kommen können :(

Man muss aber davon ausgehen dass man mit einer beliebigen Zeile anfängt. Der Arduino kann ja irgendwo im Datenstrom einsteigen

Man muss aber davon ausgehen dass man mit einer beliebigen Zeile anfängt.

Stimmt, man wird auch irgendwo mitten in einer Zeile anfangen! Das, kombiniert mit der Tatsache, dass ein Zeilenanfang E1… und E2… nicht eindeutig ist, ist das “einzige” Problem. :wink:

Prüfen ob die Zeile ein ‘:’ enthält, oder ‘(’ und ‘)’ wäre eine Möglichkeit. Was aber alles bedeutet, dass man erst später in der Zeile rauskriegt, was die Zeichen vorher bedeutet haben. Wenn man eh erst die Zeile komplett in einen Zwischenpuffer liest, wie Serenifly immer wieder empfiehlt, macht das nicht viel.

Alternativ kann man auch alles ignorieren bis “irgendwann” E mit x = 3…8 kommt. Ab dann weiss man bei jedem kommenden Zeichen, um was es geht, und braucht nicht mal eine ganze Zeile auf Vorrat zu lesen …

Eventuell sind auch zeitliche Pausen vorhanden, was man zur Synchronisation ausnutzen könnte.

Man könnte bei der Uhrzeit vielleicht auch die Länge der Zeile abfragen. Die ist glaube ich konstant, sonst würde der Parser so nicht funktionieren.

Ob man beim Rest am Anfang beginnt ist durch strncmp() sicher abgefragt.