PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Serial Daten bei Komma trennen



Sinnloserknopf
07.10.2017, 17:04
Hallo RN,
ich will von einen Arduino A zum anderen Arduino 4 Messwerte übergeben.

Diese kommen so beim Arduino B an: "000,111,222,333". Anzahl der Zeichen zwischen 0 und 3. Aber jeder Messwert ist mit einem Komma getrennt.

Ich will diese nacher möglichst so auswerten können:
Sensor[0] = 000
Sensor[1] = 111
Sensor[2] = 222
Sensor[3] = 333

Bis jetzt hab ich nicht viel mehr geschafft außer das Komma zu finden^^



#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11);

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



void loop() {

if(mySerial.available()) {
char c = mySerial.read();
if(c==',' ) {
Serial.println("komma gefunden");

}
}
}



Kann mir jemand auf die Sprünge helfen :)





Hier geht's... aber ist schmuddelig^^





unsigned long data;
char buffer[40];
int index = 0;
int counter = 0;
int Sensor[4];

void loop() {
//wenn serielle Daten vorhanden, dann einlesen
if(mySerial.available()) {
//einzelnes Zeichen lesen
char c = mySerial.read();

if(c==',' ) {

buffer[index] = 0;

counter++;

index=0;

data = atol(buffer);

Sensor[counter]=data;
if(counter == 4){counter=0;}


} else {

buffer[index++] = c;
}
}

Serial.println(Sensor[1]);
Serial.println(Sensor[2]);
Serial.println(Sensor[3]);
Serial.println(Sensor[4]);
Serial.println();
}

shedepe
07.10.2017, 17:41
Ich verstehe deine Frage nicht ganz. Du hast doch schon eine Lösung ?

Wenn ich die mir anschaue würde ih aber spontan behaupten die funktioniert so nicht.

Mal zur Logik:



Pseudocode:



int index = 0;
char buffer[4];

loop()
{
char c = mySerial.read();
buffer[index] = c;
index++;
if(c == ',')
{
//Buffer verarbeiten
index = 0;
}

}

Klebwax
08.10.2017, 01:29
So, wie du das beschreibst, kannst du das gar nicht zuverlässig dekodieren. Was kommt nach der 333 in deinem Beispiel? Die 000 von der nächsten Messung? Kommt dazwischen auch ein Komma? Wie kannst du entscheiden, welche Zahl die erste deiner vier Messwerte ist?

Ich gehe mal davon aus, daß deine "Zeilen" durch ein Newline getrennt sind. Ich würd also erstmal eine ganze Zeile empfangen. Dazu braucht man einen Buffer mit einer maximalen Länge von 4*3 Ziffern, 3 Kommas und dem abschließenden Null-Byte (für einen C-String), also 16 Zeichen.

Man wartet, bis von der seriellen ein Newline kommt. Ab da füllt man die empfangenen Zeichen in den Buffer, bis ein weiteres Newline kommt. Hier schließt man den Buffer mit einem Nullbyte ab. Jetzt kann man den Buffer mit all den Funktionen, die die Stringlibrary von C so her gibt, bearbeiten. Das Auswerten eines Records, coma separated, ist ja kein neues Problem. strchr() (https://www.tutorialspoint.com/c_standard_library/c_function_strchr.htm) oder strtok() (https://stackoverflow.com/questions/3889992/how-does-strtok-split-the-string-into-tokens-in-c) kommen mir dabei in den Sinn. Wenn man den Record erstmal in seine Felder zerlegt hat, kann man sie z.B. mit atoi() in Integer wandeln.

Testen tut man das Ganze am besten auf dem PC, C-Code ist halt C-Code. Die Debugtools auf dem PC sind mächtiger und es geht viel schneller. Den Inputbuffer kann man leicht mit gets() füllen, das Ergebniss mit printf() ausgeben. Da kann man dann auch leicht verifizieren, wie robust der Code ist, wie er auf verstümmelte oder gestörte Nachrichten reagiert. Wenn man mit dem Ergebnis zufrieden ist, macht man mit dem Arduino weiter.

MfG Klebwax

shedepe
08.10.2017, 10:03
@Klebwax. Wenn eine Zahl immer aus 3 Ziffern besteht ist das ohne weiteres machbar. Dann braucht es kein Newline, man muss es nicht zwischenspeichern sondern nur bis 3 zählen. Die erste Zahl kann man daran erkennen, dass nach 3 Ziffern kein Komma gekommen ist.

Klebwax
08.10.2017, 10:50
@Klebwax. Wenn eine Zahl immer aus 3 Ziffern besteht ist das ohne weiteres machbar. Dann braucht es kein Newline, man muss es nicht zwischenspeichern sondern nur bis 3 zählen. Die erste Zahl kann man daran erkennen, dass nach 3 Ziffern kein Komma gekommen ist.


Anzahl der Zeichen zwischen 0 und 3. Aber jeder Messwert ist mit einem Komma getrennt.

Das Format mit dem Komma entspricht ja dem üblichen csv-Format. Und da gibts, wie eigentlich bei jedem Textformat üblich, einen eindeutigen Zeilentrenner. Es wäre auch nicht schlau, sich auf feste Feldlängen zu verlassen, schon nächste Woche braucht man ein anderes (längeres) Format.

Und warum soll man nicht zwischenspeichern? Den Buffer kann man leicht aus dem Interrupt heraus füllen und die eigentliche Anwendung bleibt responsiv. Außerdem wird man flexibel, ob der Buffer von der seriellen gefüllt wird, aus einem Netzwerkstack kommt oder vom Massenspeicher gelesen wird, ändert an der Dekodierung nichts.

MfG Klebwax

shedepe
08.10.2017, 11:14
Ob es schlau ist oder nicht habe ich nicht gesagt, nur dass es machbar ist. Und da wir uns auf einem Mikrocontroller befinden will man häufig so effizient wie mögich mit seiner Rechenzeit umgehen. Das ist bei komplexeren Datenformaten + den damit komplexeren Parsern nicht unbedingt gegeben.

Aber auch wenn man ein Newline zeichen hat, würde ich nicht hingehen, die Daten zuerst speichern und dann Parsen, sondern on the fly parsen. Stringoperationen sind nämlich nicht wirklich Rechenzeit optimal.

Klebwax
08.10.2017, 13:11
Ob es schlau ist oder nicht habe ich nicht gesagt, nur dass es machbar ist.
Wenn du drauf bestehst, es ist nicht machbar, da ein Feld, wie geschrieben, 0 bis 3 Zeichen lang sein kann.


Und da wir uns auf einem Mikrocontroller befinden will man häufig so effizient wie mögich mit seiner Rechenzeit umgehen. Das ist bei komplexeren Datenformaten + den damit komplexeren Parsern nicht unbedingt gegeben.
Der Code muß so schnell sein, wie nötig und keine bisschen schneller.


Aber auch wenn man ein Newline zeichen hat, würde ich nicht hingehen, die Daten zuerst speichern und dann Parsen, sondern on the fly parsen.
Ich dagegen würde nie einzelne Zeichen abholen sondern einen Buffer im Interrupt füllen. Und erst wenn der Buffer dann geparst ist und nur gültige Werte enthält, würde ich die Daten weiterverabeiten.

Stringoperationen sind nämlich nicht wirklich Rechenzeit optimal.
Na dann sollte man den ganzen C++ Overhead des Arduino über Board werfen. Aber für nicht benutzte Prozessorzyklen gibts kein Geld zurück. Es ist also Unsinn, auf erprobte und tausendfach getestete Libraries zu verzichten. So ein moderner µC hat eine mit dem original IBM-XT vergleichbare oder sogar höhere Rechenleistung. Da wurde kaufmännische Buchhaltung oder Textverarbeitung mit gemacht, nur so zur Einordnung der Rechenleistung. Solange nicht ganz spezielle Gründe dagegen sprechen ( so als Lehrling muß man mal einen Würfel feilen bevor man an die Fräse darf;) ) würd ich immer Funktionen aus der C-Library verwenden. Da muß man zwischen 8-Bit µC, einem 32-Bit µC und dem PC nicht umlernen, ist alles C bzw C++.

