Serielle Kommunikation

Guten Tag

Ich baue einen Kickarmroboter. Nun probiere ich schon längere Zeit mit dem Arduino rum, um den Roboter anzusteuern. Einige einfachere Sachen wie einen Schrittmotor drehen zu lassen oder if then else Sätze sind kein Problem, jedoch wenn es komplexer wird, fehlt mir das Fachwissen und google etc. geben auch nicht mehr Lösungen die mir Logisch scheinen oder die ich auf mein Problem umschreiben könnte. Habe im Forum auch schon einige Intressante Sachen gelesen, aber sobald ich was probiert habe klappte es dann doch irgendwie nicht.

Also nun zu meinen Problem:

Ich möchte von Visual Basic X Y Z Werte an denn Arduino senden. Da hier ja nicht viele mit VB arbeiten, können wir auch einfach auf den Serial Monitor von Arduino beschränken. Ich möchte dort eine Eingabe machen(X20 Y30 Z10) dann soll mir der Arduino die Eingabe einlesen und die Variablen X Y Z nach den gennanten Werten setzen. Zum Verständnis ich hab im Arduino Variablen X Y Z und die sollen dann den Wert erhalten der geschiockt wurde also X=20 Y=30 Z=10.

Bis jetzt habe ich es fertig gebracht, eine Led anzusteuern. Ich habe auch schon einen Lösungsansatz mit Serial.readBytesUntil(character, buffer, length) komme da aber nicht weiter, hab das Beispiel(http://forum.arduino.cc/index.php?topic=225802.0) ganz unten probiert, anstatt der Display ansteuerung einfach , dass der Wert wieder zurück geschickt wird. Irgendwie funktioniert das bei mir aber nicht, es kommt die Fehlermeldung: invaild conversion from 'const char* to 'char'.

Ich hoffe, dass ich nicht all zu Kompliziert geschrieben habe und das jemand mir helfen kann ;)

Gruss Nils

hab das Beispiel(http://forum.arduino.cc/index.php?topic=225802.0) ganz unten probiert, anstatt der Display ansteuerung einfach , dass der Wert wieder zurück geschickt wird. Irgendwie funktioniert das bei mir aber nicht, es kommt die Fehlermeldung: invaild conversion from 'const char* to 'char'.

mit "ganz unten" meinst du reply #14, oder doch einen anderen Faden ?

Den Fehler, dass char* was anderes als char ist, hatten wir aber auch die Tage (mal wieder). Wenn du's nicht selbst findest, musst du schon einen sketch posten, der den Fehler produziert. ( Tip: der Fehler ist eher in der Variablendeklaration als in den ausführbaren Anweisungen, auch wenn's dort erst dem Compiler auffällt, und zu einem Sketch gehört beides, nicht nur ein Schnipsel aus der mitte von loop() )

AndererNilsson:
Ich möchte von Visual Basic X Y Z Werte an denn Arduino senden. Da hier ja nicht viele mit VB arbeiten, können wir auch einfach auf den Serial Monitor von Arduino beschränken. Ich möchte dort eine Eingabe machen(X20 Y30 Z10) dann soll mir der Arduino die Eingabe einlesen und die Variablen X Y Z nach den gennanten Werten setzen. Zum Verständnis ich hab im Arduino Variablen X Y Z und die sollen dann den Wert erhalten der geschiockt wurde also X=20 Y=30 Z=10.

#define ZEILENTRENNZEICHEN 13   // 13 ist Steuerzeichen CR (Carriage Return)
char* receiveBuffer()
// Empfang einer Textzeile über Serial
// Rückgabewert NULL: Zeile nicht/unvollständig empfangen
// oder Rückgabewert char-Pointer auf die vollständig empfangene Textzeile
{
  static char lineBuffer[25]; // Maximale Zeilenlänge festlegen
  static byte counter=0;
  char c;
  if (Serial.available()==0) return NULL; // Nullpointer zurück
  if (counter==0) memset(lineBuffer,0,sizeof(lineBuffer));// Puffer vor Benutzung löschen
  c=Serial.read();
  if (c==ZEILENTRENNZEICHEN)
  {
    counter=0;
    return lineBuffer;
  }
  else if (c>=32) // kein Steuerzeichen?
  {
    lineBuffer[counter]=c; // Zeichen im Zeilenpuffer einfügen
    if (counter<sizeof(lineBuffer)-2) counter++;
  }
  return NULL;
}

boolean serialTask(int &Xval, int &Yval, int &Zval)
// Rückgabewert false: keine Textzeile empfangen oder nicht alle drei Werte empfangen
// Rückgabewert true: Textzeile wurde empfangen und neue Werte zugewiesen
{
  char* text=receiveBuffer();
  if (text==NULL) return false;
  // Testen auf "X", "Y" und "Z" Werte
  char* XVAR=strchr(text,'X');
  char* YVAR=strchr(text,'Y');
  char* ZVAR=strchr(text,'Z');
  if (XVAR==NULL || YVAR==NULL || ZVAR==NULL) return false;
  Xval=atoi(XVAR+1);
  Yval=atoi(YVAR+1);
  Zval=atoi(ZVAR+1);
  return true;
}

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

void loop()
{
  int x, y, z;
  char linebuf[25];
  if (serialTask(x, y, z)) // neue Werte wurden empfangen
  { // Ausgabe formatieren
    snprintf(linebuf,sizeof(linebuf),"X=%d, Y=%d, Z=%d",x,y,z);
    Serial.println(linebuf);
  }
}

Oder einfach mal das Beispiel Communication=> ReadASCIIString ansehen.

Hier wird genau das gemacht und erklärt.

Guten Tag

Danke für euere Bemühungen!! Stelle gerne wiedermal eine Frage.

Schade das ich die Seite von Arduino nicht selber gefunden habe :&

Und hier noch der Code:

void setup() {
// initialize serial:
Serial.begin(9600);
}

void loop() {
// wenn was vom Seriellerschnittstelle kommt dann soll es gelesen werden:
while (Serial.available() > 0) {

// nach dem nächsten int suchen(mann kann werte mit space komma etc trennen):
int x = Serial.parseInt();
// do it again:
int y = Serial.parseInt();
// do it again:
int z = Serial.parseInt();
// Ausgabe der Werte nacheinander( Wenn X20 eingegeben wurde kommt 20 raus da X kein wert von int ist)
Serial.println(x);
Serial.println(y);
Serial.println(z);

}
}

Nochmals Danke!!

jurs:

#define ZEILENTRENNZEICHEN 13   // 13 ist Steuerzeichen CR (Carriage Return)

char* receiveBuffer()
// Empfang einer Textzeile über Serial
// Rückgabewert NULL: Zeile nicht/unvollständig empfangen
// oder Rückgabewert char-Pointer auf die vollständig empfangene Textzeile
{
  static char lineBuffer[25]; // Maximale Zeilenlänge festlegen
  static byte counter=0;
  char c;
  if (Serial.available()==0) return NULL; // Nullpointer zurück
  if (counter==0) memset(lineBuffer,0,sizeof(lineBuffer));// Puffer vor Benutzung löschen
  c=Serial.read();
  if (c==ZEILENTRENNZEICHEN)
  {
    counter=0;
    return lineBuffer;
  }
  else if (c>=32) // kein Steuerzeichen?
  {
    lineBuffer[counter]=c; // Zeichen im Zeilenpuffer einfügen
    if (counter<sizeof(lineBuffer)-2) counter++;
  }
  return NULL;
}

boolean serialTask(int &Xval, int &Yval, int &Zval)
// Rückgabewert false: keine Textzeile empfangen oder nicht alle drei Werte empfangen
// Rückgabewert true: Textzeile wurde empfangen und neue Werte zugewiesen
{
  char* text=receiveBuffer();
  if (text==NULL) return false;
  // Testen auf “X”, “Y” und “Z” Werte
  char* XVAR=strchr(text,‘X’);
  char* YVAR=strchr(text,‘Y’);
  char* ZVAR=strchr(text,‘Z’);
  if (XVAR==NULL || YVAR==NULL || ZVAR==NULL) return false;
  Xval=atoi(XVAR+1);
  Yval=atoi(YVAR+1);
  Zval=atoi(ZVAR+1);
  return true;
}

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

void loop()
{
  int x, y, z;
  char linebuf[25];
  if (serialTask(x, y, z)) // neue Werte wurden empfangen
  { // Ausgabe formatieren
    snprintf(linebuf,sizeof(linebuf),“X=%d, Y=%d, Z=%d”,x,y,z);
    Serial.println(linebuf);
  }
}

Sorry, dass ich dieses Thema nochmal auskrame, aber ich würde gerne den Sketch von jurs für mein Projekt verwenden. Ich suche noch nach einer Möglichkeit den Sketch zu erweitern, sodass auch Befehle empfangen und ausgewertet werden können. So in der Art:
“goto X10 Y20 Z10”

Dh. Einen Befehl am Anfang, z.B. “goto” (=>Was mit den Koordinaten gemacht werden soll) und dann die eigentlichen Koordinaten. Wäre super, wenn mir da jemand weiter helfen könnte

Lerne mit den Standard C String Funktionen umzugehen.

Dann wird es ganz einfach:

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

  char str[] = "goto10,20,30";

  if (strncmp(str, "goto", 4) == 0)
  {
    int x = atoi(strtok(str + 4, ",;"));
    int y = atoi(strtok(NULL, ",;"));
    int z = atoi(strtok(NULL, ",;"));

    Serial.println(x);
    Serial.println(y);
    Serial.println(z);
  }
  else
    Serial.println(F("unbekanntes Kommando"));
}

void loop() 
{
}

Oder strncasecmp() um Groß-/Kleinschreibung zu ignorieren

Noch einfacher wird es wenn du das Kommando auf einen Buchstaben beschränkst. Besonders wenn man mehrere Kommandos hat. Dann kann man einfach switch/case auf das erste Zeichen machen:

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

  char str[] = "g10,20,30";

  switch(str[0])
  {
    case 'g':
    case 'G':
      {
       int x = atoi(strtok(str + 1, ",;"));
        int y = atoi(strtok(NULL, ",;"));
        int z = atoi(strtok(NULL, ",;"));

        Serial.println(x);
        Serial.println(y);
        Serial.println(z);
      }
      break;
    default:
        Serial.println(F("unbekanntes Kommando"));
  }
}

void loop() 
{
}

Serenifly: Noch einfacher wird es wenn du das Kommando auf einen Buchstaben beschränkst. Besonders wenn man mehrere Kommandos hat. Dann kann man einfach switch/case auf das erste Zeichen machen:

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

 char str[] = "g10,20,30";

 switch(str[0])  {    case 'g':    case 'G':      {       int x = atoi(strtok(str + 1, ",;"));        int y = atoi(strtok(NULL, ",;"));        int z = atoi(strtok(NULL, ",;"));

       Serial.println(x);        Serial.println(y);        Serial.println(z);      }      break;    default:        Serial.println(F("unbekanntes Kommando"));  } }

void loop() { }

Erstmal vielen Dank für deinen Sketch. Ich glaube aber das break; fehlt hier noch nach case 'g'. Mein Problem: Ich würde gerne deine Funktion mit der Funktion char* receiveBuffer() von jurs kombinieren, aber bei jurs' Funktion handelt es sich ja um ein char pointer und bei deiner um ein char array.

100-200-00: Sorry, dass ich dieses Thema nochmal auskrame, aber ich würde gerne den Sketch von jurs für mein Projekt verwenden. Ich suche noch nach einer Möglichkeit den Sketch zu erweitern, sodass auch Befehle empfangen und ausgewertet werden können. So in der Art: "goto X10 Y20 Z10"

Dh. Einen Befehl am Anfang, z.B. "goto" (=>Was mit den Koordinaten gemacht werden soll) und dann die eigentlichen Koordinaten. Wäre super, wenn mir da jemand weiter helfen könnte

OK, dann poste ich auch nochmal in diesem Thread mit und stelle die Rückfrage:

Würde es nicht reichen, einen Befehl und seine Parameter in einer Zeile getrennt mit Leerzeichen zu posten, also beispielsweise

Statt Befehl:

goto X10 Y20 Z10

Setze Befehl:

goto 10 20 10"

Oder nochmal anders gefragt:

Reicht es aus, wenn der Arduino in einer Zeile den Befehl goto und drei Parameter auswertet?

Oder soll der Arduino auch die Reihenfolge der Parameter erkennen und auswerten?

Also kann der goto-Befehl mal so gesendet werden:

goto X10 Y20 Z10

(Reihenfolge XYZ Und mal so:

goto Y50 Z100 X20

Reihenfolge YZX So dass der Ardduino auch bei wechselnder Reihenfolge die Parameter auswertet, ohne dass es nach dem goto immer dieselbe Reihenfolge ist , in der die Parameter nachfolgen?

Also wenn das Protokoll 100% genau definiert ist, kann es der Arduino auch 100% genau zerlegen.

Aber der Arduino muß eben wissen, woran er X und Y und Z erkennen soll.

Ist X immer der erste Parameter nach einem goto, getrennt durch ein Leerzeichen?

Oder ist X immer der parameter, der vom vorhergehenden Kommando pder Parameter mit einem Leerzeichen und einem X in der Form " X" abgetrennt ist?

Nur wenn das Protokoll 100% definiert ist, kann es exakt zerlegt werden. Aus Deiner Beschreibung ist mir nicht ganz klar, ob das Protokoll nach einem goto immer die drei Parameter in derselben Reihenfolge sendet, oder ob der arduino den X-Parameter am Buchstaben X, den Y-Parameter am Buchstaben Y und den Z Parameter am Buchstaben Z in den empfangenen Daten erkennen soll, so dass die Parameter in beliebiger Reihenfolge empfangen werden können.

aber bei jurs' Funktion handelt es sich ja um ein char pointer und bei deiner um ein char array.

Lerne etwas C Grundlagen zu Arrays. Dann verstehst du auch dass eine Array Variable nicht viel mehr als ein Zeiger auf das erste Element ist. Bei jurs ist das Array statisch innerhalb der Auslese-Funktion deklariert und es wird ein Zeiger darauf zurückgegeben. Das läuft letztlich auf das gleiche hinaus. Man speichert den Zeiger erst mal ab. Danach kann man ihn auswerten und fast genauso wie ein Array behandeln (ein Unterschied ist z.B. die Abfrage auf NULL um zu sehen ob man überhaupt ein Ergebnis hat).

Das oben war sowieso nur Test Code der das Array fest vorgibt. Du kannst auch meine Einlese-Funktion aus dem Link verwenden. Die macht genau das gleiche wie die von jurs, aber hat das Array global definiert und gibt true/false statt einen Zeiger zurück um zu sehen ob eine Zeile eingelesen wurde.

jurs: Reicht es aus, wenn der Arduino in einer Zeile den Befehl goto und drei Parameter auswertet?

ja, das würde reichen. Am Schluss soll sowieso eine GUI die Befehle (immer in korrekter Reihenfolge) an den Arduino schicken.

Serenifly: Lerne etwas C Grundlagen zu Arrays. Dann verstehst du auch dass eine Array Variable nicht viel mehr als ein Zeiger auf das erste Element ist.

Arrays habe ich verstanden, nur die Zeiger verstehe ich leider nicht. Habe mir bereits ein Buch zu C Programmieren geholt, aber die Zeiger wollen mir einfach nicht in den Kopf gehen.

Ich habe verstanden, dass ein array ein Feld ist, in das ich mehrere Werte eintragen kann und dass ich einzelne werte über den Index in den eckigen Klammern aufrufen kann (z.B: myarray[Index]=5;).

myArray ist äquivalent zu &myArray[0]. Die Adresse des ersten Elements. Funktionen die mit Arrays arbeiten (wie strtok() in diesem Fall) haben Zeiger als Parameter.

Wenn du einen Zeiger hast der auf Array Speicher zeigt dann kannst du da auch [] verwenden. Man kann also ganz einfach sowas machen:

void loop()
{
   char* ptr = receiveBuffer();

   if (ptr != NULL)
   {
       switch (ptr[0])
       {
       }
   }
}

Oder Alternativ wenn man näher an der Zeiger-Schreibweise bleiben will:

void loop()
{
   char* ptr = receiveBuffer();

   if (ptr)
   {
       switch (*ptr)
       {
       }
   }
}

Ich sehe auch gerade, dass ich meine Version gar nicht verlinkt hatte: http://forum.arduino.cc/index.php?topic=359203.msg2486412#msg2486412

parseSerial() würde bei dir dann anders aussehen, aber die Einlese-Funktion ist universell verwendbar. Und nicht nur für die serielle Schnittstelle

Macht wie gesagt das gleiche, aber ohne direkt Zeiger zu verwenden

100-200-00: ja, das würde reichen. Am Schluss soll sowieso eine GUI die Befehle (immer in korrekter Reihenfolge) an den Arduino schicken.

Arrays habe ich verstanden, nur die Zeiger verstehe ich leider nicht. Habe mir bereits ein Buch zu C Programmieren geholt, aber die Zeiger wollen mir einfach nicht in den Kopf gehen.

Ich habe verstanden, dass ein array ein Feld ist, in das ich mehrere Werte eintragen kann und dass ich einzelne werte über den Index in den eckigen Klammern aufrufen kann (z.B: myarray[Index]=5;).

Vielleicht kannst Du mir mal erklären, was Dir an dem in Antwort #2 geposteten Code nicht gefällt?

Der Code funktioniert mit Kommandozeilen, die mit einem Zeilentrennzeichen CR (Carriage Return) gesendet wwerden und nach diesem Schema gesendet werden: X20 Y30 Z10

Also kein "goto" als Kommando vorneweg, sondern nur die drei Parameter mit vorangestelltem Großbuchstaben.

Zum Testen: Seriellen Monitor öffnen und einstellen auf 9600 Baud und dass als Zeilenende CR gesendet wird, dann kannst Du Kommandos der Art senden: X20 Y30 Z10 Die Parameter werden ausgelesen und als Antwort eine ähnliche Zeile ausgegeben, die aus den eingelesenen Variablen aufgebaut wird, und zwar: X=20, Y=30, Z=10

Was fehlt Dir?

Dass das Programm nur auf Zeilen reagiert, die mit "goto" beginnen?

Oder sollen die Parameter etwas anderes als int-Werte sein?

Im oben geposteten Programmbeispiel sind die eingelesenen Variablen in der loop-Funktion so deklariert: int x, y, z;

Sollen das andere Werte sein? byte? long? unsigned int? Oder gar 'float' Gleitkommawerte?

Ich weiß nicht, was Dir an dem Programmbeispiel fehlt. Das Programmbeispiel kommt mit vollständigem Quellcode, den Du einsehen kannst.

Aber ich fange jetzt nicht an, ein vollständiges Programmiertutorial zu schreiben, das anfängt bei "am anfang schuf Gott Himmel und Erde und dann irgendwann die Programmiergrundlagen in der Programmiersprache C/C++ behandelt.

Im Gegensatz zu dem oben geposteten Programmbeispiel wäre das ein dicker Wälzer. Soviel Zeit habe ich nicht, so ein Buch zu schreiben, dass sämtliche Grundlagen von C/C++ abhandelt.

P.S.: Wie ich gerade gemerkt habe, kannst Du auch das Kommando goto vorneweg senden, also: goto X10 Y20 Z10 Auch das wird von meinem Programm ausgewertet, allerdings hat das Vorhandensein oder Nichtvorhandensein von goto am Zeilenanfang keine spezielle bedeutung, das wird einfach überlesen.

Hier mal komplett:

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

struct Coordinate
{
  int x;
  int y;
  int z;
};

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

void loop()
{
  if (readSerial(Serial) == true)
  {
    switch(serialBuffer[0])
    {
    case 'G':
    case 'g':
      {
        Coordinate coord;
        parseCoordinate(serialBuffer + 1, coord);   //+ 1 für ein Zeichen nach dem 'G/g'

        Serial.print("x: "); Serial.println(coord.x);
        Serial.print("y: "); Serial.println(coord.y);
        Serial.print("z: "); Serial.println(coord.z);
        Serial.println();
      }
      break;
    }
  }
}

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;
}

void parseCoordinate(char* str, Coordinate& coord)
{
  coord.x = atoi(strtok(str, ",; "));   //Komma, Strichpunkt oder Leerzeichen als Delimiter
  coord.y = atoi(strtok(NULL, ",; "));
  coord.z = atoi(strtok(NULL, ",; "));
}

Das Kommando wird am ersten Buchstaben erkannt. Dadurch kann man einfach andere Kommandos implementieren. Und die Koordinaten kommen direkt hintereinander ohne zusätzliche Zeichen die die Bedeutung regeln. Dadurch muss man nichts suchen, sondern kann einfach mit strttok() splitten.

Also einfach sowas: “g100,200,300”

Wenn du ganze Wörter als Kommandos willst, musst nur statt switch/case strncmp() verwenden und statt +1 zu machen +n, wobei n die Länge des Kommandos ist.

Wie die Parse-Funktion aufgerufen wird kann man natürlich auch anders schreiben. Geschmackssache. Und das geht eben auch mit der char* receiveBuffer() Funktion von jurs, da diese letztlich das gleiche macht. Nur etwas anders.

Und den Serial Monitor so einstellen dass ein Newline/LF am Ende gesendet wird! Sonst geht es nicht

Hängt davon ab:

  • Wenn bei ‘g’ nichts gemacht werden soll, bei ‘G’ aber schon, hast du recht.
  • Wenn ‘g’ und ‘G’ gleich behandelt werden sollen, ist das fehlendebreak;Absicht

