Adruino Uno -> Daten aus einem String splitten

Hallo,

ich versuche verzweifelt die Daten aus einem String in Variablen zu schreiben.
Im WWW findet man leider keine guten Ansätze.

Hoffe das ihr mir denk Anstöße geben könnt und wäre für jede Hilfe dankbar.

Die Daten die ich empfangen möchte sehen so aus -> 7:5:8

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

void loop() {
  String daten =  Serial.readStringUntil(','); // read serial data
  String data[] = split(daten, ":"); // Split the comma-separated message
  int x = data[0].toInt();
  int y = data[1].toInt();
  int z = data[2].toInt();
  Serial.print("x= " + x);
  Serial.print(", y= " + y);
  Serial.println(", z= " + z);
}

Folgende Fehlermeldung wird ausgegeben:

Arduino: 1.6.5 (Windows 8.1), Platine: "Arduino/Genuino Uno"

test.ino: In function 'void loop()':
test.ino: In function 'void loop()':
test:7: error: 'split' was not declared in this scope
test:7: error: 'split' was not declared in this scope
'split' was not declared in this scope

'split' was not declared in this scope

Dieser Report hätte mehr Informationen mit
"Ausführliche Ausgabe während der Kompilierung"
aktiviert in Datei > Einstellungen

Nein, hatte ich nicht vor. Hoffe jedoch das mir hier geholfen werden kann.

Du musst eine Methode schon auf dem Objekt aufrufen zu dem sie gehört. Wenn es mich nicht täuscht wurde sie split() Methode aber abgeschafft. Sie existiert nicht im Code und auch nicht in der Doku. Ist mir auch neu. Seltsam.

Am besten man steigt gleich auf C Strings um. Das geht sehr schön und braucht weniger Speicher als die String Klasse:

const int SERIAL_BUFFER_SIZE = 21;
char serial_buffer[SERIAL_BUFFER_SIZE];

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

void loop()
{
  if (read_serial())
    parse_serial();
}

bool read_serial()
{
  static byte index;

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

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

void parse_serial()
{
  int x = atoi(strtok(serial_buffer, ";:,"));
  int y = atoi(strtok(NULL, ";:,"));
  int z = atoi(strtok(NULL, ";:,"));

  Serial.print(F("x = ")); Serial.println(x);
  Serial.print(F("y = ")); Serial.println(y);
  Serial.print(F("z = ")); Serial.println(z);
}

Den Serial Monitor dabei so einstellen dass ein LF/linefeed/newline am Ende gesendet wird! Also den String mit einem LF statt einem Komma abschließen. Sonst geht es nicht!

Den seriellen Puffer kann man bei Bedarf größer machen

Wieso schreibst Du die Daten, die einzeln an der Seriellen Schnittstelle ankommen, zuest in einen String, um sie danach zu teilen und dann in Zahlen umzuwandeln?
Wieso liest Du sie nicht mit Serial.read gleich in die richtigen Variablen?.

Grüße Uwe

uwefed:
Wieso liest Du sie nicht mit Serial.read gleich in die richtigen Variablen?

Das ist nur wirklich sinnvoll wenn es immer einstellige Ziffern sind. Ist hier vielleicht der Fall, aber wer weiß

Man kann zwar auch per Serial.read() Zahlen mit mehreren Ziffern einlesen und die Ziffern aufaddieren, aber ich habe festgestellt, dass der Umweg über einen C String einfach flexibler ist. Der Code ist nicht viel und man kann ihn leicht ändern. Die Einlese-Funktion bleibt immer gleich und wenn sich was am Daten-Format ändert ist schnell eine andere Parse Funktion geschrieben.

Es gibt parseInt() aber das ist eine Schrott Funktion da blockierend. Wenn man das drei mal macht und nur zwei Zahlen eingibt steht der Code erst mal für eine Sekunde still. Mit dem Timeout Parameter wird es etwas besser, aber immer noch nicht gut.

Oder eine andere Sache die mit C Strings extrem einfach geht: verschiedene Kommandos unterscheiden. Mal angenommen man will neben den Koordinaten noch eine Geschwindigkeit eingeben. Dann macht man seine zwei Kommandos so:
"c10,20,30"
"s100"

Und kann einfach das machen:

switch(serial_buffer[0])
{
case 'c':
  x = atoi(strtok(serial_buffer + 1, ";:,"));
  ...
  break;
case 's':
  speed = atoi(serial_buffer + 1);
  break;
}

Nicht viel Code und einfach erweiterbar

Umweg über einen String

Hab mich schon gewundert, aber du meinst gar keinen String sondern einen

char serial_buffer[BUFSIZE];  // zur Verwirrung auch c_string oder ähnlich genannt

Ja, C String halt. Keinen Arduino String :stuck_out_tongue:

Das hätt mich jetzt auch gewundert

Ok, ich habe es ausgebessert :stuck_out_tongue:

Es ging mir um die Unterscheidung "Strings <-> Ziffern/Zahlen direkt einlesen" und nicht um "C Strings <-> Arduino String Klasse"

Hallo,

vielen Dank für den schnellen Code @Serenifly

Auch dir vielen Dank Uwe.

@Uwe Es werden noch ein paar Variablen hinzukommen und so wie Serenifly das gemacht hat finde ich sehr gut.

:slight_smile: