Problem mit Serial.available und Serial.readStringUntil

Hallo,

ich habe gerade ein einfaches Verständnisproblem.

Wenn ich den folgenden Sketch hochlade kommt zunächst folgendes (siehe Bild 1).

String b = "test";

void setup() {

  Serial.begin (9600);
  Serial.setTimeout(1000);
  delay(1000);
}

void loop() {
  if (Serial.available() > 0) {
    b = Serial.readStringUntil(',');
  }
    //ESPSerial.print(a);
    Serial.print("b: ");
    Serial.println(b);
    delay(300);
  
}

Soweit so gut. Gebe ich nun jedoch z.B. Hallo, ein, so kommt das (siehe Bild 2)
Weiß jemand wo das Problem liegt?
Liebe Grüße,

Wenn Du einmal in der IDE auf CTRL-T drückst, siehst Du den Fehler selber.

String b = "test";

void setup()
{

  Serial.begin (9600);
  Serial.setTimeout(1000);
  delay(1000);
}

void loop()
{
  if (Serial.available() > 0)
  {
    b = Serial.readStringUntil(',');
  }
  //ESPSerial.print(a);
  Serial.print("b: ");
  Serial.println(b);
  delay(300);

}

Du gibst alle 300ms 'b' aus - egal ob Du was empfangen hast oder nicht.

Ja aber müsste nicht der String Hallo in b gespeichert werden?
Also das quasi die ganze Zeit Hallo ausgegeben wird.

Gebe ich nun jedoch z.B. Hallo, ein, so kommt das (siehe Bild 2)
Weiß jemand wo das Problem liegt?

Das sieht doch richtig aus!

Einmal kommt das Hallo und danach das Zeilenende, solange bis du was anderes eingibst.

Also alles ok, es tut das, was du programmiert hast.

Ja aber müsste nicht der String Hallo in b gespeichert werden?
Also das quasi die ganze Zeit Hallo ausgegeben wird

Nöö...
Nach dem Hallo kommt ein Zeilenende, und das bleibt dir erhalten.

In Ergänzung zu combie (war gerade noch am Bilder schießen):

Im Prinzip ja, aber...
...nur dann, wenn nach dem Komma keine weiteren Zeichen kommen.
Vermutlich hast Du im seriellen Monitor das Zeilenende noch an:
NLCR.png

Das kann man ausschalten:
NoLineEnding.png

NLCR.png

NoLineEnding.png

Hallo,

ich spendiere einen Nullterminator. :slight_smile:

Ändere folgende Zeile mal so ab.

b = Serial.readStringUntil('\0');

Danach nur Hallo tippen und absenden.
Oder du lässt dein Komma stehen, und tippst Hallo mit angehängten Komma.
Dann merkst du schon wie das funktioniert.
readStringUntil liest Zeichen in deine String Variable bis es deinen definierten "Terminator" findet. In deinem Fall das Kommazeichen. Solange man nichts neues eintippt bleibt deine Zeichenkette in der String Variablen b erhalten.

In deinem Fall hat er immer gelesen und nach dem Komma gesucht und nie gefunden. Deshalb gabs anschließend nur Leerzeichen. Allerdings weiß ich nicht wo die Leerzeilen dazwischen herkommt. Vielleicht bedingt durch volle Zeilen mit lauter Leerzeichen und dadurch "unsichtbaren" Zeilenumbruch.

Allgemein wird String auf kleinen Controllern jedoch nicht empfohlen. Man nimmt besser ein char Array mit etwas mehr Aufwand.

Bei Serial dürfte kein '\0' ankommen.
Das Zeichen der Wahl dürfte eher '\n' sein.
Die Leerzeile kommt mwohl vom Zeilenvorschub aus dem SerMon.

Gruß Tommy

Doc_Arduino:
Allerdings weiß ich nicht wo die Leerzeilen dazwischen herkommt.

readStringUntil() hat einen Timeout (Defaultwert 1s).
Damit steht dann das Zeilenende schon in b drin, egal ob danach noch ein Komma kommt.

Aja danke, jetzt wo ich auf "kein Zeilenende" umgestellt habe funktioniert es.

Jetzt noch eine ganz blöde Frage zum Verständnis: wenn ich also "neue Zeile" einstelle, dann wird also diese neue Zeile in b gespeichert oder?

Und zum Thema Strings allgemein. Ich lese immer wieder, dass die Verwendung von Strings aufgrund des Speichers ungünstig ist. Betrifft das den Arduino Mega auch?

Ja, den eigentlich auch. Die Probleme kommen halt etwas später. Schau Dir mal dieses Tutorial zu Zeichenketten an.

Gruß Tommy

Hallo,

ja '\n' ist besser. :slight_smile:

jule2000:
Jetzt noch eine ganz blöde Frage zum Verständnis: wenn ich also "neue Zeile" einstelle, dann wird also diese neue Zeile in b gespeichert oder?

Beim ersten Mal nicht - da stoppt das wie befohlen beim Komma. Danach sind aber noch Zeichen eingetroffen - nämlich das Zeilenende.
Wenn Du mal 'Hallo,hier Rest' eingibst, siehst Du was dann passiert.

Ich habe hier mal ganz schnell einen Sketch erstellt, der Dir Zeichen für Zeichen als Zahl (im HEX-Format) und dahinter als Zeichen ausgibt. Damit kannst Du sehen, was nacheinander in Deinem String landen würde.
Spiel mal ein wenig mit Zeichenketten und der Zeilenende-Einstellung.

void setup()
{

  Serial.begin (9600);
  Serial.setTimeout(1000);
  delay(10);
}

void loop()
{
  if (Serial.available() > 0)
  {
    char b = Serial.read();
    Serial.print(b, HEX);
    if (b >= ' ')
    {
      Serial.print(" \'");
      Serial.print(b);
      Serial.println('\'');
    }
    else
    {
      Serial.println(F("  nicht druckbares Zeichen"));
    }
  }
}

Das erzeugt mit "Hallo," bei eingeschaltem Zeilenende (NL+CR) diese Ausgabe:

18:27:40.918 -> 48 'H'
18:27:40.918 -> 61 'a'
18:27:40.918 -> 6C 'l'
18:27:40.918 -> 6C 'l'
18:27:40.918 -> 6F 'o'
18:27:40.918 -> 2C ','
18:27:40.965 -> D  nicht druckbares Zeichen
18:27:40.965 -> A  nicht druckbares Zeichen

Danke werde ich mir anschauen :).

Und vielen Dank für die schnellen Antworten!

jule2000:
Und zum Thema Strings allgemein. Ich lese immer wieder, dass die Verwendung von Strings aufgrund des Speichers ungünstig ist. Betrifft das den Arduino Mega auch?

Durchaus.

Die Verwendung von nur einem String Objekt mildert das Problem.
Zusätzlich wurde String::reserve() erfunden.
Die beiden Maßnahmen, sollten im Team jegliches Ungemach aus der Ecke vertreiben.

ich spendiere einen Nullterminator. :slight_smile:

Ändere folgende Zeile mal so ab.

  b = Serial.readStringUntil('\0');

Sicher, dass das geht? (Bzw. nicht einfach ins timeout läuft?)
Ein '\0' wird nämlich gar nicht mitübertragen.

Der Datentyp String ist übrigens nie notwendig, und wurde nur zur Bequemlichkeit bei Arduino dazuerfunden. (Und weil im ersten Entwurf "die Arduino-Sprache" wie Java aussehen sollte, obwohl es immer schon C++ war)
Wenn String also Probleme macht, ist es das beste, es einfach nicht zu verwenden. (Finde ich)
Gibt auch readBytesUntil.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.