Serenifly:

const int SERIAL_BUFFER_SIZE = 20;

char serialBuffer[SERIAL_BUFFER_SIZE];

struct Coordinate
{
  int x;
  int y;
  int z;
};

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

void loop()
{
  if (readSerial(Serial) == true)
  {
    switch(serialBuffer[0])
    {
    case ‘G’:
    case ‘g’:
      {
        Coordinate coord;
        parseCoordinate(serialBuffer + 1, coord);  //+ 1 für ein Zeichen nach dem ‘G/g’

Serial.print("x: "); Serial.println(coord.x);
        Serial.print("y: "); Serial.println(coord.y);
        Serial.print("z: "); Serial.println(coord.z);
        Serial.println();
      }
      break;
    }
  }
}

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;
}

void parseCoordinate(char* str, Coordinate& coord)
{
  coord.x = atoi(strtok(str, ",; "));  //Komma, Strichpunkt oder Leerzeichen als Delimiter
  coord.y = atoi(strtok(NULL, ",; "));
  coord.z = atoi(strtok(NULL, ",; "));
}

Erstmal vielen Dank für den Sketch, ich konnte diesen soweit anpassen, dass er in meinem Projekt so funktioniert, so wie ich mir das vorgestellt habe.
Eine Frage habe ich noch zur Buffersize: Wie groß kann ich diesen wählen? Ich verwende einen Arduino Mega 2560, dieser hat standardmäßig einen Buffer von 64 Bytes, dh. ich kann die Buffersize in dem Sketch auf max. 64 setzen (1 char = 1 byte) ?

100-200-00: Eine Frage habe ich noch zur Buffersize: Wie groß kann ich diesen wählen?

Du darfst die Größe des dynamischen Speichers für alle Variablen nicht überschreiten, beim Mega2560 sind das 8.192 Bytes. Minimal benötigst Du die Anzahl der übertragenen Zeichen plus Zeilenende.

100-200-00: (1 char = 1 byte) ?

Für ASCII ist ein Zeichen ein Byte. Bei UTF-8 kann ein Zeichen auch durch mehrere Bytes codiert werden.

Eine Frage habe ich noch zur Buffersize: Wie groß kann ich diesen wählen?

Das hängt davon ab wie deine übertragenen Daten aussehen. Der Puffer muss mindestens Platz für den längsten String + 1 haben.

ch verwende einen Arduino Mega 2560, dieser hat standardmäßig einen Buffer von 64 Bytes

Verwechsele nicht den internen Eingangspuffer der Serial Klasse mit diesem Puffer. Das sind zwei verschiedene Sachen. Dieser Puffer kann ruhig größer sein wenn man das wirklich braucht.

Bei meiner Recherche bin ich auf diesen alten Thread gestoßen. Ich habe den Sketch aus Post #2 für eine einfache Dateneingabe zusammengestrichen. Solange die wirkliche Eingabelänge die maximale Zeilenlänge nicht überschreitet, ist die Welt in Ordnung. Übersteigt sie aber die maximale Zeilenlänge besteht das letzte Zeichen aus dem letzten Tastaturanschlag. Hier ein paar Beispiele mit der Zeichenlänge [5]. Mir ist klar, dass das letzte Zeichen NULL ist.

Eingabe             Ausgabe     gewünscht
1234                 1234          okay
12345                1235          1234
123456789            1239          1234

Hier der zusammengestrichene Sketch:

#define ZEILENTRENNZEICHEN 13   // 13 ist Steuerzeichen CR (Carriage Return)

char* text;

char* receiveBuffer()
// Empfang einer Textzeile über Serial
// Rückgabewert NULL: Zeile nicht/unvollständig empfangen
// oder Rückgabewert char-Pointer auf die vollständig empfangene Textzeile
{
  static char lineBuffer[5]; // Maximale Zeilenlänge festlegen
  static byte counter=0;
  char c;
  if (Serial.available()==0) return NULL; // Nullpointer zurück
  if (counter==0) memset(lineBuffer,0,sizeof(lineBuffer));// Puffer vor Benutzung löschen
  c=Serial.read();
  if (c==ZEILENTRENNZEICHEN)
  {
    counter=0;
    return lineBuffer;
  }
  else if (c>=32) // kein Steuerzeichen?
  {
    lineBuffer[counter]=c; // Zeichen im Zeilenpuffer einfügen
    if (counter<sizeof(lineBuffer)-2) counter++;
  }
  return NULL;
}

boolean serialTask(char Daten)
// Rückgabewert false: keine Textzeile empfangen oder nicht alle drei Werte empfangen
// Rückgabewert true: Textzeile wurde empfangen und neue Werte zugewiesen
{
  text=receiveBuffer();
  if (text==NULL) return false;
  return true;
}

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

void loop()
{
  char* Daten;
  char linebuf[5];
  if (serialTask(Daten)) // neue Werte wurden empfangen
  { // Ausgabe formatieren
    Serial.println(text);
  }
}

Wer sieht den Grund? Der letzte Tastaturanschlag liegt irgendwie noch im Puffer und überschreibt den letzten verfügbaren Platz. Ich komme einfach nicht darauf was ich machen kann, dass der Rest einfach abgeschnitten und verworfen wird.

Gruß Eberhard

Schau dir das an:

  else if (c>=32)
  {
    lineBuffer[counter]=c;
    if (counter<sizeof(lineBuffer)-2) counter++;
  }

Die Abfrage ob man das Zeichen abspeichert muss eine Ebene höher. Also vor dem Abspeichern fragen ob noch Platz ist

Siehe auch meinen Code in #13