Text aus Seriellen Monitor auslesen und aufteilen

Moin.

Ich versuche mich gerade daran, eine Eingabe über den Seriellen Monitor zu verarbeiten.

Ich möchte

time1:11:22:33;

einlesen und dann in

time1
11
22
33

aufteilen.

Das einlesen funktioniert soweit nur habe ich momentan überhaupt keinen Ansatz, wie ich dies dann aufteilen kann :confused:

Hat jemand ne Idee?

Wie wäre es hiermit: strtok(...)

Die Idee hatte ich auch schon.

Nur habe ich das Problem, das ich den Text als String einlese und strtok nur char zerteilen kann, oder?

Oder kann ich auch in einen char den Text einlesen? bei mir kommt da dann nur Müll raus!

Aduadu:
...
time1:11:22:33;

einlesen und dann in

time1
11
22
33

aufteilen.

Strings sind ein klasse Sache, wenn es um solche Dinge geht. Aber sie sind wohl sehr speicherintensiv. Ich habe noch nicht so viel Erfahrung, was das angeht, aber ich glaube, dass Du Eingaben besser in Form von C-Strings (char-Arrays, die mit 0 aufhören) händeln (oder Beethoven :slight_smile: könntest.

Das könnte die Lösung Deines Problems, wenn sie denn gefunden wird, erheblich schneller machen.

Nachtrag: Ups, ich sehe gerade den letzten Satz Deines letzten Postings. Ich würde eher das Problem lösen, die Eingabe als C-String zu erfassen, als zu gucken, wie Du den String zerschnippeln kannst.

Gruß

Gregor

bei mir kommt da dann nur Müll raus!

Dann machst du was falsch.
Aber leider kann ich nicht erkennen, was..

Ja, die Stringklasse macht Sorgen auf kleinen AVRs.
Je kleiner der Heap, desto problematischer.
Genauer: Die dynamische Speicherverwaltung bereitet die Sorgen.
Selbst bei sorgfältiger Programmierung neigt der Speicher(Heap) zur Fragmentierung.
Und dann knallts irgendwann...

Ich hab es so gemacht:

sRequest = Serial.readStringUntil('\r'); //Zeile kpl einlesen

und dann so:

Serial.println("Stringwerte:");
Serial.println(sRequest.substring(15, 17));
Serial.println(sRequest.substring(18, 20));
Serial.println(sRequest.substring(24, 26));
Serial.println(sRequest.substring(27, 28));

Funktioniert, könnte aber blockierender Code sein... :grin:

Das ist doch alles mehr als überflüssig! Schaut euch Kapitel 4 mal an, bevor man hier wieder mit Kanonen auf Spatzen schießt
http://www.oreilly.de/catalog/arduinockbkger/chapter/ch04.pdf

Erst mal eine Funktion mal um Text allgemein einzulesen (geht nicht nur mit Serial, sondern auch mit SD oder Ethernet!):

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

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

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

    if (c >= 32 && index < SERIAL_BUFFER_SIZE - 1)
    {
      serialBuffer[index++] = c;
    }
    else if (c == '\n' && index > 0)
    {
      serialBuffer[index] = '\0';
      index = 0;
      return true;
    }
  }
  return false;
}

Dann diese Verwenden und eine Parser dazu schreiben:

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

void loop()
{
  if (readSerial(Serial))
  {
    Serial.print("Read: "); Serial.println(serialBuffer);
    parseSerial();
  }

}

void parseSerial()
{
  char* cmd = strtok(serialBuffer, ":");

  if (strcasecmp_P(cmd, PSTR("time1:")) == 0)
  {
    int hour = atoi(strtok(NULL, ":"));
    int minute = atoi(strtok(NULL, ":"));
    int second = atoi(strtok(NULL, ":"));

    Serial.println(cmd);
    Serial.println(hour);
    Serial.println(minute);
    Serial.println(second);
    Serial.println("---");
  }
}

Die Zeit kann man allerdings auch anders machen, solange man immer 2 Stellen pro Teil macht:

void parseSerial()
{
  if (strncasecmp_P(serialBuffer, PSTR("time1:"), 6) == 0)
  {
    char* ptr = serialBuffer + 6;

    int hour = atoi(ptr);
    int minute = atoi(ptr + 3);
    int second = atoi(ptr + 6);

    Serial.println(hour);
    Serial.println(minute);
    Serial.println(second);
    Serial.println("---");
  }
}

Also einfach Ausnutzen dass die Position der Teile bekannt ist wenn man sich genau daran hält. Dann darf man aber auch keine Abweichungen bei der Angabe machen. strtok() ist da flexibler. Und braucht auch kaum Speicher.

Den SerialMonitor dabei ein LF/newline am Ende senden lassen! Sonst geht es nicht

EDIT:
Hatte die globalen Variablen vergessen

stoni99:
Ich hab es so gemacht:

sRequest = Serial.readStringUntil('\r'); //Zeile kpl einlesen
.........

Funktioniert, könnte aber blockierender Code sein... :grin:

Du machst Fortschritte. Immerhin hast du das schon erkannt.

Moin.

Leider habe ich es erst heute geschafft eure Ideen umzusetzen....

@Serenifly: Dein Lösungsvorschlag funktioniert hervorragend!!! Muss da noch ein wenig durchsteigen, aber das hat mir sehr weiter geholfen!!!!

sschultewolter:
Das ist doch alles mehr als überflüssig! Schaut euch Kapitel 4 mal an, bevor man hier wieder mit Kanonen auf Spatzen schießt
http://www.oreilly.de/catalog/arduinockbkger/chapter/ch04.pdf

Auf wen beziehst Du Dich?

Gruß

Gregor

Schön zu sehen, dass O'REILLY das Kapitel 4 des Kochbuch - Klassikers als Leseprobe veröffentlicht.

Schadet euch sicher nicht, die 59 Seiten gründlich durchzuarbeiten, statt arduinomässig Beispielsketche und Libraries auszuprobieren, Kinder :wink:

Auf wen beziehst Du Dich?

Selbstreferentiell ist eigentlich was anderes, dachte ich. Aber das Kochbuch eignet sich schon auch als Spatzen-Kanone. :wink: :wink: :stuck_out_tongue:

Da werde einige nette Sachen gezeigt wie man Integer direkt einlesen kann ohne erst mal über einen String zu gehen. Sollte man mal gemacht haben und ihn manchen Fällen ist es von Vorteil.

Ich finde aber mit einem String ist man flexibler. Da kann viel leichter das Format anpassen ohne viel am Code zu ändern. Die Einlese-Funktion bleibt immer gleich und man muss nur den Parser ändern. Und man kann mehrere verschiedene Parser im gleichen Programm haben.

Wenn man Text + Daten kombiniert, geht es gar nicht anders. Also wie hier:
time:xx:xx:xx
oder:
date:xx.xx.xx

Eine Sache mit der man sich hier das Leben etwas vereinfachen kann ist wenn man statt eines ganzen Wortes nur einen Buchstaben voranstellt. Also hier 't' oder 'T'. Dann reicht ein switch/case für die Abfrage.