Werte aus dem Seriellen Monitor auswerten

Hallo,

ich wollte, wenn ich bei dem Seriellen Monitor z.B. 12 eingebe, etwas passiert, z.B. die LED auf Pin 12 angeht oder etwas geschrieben wird.
Mein Problem ist, wenn ich das auswerte, was der Befehl Serial.read() sagt, kommen immer zahlen werte, das ist ja kein großes Problem, doch es wenn ich 12 eingebe kommt einmal die 49 (1) und einmal die 50 (2), also nicht als 12, sondern als 1 und 2 und dann geht nicht meine LED 12 an, sondern nur die LED 1 und 2.
Meine "Lösungsidee" war, dass man mit dem Befehl Serial.readString() die geschriebene Zeile in einen String bringt. dann könnte man das so theoretisch so auswerten:

if (Serial.readString() == 12){ // falls die 12 geschrieben wurde, soll die LED angehen;

digitalWrite(12, HIGHT); // die LED auf pin12 wird angeschaltet

}

das hätte den Vorteil, dass man das auch mit Wörtern oder Texten machen kann, doch das klappt bei mir leider nicht ;/.
Ich würde mich aber auch damit zufriedengeben, wenn ich das nur mit Zahlen machen kann, dann könnte man ja den String mit der Zahl in eine int setzen, das habe ich auch ausprobiert, hat aber auch nicht geklappt.

Ich würde mich sehr freuen, wenn mir jemand erklären kann, wie ich das hinbekommen kann.
Wenn jemand einen "fertigen" Code hat, würde ich mich auch über eine Erklärung freuen, denn ich will das Programm auch verstehen ;D

Ich weiß auch, dass es dazu schon Themen gibt, aber mir hat noch keines geholfen und ich habe es nicht verstanden.

Vielen Dank im Voraus LG! 8) :smiley: :wink:

1 Like

Hast du dir das Beispiel in der IDE schon angesehen ?
Da ist beschrieben, wie es gemacht wird.

Hallo,

das ist ASCII Code. Dabei ist 48 ... 0 dezimal usw. Schau dir einmal eine ASCII Tabelle an.
Code 0 bis 47 sind erstmal Steuer- und Sonderzeichen, ab 48 beginnen unsere gewohnten dezimalen Ziffern und Buchstaben.
Das Bsp. der IDE sollte für dich okay sein.

Hey,
vielen Dank für die Antworten schon ein Mal!

Ja, die Beispiele habe ich mir angeguckt und das mit der ASCII Tabelle habe ich (mit den Zahlen) schon verstanden.

Im Beispiel funktioniert das aber nur so weit, dass wenn ich im Seriellen Monitor eine Ziffer eingebe etwas passiert, ich würde es aber gerne mit einer mehrstelligen Zahl machen wollen. Noch besser wäre sogar ein Wort, dass, wenn ich Beispielsweise StartMotor eingebe, der Schrittmotor anfängt zu drehen.

Dazu müsste ich ja eigentlich einen String mit einer if-Abfrage abfragen können?!

Ich kann ja schlecht abfragen, ob der ASCII code erst 49, dann nach einer Millisekunde(oder wie viel?) 50 ist, damit ich die 12 bekomme oder???

LG

Finuino:
Ja, die Beispiele habe ich mir angeguckt...

Aber offensichtlich nicht richtig.
Sieh dir das Beispiel "SerialEvent" an, da wird das beschrieben, was du brauchst.

Stelle den Serial Monitor so ein dass ein LF oder CR am Ende gesendet wird

Das Programm reagiert auf zwei Kommandos: "ledan" und "ledaus". Groß-/Kleinschreibung ist egal:

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

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

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

void parseSerial()
{
  if (strcasecmp(serialBuffer, "ledan") == 0)
    Serial.println("an");
  else if (strcasecmp(serialBuffer, "ledaus") == 0)
    Serial.println("aus");
}

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' || c == '\r') && index > 0)
    {
      serialBuffer[index] = '\0';
      index = 0;
      return true;
    }
  }
  return false;
}

Oder wenn du die Eingabe in einen Integer konvertieren willst:

void parseSerial()
{
  int value = atoi(serialBuffer);
  Serial.println(value);
}

Das kann man auch kombinieren. Dann kann man Kommandos wie "5,aus" oder "6,an" eingeben:

void parseSerial()
{
  char* ptr = strtok(serialBuffer, ",");
  int value = atoi(ptr);
  Serial.println(value);

  ptr = strtok(NULL, ",");
  if (strcasecmp(ptr, "an") == 0)
    Serial.println("LED an");
  else if (strcasecmp(ptr, "aus") == 0)
    Serial.println("LED aus");

  Serial.println();
}

Die Einlese-Funktion ist immer gleich. Man hat einen C String als Ergebnis. Je nachdem was man dann machen will muss man nur die Auswertungs-Funktion ändern

Vielen Dank, werde ich gleich ausprobieren ;D

Finuino:
Noch besser wäre sogar ein Wort, dass, wenn ich Beispielsweise StartMotor eingebe, der Schrittmotor anfängt zu drehen.

Hat dazu nicht gerade gestern hier im deutschen Bereich des Forums jemand (Whandall?) ein komplettes Beispielprogramm gepostet, mit Begriffserkennung und Funktionszeiger, so dass zu jedem übermittelten Begriff eine eigene Funktion aufgerufen werden kann?

Edit/Nachtrag: Ja, war gerade erst gestern.

Hier ist sein Beitrag mit Beispielprogramm, wie man zu jedem Begriff, der über die serielle Schnittstelle gesendet wird, eine eigene Funktion aufrufen kann:
http://forum.arduino.cc/index.php?topic=471383.msg3226120#msg3226120

Er hat wohl nur vergessen dazuzuschreiben, dass im seriellen Monitor das Zeilendende-Trennzeichen auf "Neue Zeile" gesetzt sein muss.

Beispielprogramm gepostet, mit Begriffserkennung und Funktionszeiger

Ein super Beispiel, aber wenn es dir auf den ersten Blick etwas kompliziert vorkommt, mach dir besser erstmal keinen Kopp.

Ein wesentlicher Unterschied zwischen Serial.read() und z.B. dem Einlesen von Zuständen an Pins ist, dass bei read() jeder gelesene Buchstabe danach weg ist, und du mit mehreren read() mehrere Buchstaben nacheinander bekommst.

Ich kann ja schlecht abfragen, ob der ASCII code erst 49, dann nach einer Millisekunde(oder wie viel?) 50 ist, damit ich die 12 bekomme oder???

Doch, im Prinzip läuft es so ab. Nur dass du nicht eine bestimmte Zeit warten musst, sondern abfragst, ob ein oder mehrere neue Zeichen da sind. Daher auch die Sache mit dem Neue-Zeile Zeichen.
Und die ASCII Codes (49, 50) brauchen so natürlich nirgends zu stehen, das würde das Ganze nur schwer lesbar machen.


Die einfachste Wandlung von Text in Zahl geht so:
Wenn ein neuer Buchstabe gekommen ist, und der im Bereich '0' .. '9' liegt ( deine berüchtigte 48 ),
dann multipliziere die Zahl, die du schon hast, mit 10 und addiere den Unterschied zwischen dem neuen Zeichen und '0' dazu.

Nun musst du noch erkennen, wann die Ziffernfolge zuende ist, und dass "die Zahl, die du schon hast" rechtzeitig wieder auf 0 gesetzt wird, bevor die zeichenweise Wandlung wieder losgeht.

if (Serial.available() ) {
  char c = Serial.read();
  if (c >= '0' && c <= '9') value = value*10 + c - '0';
  if ( c == 10) {   // newLine 
     workWith(value);
     value = 0;
  }
}

Quiz: was macht dieser Code mit der Eingabe " 34x21 aber hall0 " ?
Antwort: Hängt davon ab, wie value definiert ist


Mag auch nett sein, wenn dein Sketch auf den Text "StartMotor" reagiert, ist aber effektiv viel Arbeit.
Vieles davon ist irgendwo in Funktionen versteckt, die du hier geschenkt bekommst, die aber, sobald du sie in deinem Sketch verwendest, deine sind. Musst du also schon (zur Not) verstehen, was sie machen und was nicht.