MfG Klebwax

HaWe
09.10.2017, 09:22
da die Daten als Text-String im ASCII- bzw. csv-Format per Serial() gesendet und empfangen werden , ist es sinnvoll, die Arduino Serial + String-class Funktionen zu verwenden, zusammen mit einem eindeutigen Trennzeichen, z.B. LineFeed:


char termbyte = '\n';
String ReadBuffer = "";
while ( !Serial.available() );
if ( Serial.available() ) {
ReadBuffer = Serial.readStringUntil(termbyte);
}

Dann muss man den Puffer noch an den Kommas in Einzelstrings ("Tokens") aufteilen und die einzelnen Tokens in echte Zahen umwandeln.

https://www.arduino.cc/en/Reference/Serial
https://www.arduino.cc/en/Reference/StringObject

edit:
alternativ kann man die Daten auch einzeln jeweils bis zum termbyte ',' lesen, dann sofort in eine Zahl umwandeln, und fortsetzen bis das termbyte '\n' ist, damit man wieder eindeutigere Start- und Stoppbedingungen hat, und dann wieder von vorn - ist aber wschl etwas schwieriger zu programmieren mit den Arduino-Methoden.

shedepe
12.10.2017, 16:27
@Klebwax. Sorry. Lese Kompetenz ;)
Über die anderen Punkte kann man sich streiten. Auf einem Desktop würde ich dir sofort recht geben, auf einem Mikrocontroller nicht.

Peter(TOO)
13.10.2017, 22:27
Kennt das Arduino-C kein scanf(); oder sscanf(); ?


sscanf(buffer, "%d,%d,%d,%d", &sensor[0], &sensor[1], &sensor[2], &sensor[3]);

MfG Peter(TOO)

HaWe
14.10.2017, 09:11
Kennt das Arduino-C kein scanf(); oder sscanf(); ?


sscanf(buffer, "%d,%d,%d,%d", &sensor[0], &sensor[1], &sensor[2], &sensor[3]);

MfG Peter(TOO)

prinzipiell schon - aber erstmal müsstest du zeigen, wie dein "buffer" erzeugt wird, und dann - probier's aus!

Mxt
14.10.2017, 11:15
prinzipiell schon - aber erstmal müsstest du zeigen, wie dein "buffer" erzeugt wird, und dann - probier's aus!

Ich habe mir gerade mal erlaubt das hier auf dem Uno zu testen


void setup() {
// put your setup code here, to run once:

Serial.begin(9600);

int a,b,c;
String test = "1 2 3";
sscanf(test.c_str(), "%d %d %d",&a, &b, &c);

Serial.print("a = ");
Serial.println(a);
Serial.print("b = ");
Serial.println(b);
Serial.print("c = ");
Serial.println(c);
}

void loop() {
// put your main code here, to run repeatedly:

}

ergibt auch brav


a = 1
b = 2
c = 3


Nachteil: Der kleine Sketch belegt bereits 4780 Bytes Flash und 228 Bytes RAM.

Normalerweise nehme ich sprintf usw. nur auf dem Teensy. Da gehen aber auch C++ strings und die Konvertierungsfunktionen aus C++14.

HaWe
14.10.2017, 12:41
Ich habe mir gerade mal erlaubt das hier auf dem Uno zu testen


void setup() {
// put your setup code here, to run once:

Serial.begin(9600);

int a,b,c;
String test = "1 2 3";
sscanf(test.c_str(), "%d %d %d",&a, &b, &c);

Serial.print("a = ");
Serial.println(a);
Serial.print("b = ");
Serial.println(b);
Serial.print("c = ");
Serial.println(c);
}

void loop() {
// put your main code here, to run repeatedly:

}

ergibt auch brav


Nachteil: Der kleine Sketch belegt bereits 4780 Bytes Flash und 228 Bytes RAM.

Normalerweise nehme ich sprintf usw. nur auf dem Teensy. Da gehen aber auch C++ strings und die Konvertierungsfunktionen aus C++14.

dass das so funktioniert, ist schon klar, die Frage war, wie der OP seinen buffer string generieren soll (bei dir ist er ja fix und heißt test, also kein kontinuierlicher Serial stream).
Das Konvertieren der Einzel-Tokens zu Zahlen dann wäre das geringere Problem.
Ich hatte dazu ja \n als Trennzeichen der Gruppen vorgeschlagen - dann müsste man in Tokens aufteilen und umwandeln, wie ich ebenfalls bereits schrieb
- wie auch immer man das tun will, entweder über Arduino Funktionen oder meinetwegen auch über sscanf.
Aber ohne eindeutige Gruppen-Trennung wird das kaum zuverlässig funktionieren.

Mxt
14.10.2017, 12:46
Aber ohne eindeutige Gruppen-Trennung wird das kaum zuverlässig funktionieren.
Das stimmt, die Gruppentrennung kann aber auch am Anfang der Daten stehen.

Ich hatte schon mal industrielle Sensoren wo das so aussah:

- Paketanfang mit Steuerzeichen STX (Start of Text oder Start of Transmission, siehe ASCII-Tabelle)
- Zeichen das Pakettyp beschreibt
- Je nach Pakettyp unterschiedlich viele Daten

Wahrscheinlich stammt das noch aus Zeiten wo Speicher sehr knapp war. Sowas kann man in der Tat auch "on the fly" parsen, ohne alle Daten im Arbeitspeicher zu behalten.

HaWe
14.10.2017, 12:49
also warum dann nicht
String buffer=Serial.ReadStringUntil('\n');
und dann den String teilen und umwandeln?

Mxt
14.10.2017, 13:29
Ich bevorzuge eigentlich das Lesen einzelner Zeichen, die ich dann selbst in Array oder string hinzufüge.

+ Man kann da einen Timeout einbauen
+ Falls die Gegenseite mal das \n vergisst, kann man aufhören wenn es zuviel wird (die Teensy Implementierung von readStringUntil hat im Gegensatz zu Arduino eine einstellbare Maximallänge)
+ Man kann auch Zeilenenden wie \r\n beachten
+ Steuerzeichen kann man ignorieren, z.B. Falls da jemand auf der Gegenseite von Hand tippt
+ Spezialprotokolle wie das obige mit STX kann man gut behandeln, einfach erst mit dem Lesen anfangen, wenn man ein Startzeichen gesehen hat

- - - Aktualisiert - - -

Ok, immerhin einen Timeout haben sie bei Arduino


String Stream::readStringUntil(char terminator)
{
String ret;
int c = timedRead();
while (c >= 0 && c != terminator)
{
ret += (char)c;
c = timedRead();
}
return ret;
}


beim Teensy sieht die Funktion so aus


String Stream::readStringUntil(char terminator, size_t max)
{
String str;
size_t length = 0;
while (length < max) {
int c = timedRead();
if (c < 0) {
setReadError();
break; // timeout
}
if (c == 0 || c == terminator) break;
str += (char)c;
length++;
}
return str;
}


Das ist ist ja fast wie bei dem Bug in der Arduino map Funktion ...

HaWe
14.10.2017, 13:30
Ich bevorzuge eigentlich das Lesen einzelner Zeichen, die ich dann selbst in Array oder string hinzufüge.

+ Man kann da einen Timeout einbauen
+ Falls die Gegenseite mal das \n vergisst, kann man aufhören wenn es zuviel wird (die Teensy Implementierung von readStringUntil hat im Gegensatz zu Arduino eine einstellbare Maximallänge)
+ Man kann auch Zeilenenden wie \r\n beachten
+ Steuerzeichen kann man ignorieren, z.B. Falls da jemand auf der Gegenseite von Hand tippt
+ Spezialprotokolle wie das obige mit STX kann man gut behandeln, einfach erst mit dem Lesen anfangen, wenn man ein Startzeichen gesehen hat

man kann vieles tun, auch ein eigenes TCP programmieren, aber hier heißt es doch: KISS, und trotzdem halbwegs sicher!
Problem bei Serial/UART sind Datenübertragungsfehler, und kaum ist mal 1 Trennzeichen falsch übertragen/gelesen, sind die ganzen Daten async.
Also ein definiertes Ende, was auch dann den neuen Start synced!
Also was ist einfacher als

String buffer=Serial.ReadStringUntil('\n');
und dann den String teilen und umwandeln?

Mxt
14.10.2017, 13:55
Das Problem sind eigentlich nicht falsche Endzeichen. Eher Gegenseiten, z.B. ein Raspi, die mal unbedacht einen zu langen Text, z.B. eine Fehlermeldung schicken. Auf einem kleinen Arduino geht dann schnell nichts mehr, weil gelesen wird bis der Speicher voll ist.

HaWe
14.10.2017, 14:18
Das Problem sind eigentlich nicht falsche Endzeichen. Eher Gegenseiten, z.B. ein Raspi, die mal unbedacht einen zu langen Text, z.B. eine Fehlermeldung schicken. Auf einem kleinen Arduino geht dann schnell nichts mehr, weil gelesen wird bis der Speicher voll ist.

ja, oder einfach zu schnell sendet, so dass der Empfänger nicht nachkommt. Ich selber schicke daher immer mindestes 1 ack zurück, bevor neue Daten geschickt werden (handshake).
Aber wenn man die Gegenseite per delays etwas verlangsamt, geht es auch so.

Übrigens:
Transmission Fehler passieren häufig, das merkt man, wenn man checksums einführt. Je nach Bedingungen (UART speed, msg Länge, Kabel oder drahtlos, timeouts, Störfelder) durchaus jede 50.- jede 1000. msg fehlerhaft. Und wenn dabei 1 Trennzeichen verlorengeht und man ohne feste Paket-Grenzen arbeitet, ist spätestens ab dann Schluss mit lustig. Mit Paket-Trennzeichen aber synced es sich anschließend automatisch wieder ganz von selbst.

Daher sehe ich immer noch mein Modell ganz vorn:
String buffer=Serial.readStringUntil('\n');
und dann den String teilen und umwandeln

Peter(TOO)
14.10.2017, 19:56
Eher Gegenseiten, z.B. ein Raspi, die mal unbedacht einen zu langen Text, z.B. eine Fehlermeldung schicken. Auf einem kleinen Arduino geht dann schnell nichts mehr, weil gelesen wird bis der Speicher voll ist.

Dafür gibt es seit ewigen Zeiten Hand-Shake-Protokolle.

Das verbreitetste Software-Protokoll ist XON/XOFF, dies verstehen die meisten Geräte mit RS-232 Schnittstelle und es funktioniert mit einer 3-Draht-Verbindung.

Wenn eine komplette RS-232-Schnittstelle vorhanden ist, kann man auch Hardware-Handshake verwenden.

Die meisten Betriebssysteme lesen die Zeichen per Interrupt in einen Ringbuffer ein. Einige Bytes bevor der Ringbuffer überläuft sendet man ein XOFF. Dadurch darf der Sender noch ein paar weitere Zeichen senden ohne, dass diese verloren gehen. Ist dann wieder genügend Platz im Ringbuffer sendet man ein XON. Die Applikation liest dann seine Daten aus dem Ringbuffer.

Beim Senden mach man es auch so. Die Applikation schreibt in einen Buffer. gesendet wird dann per Interrupt. Der Vorteil des Buffers liegt darin, dass die Applikation direkt weiter arbeiten kann nachdem die Daten in den Buffer geschrieben wurden, zumindest so lange noch Platz im Buffer ist.
Beim direkten Schreiben auf die Hardware, muss die Applikation oft warten, bis das letzte Zeichen gesendet ist. Dies verlansamt dann die Rechenzeit für die Anwendung ganz erheblich, wenn niedrige Baudraten verwendet werden.

Typische Programme berechnen zuerst eine Menge (CPU-Zeit) um dann einige Zeichen (Textzeile) auszugeben. Durch die Verwendung von Interrupts bekommt man eine einfache Art von Multitasking hin. Senden, Empfangen und Berechnen sind dann eigene Tasks, welche parallel ablaufen können.

MfG Peter(TOO)

HaWe
14.10.2017, 20:52
Dafür gibt es seit ewigen Zeiten Hand-Shake-Protokolle.

Das verbreitetste Software-Protokoll ist XON/XOFF, dies verstehen die meisten Geräte mit RS-232 Schnittstelle und es funktioniert mit einer 3-Draht-Verbindung.

Wenn eine komplette RS-232-Schnittstelle vorhanden ist, kann man auch Hardware-Handshake verwenden.

Die meisten Betriebssysteme lesen die Zeichen per Interrupt in einen Ringbuffer ein. Einige Bytes bevor der Ringbuffer überläuft sendet man ein XOFF. Dadurch darf der Sender noch ein paar weitere Zeichen senden ohne, dass diese verloren gehen. Ist dann wieder genügend Platz im Ringbuffer sendet man ein XON. Die Applikation liest dann seine Daten aus dem Ringbuffer.

Beim Senden mach man es auch so. Die Applikation schreibt in einen Buffer. gesendet wird dann per Interrupt. Der Vorteil des Buffers liegt darin, dass die Applikation direkt weiter arbeiten kann nachdem die Daten in den Buffer geschrieben wurden, zumindest so lange noch Platz im Buffer ist.
Beim direkten Schreiben auf die Hardware, muss die Applikation oft warten, bis das letzte Zeichen gesendet ist. Dies verlansamt dann die Rechenzeit für die Anwendung ganz erheblich, wenn niedrige Baudraten verwendet werden.

Typische Programme berechnen zuerst eine Menge (CPU-Zeit) um dann einige Zeichen (Textzeile) auszugeben. Durch die Verwendung von Interrupts bekommt man eine einfache Art von Multitasking hin. Senden, Empfangen und Berechnen sind dann eigene Tasks, welche parallel ablaufen können.

MfG Peter(TOO)
Peter,
statt wieder mal nur Allgemeinplätze und Anekdötchen zu verbreiten: schreib doch lieber nen Arduino-Code hier rein, den der OP wirklich benutzen kann.

Klebwax
15.10.2017, 06:45
schreib doch lieber nen Arduino-Code hier rein, den der OP wirklich benutzen kann.

Ich hatte weiter oben vorgeschlagen, die Zeichen im Interrupt zu empfangen und im Interrupthandler den String zu füllen. Da Arduino nicht meine Baustelle ist, hab ich mal nach "arduino uart receive interrupt" gegoogelt. Dabei ist dann als erster Hit dieses (https://www.arduino.cc/en/Tutorial/SerialEvent) herausgekommen:

/*
Serial Event example

When new serial data arrives, this sketch adds it to a String.
When a newline is received, the loop prints the string and clears it.

A good test for this is to try it with a GPS receiver that sends out
NMEA 0183 sentences.

NOTE: The serialEvent() feature is not available on the Leonardo, Micro, or
other ATmega32U4 based boards.

created 9 May 2011
by Tom Igoe

This example code is in the public domain.

http://www.arduino.cc/en/Tutorial/SerialEvent
*/

String inputString = ""; // a String to hold incoming data
boolean stringComplete = false; // whether the string is complete

void setup() {
// initialize serial:
Serial.begin(9600);
// reserve 200 bytes for the inputString:
inputString.reserve(200);
}

void loop() {
// print the string when a newline arrives:
if (stringComplete) {
Serial.println(inputString);
// clear the string:
inputString = "";
stringComplete = false;
}
}

/*
SerialEvent occurs whenever a new data comes in the hardware serial RX. This
routine is run between each time loop() runs, so using delay inside loop can
delay response. Multiple bytes of data may be available.
*/
void serialEvent() {
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag so the main loop can
// do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}

Mangels eines Arduinos kann ich das nicht testen, es sieht für mich aber ok aus. serialEvent() scheint mir zwar kein wirklicher Interrupthandler zu sein, blockiert aber die Mainloop nicht und hat daher einen ähnlichen Effekt. In der Mainloop kann man, wenn stringComplete true ist, ganz in Ruhe sscanf() oder was auch immer passt einsetzen. Und in serialEvent() kann man sicherstellen, daß der Inputstring nicht durch eine zu lange Zeile überläuft und einen Fehler melden.

MfG Klebwax

Mxt
15.10.2017, 08:00
serialEvent()[/B] scheint mir zwar kein wirklicher Interrupthandler zu sein,
Ich habe keinen Überblick über alle Arduino Modelle, aber bei den meisten gibt es einen internen Interrupthandler, der die seriellen Daten in einen internen Puffer kopiert, solange da Platz ist. Beim Teensy 32 oder 64 Byte pro Schnittstelle, bei den kleineren ists wahrscheinlich weniger.

serialEvent wird zwischen den Läufen von loop() ausgeführt, wenn die Funktion definiert ist.


// SerialEvent functions are weak, so when the user doesn't define them,
// the linker just sets their address to 0 (which is checked below).
...
#if defined(HAVE_HWSERIAL0)
void serialEvent() __attribute__((weak));
...


Das Beispiel zu serialEvent findet sich übrigens in der IDE.

HaWe
15.10.2017, 08:35
die Serial class verwaltet den Serial Puffer , Serial events und Serial timeouts, z.B. bei Serial.readStringUntil(), und sie arbeiten auf AVR, SAM, SAMD, ESP, und sogar Intel Curie und STM (natürlich über verschiedene libs und verschiedene cores).
Es sind also posts sicher nicht so hilfreich für Anfänger, wenn der betreffende Ratgebende seinen Code nicht vorher selber zusammen mit der Arduino IDE auf einem eigenen Arduino testen kann, immerhin ist z.B. die Serial class absolut essentiell.
Da aber viele C/++ Kenner hier sicher einiges zu Arduinisch beitragen könnten, fände ich es durchaus äußerst hilfreich, wenn sie mal 5 EUR für nen Nano oder auch nen nodeMCU investieren würden! 8-)

Mxt
15.10.2017, 08:43
Der Grund dafür

und sie arbeiten auf AVR, SAM, SAMD, ESP, und sogar STM (natürlich über verschiedene libs und verschiedene cores).

liegt darin, dass die Serial class nichts davon selbst tut

verwaltet den Serial Puffer , Serial events und Serial timeouts, z.B. bei Serial.readStringUntil(),

Serial ist nur ein kleines Konstrukt, das verschiedene Dinge zusammenbringt.

So ist z.B. readStringUntil gar nicht aus Serial, sondern aus Stream
https://www.arduino.cc/en/Reference/Stream
Das man es in Serial benutzen kann liegt daran, dass ein Serial objekt auch ein Stream ist, durch C++ Vererbung.

Dass ein Serial Objekt mit dem UART des konkreten Arduino sprechen kann, liegt daran, dass es auch ein HardwareSerial Objekt ist. Und unter diesen HardwareSerial Objekten liegen C, nicht C++, Funktionen aus den entsprechenden Arduino Cores, die gibt es für die verschiedene Controller.

Durch diese Architektur gibt es Dinge wie ESP32 in Arduino, weil die diese Dinge einfach mitbenutzen können, obwohl was anderes drunterliegt. Da gibt es nicht die "Super Arduino Entwickler", die das alles zusammenhalten.

HaWe
15.10.2017, 08:48
aja, aber wie auch immer die Serial Class gestrickt ist, sie ist jedenfalls ausgesprochen komplex, sei es durch ihre Kernfunktionen oder durch die stream class oder was auch immer da außerdem noch drin steckt. Immerhin werden diese Methoden alle unter der Serial Class gelistet, und für den Arduinisch user ist es ja doch egal, ob Kernfunktion oder Vererbung aus stream:
https://www.arduino.cc/en/Reference/Serial