"Start Motor" und "startMotor" sind nämlich erstmal zwei ganz andere Kommandos. (nur mal so als Beispiel)

Ich persönlich finde es einfacher schöner. Soviele Kommandos sind es selten, dass man dafür mehr als einen Buchstaben bräuchte. Ein Buchstabe und eine (mehrstellige) Zahl + Zeilenende ist meist ein guter Kompromiss zwischen einfachem Auswerten und einfacher intuitiver Befehlseingabe.

michael_x:
Ein Buchstabe und eine (mehrstellige) Zahl + Zeilenende ist meist ein guter Kompromiss zwischen einfachem Auswerten und einfacher intuitiver Befehlseingabe.

Lässt sich mit meinem Code auch schön machen, da man dann switch/case auf das erste Zeichen machen kann. Und in dem jeweiligen Fall dann Konvertieren und Zuweisen an eine Variable.

Das ist auch praktisch wenn man unterschiedliche Werte überträgt, aber diese irgendwie unterscheiden muss. Dann kann man z.B. "Txxx" für Temperatur verwenden, und "Lxxx" für Luftfeuchtigkeit.

Hey,
vielen Dank für die vielen langen, mühsamen und guten Antworten!

jurs:
Hier ist sein Beitrag mit Beispielprogramm, wie man zu jedem Begriff, der über die serielle Schnittstelle gesendet wird, eine eigene Funktion aufrufen kann:
Funktion über Serielle Schnittstelle aufrufen - #7 by Whandall - Deutsch - Arduino Forum

, das Programm habe ich leider nur so halb verstanden, aber trotzdem ein BISSCHEN ;/.

michael_x:

Die einfachste Wandlung von Text in Zahl geht so:
Wenn ein neuer Buchstabe gekommen ist, und der im Bereich '0' .. '9' liegt ( deine berüchtigte 48 ),
dann multipliziere die Zahl, die du schon hast, mit 10 und addiere den Unterschied zwischen dem neuen Zeichen und '0' dazu.

kann man das nicht einfach (bei Ziffern) so machen:

if(Serial.read()>=48 && <=57){

a = Serial.read() - 48; // in dem Fall ist "a" die gesuchte Ziffer;

}

und dein "Langer Text" war übrigens auch sehr hilfreich ;D

Ich glaube ich werde es auch so ähnlich, wie Serenifly, machen.

Bin mal gespannt, was mein Programm dann für ein Mischmasch wird :wink:

Noch ein Mal vielen Dank, für die schnellen und hilfreichen Antworten !!!
LG

Finuino:
kann man das nicht einfach (bei Ziffern) so machen:

if(Serial.read()>=48 && <=57){

a = Serial.read() - 48; // in dem Fall ist "a" die gesuchte Ziffer;

}

Das funktioniert nicht. Der Vergleich muss anders aufgebaut werden. Selbst dann kannst Du keine anteren Zeichen, als Ziffern empfangen, auch keinen Zeilenvorschub.
Besser wäre dann:

c = Serial.read();
if (c >= 48 && c <= 57) {
  a = c - 47; // das ist eine Ziffer
}
else {
  // hier die anderen Zeichen bearbeiten
}

Edit: Ich würde immer bis '\n' (Zeilenvorschub) einlesen und dann die Zeile auswerten.

Gruß Tommy

heißt \n neue Zeile ??

Ja, sorry hätte ich dazu schreiben sollen. Manche Sachen sind einem mittlerweile so selbstverständlich, da merkt man das nicht.

Gruß Tommy

ok, Danke!
LG

Es ist auch leserlicher wenn du die Zeichen in Hochkommas setzt. '0' statt 48. Dann musst du dir nicht den ASCII Code merken und man sieht sofort was gemeint ist. Vor allem bei den Vergleichen

Heißt es, wenn man eine Ziffer in Hochkommas setzt, dass diese dann gleichzeitig die ASCll Zahl ist???

Ja. Genauso kann man auch '\n' oder '\r' für LF und CR schreiben

egal:
a = c - 47; // das ist eine Ziffer

Sowas passiert einem dann auch seltener :wink: