Serial.available() gibt unerwartete Anzahl zurück

Hallo, ich bin auf ein merkwürdiges Verhalten von Serial.available() gestoßen: Mal gibt es nur 1 oder 0 zurück, mal gibt es die Anzahl der noch aus dem RX-Buffer zu lesenden Zeichen zurück. Mein Code läuft trotzdem einwandfrei, aber mich interessiert, warum das so ist.
Im Beispiel-Code ist eigentlich nur das Einlesen interessant, aber ich poste das Ausgeben der Vollständigkeit halber auch.

//#########################################################################################################################
//             Code 24 (getestet: ok mit while(anz1... > 0) ) Mit if(anz0... > 0) ist es not ok.
//       Verhalten von Serial.available();   Benutzung des seriellen Monitors für Eingabe und Ausgabe
//#########################################################################################################################

const int ArrayLen = 61;
char Array_char[ArrayLen];    // char-Zwischen-Array
int Array_int[ArrayLen];      // int-Zwischen-Array
char myChar;                  // seriell gelesenes Zeichen
int myChar_int;               // int-Version des seriell gelesenen Zeichens
int anz1_noch_available = 0;  // Anzahl der noch zu lesenden Zeichen im RX-Buffer
int anz2_noch_available = 0;  // Anzahl der noch zu lesenden Zeichen im RX-Buffer
int i = 0, n = 0;             // Zähler
boolean ausgeben = false;     // Ausgabe der eingelesenen Daten starten bei "= true"

void setup() {
  Serial.begin(9600);
  delay(1000);
  Serial.println(F("\nAnfang ..."));
}

void loop() {
  readSerial();
}

void readSerial()  // die seriell eingegeben Daten lesen, zwischenspeichern und im seriellen Monitor ausgeben
{
  ausgeben = false;
  i = 0;
  while (anz1_noch_available = Serial.available() > 0)  // anz1 ist stets entweder 0 oder 1 !
  {
    Serial.print("anz1=");
    Serial.print(anz1_noch_available);
    Serial.print("|  ");
    myChar = Serial.read();
    delay(100);  // delay() muss sein, sonst ist anz2 stets = 0 und ausgeben ist nie true !
    Array_char[i] = myChar;
    myChar_int = myChar;
    Array_int[i] = myChar_int;
    i++;
    anz2_noch_available = Serial.available();  // anz2 ist die Anzahl der noch zu lesenden Zeichen im RX-Buffer !
    Serial.print("anz2=");
    Serial.print(anz2_noch_available);
    Serial.print("|  ");
    if (myChar_int == 13 || myChar_int == 10)
      ausgeben = true;
  }  // Ende von while (anz1_noch_available = Serial.available() > 0)

  if (ausgeben) {
    Serial.println("X");  // zeigt an, dass das Einlesen in die beiden Zwischen-Arrays beendet ist.
    Serial.print("eingegeben wurde: ");
    i = 0;
    while (Array_int[i] != 13 && Array_int[i] != 10) {  // kein Ende-Kennzeichen gelesen
      Serial.print(Array_char[i]);                      // ein Byte als char ausgeben
      Serial.print("(");
      Serial.print(Array_int[i]);  // das char-Byte als int ausgeben
      Serial.print(")  ");
      i++;
    }
    Serial.println("Y");  // zeigt an, dass ein Durchlauf von readSerieal() beendet ist
  }                       // Ende von if(ausgeben)
}  // Ende von void readSerial()
Eingabe z.B.: 
123
Ausgabe dazu: 
Anfang ...
anz1=1|  anz2=4|  anz1=1|  anz2=3|  anz1=1|  anz2=2|  anz1=1|  anz2=1|  anz1=1|  anz2=0|  X
eingegeben wurde: 1(49)  2(50)  3(51)  Y

Es gibt ja viele Posts zu Serial.available(), aber diese Merkwürdigkeit habe ich noch nirgends gesehen.
Ich würde mich über einen Hinweis freuen, am besten, wo ich ich eine tiefer gehende Erklärung zu Serial.available() finde.
Wie stellt die Funktion fest, wie viele Zeichen noch im RX-Buffer sind? Durch Suche nach CR oder NL?
Wie werden die Zeichen in den RX-Buffer geschrieben: von Index Null immer weiter nach hinten oder umgekehrt?
Wie werden Zeichen in den RX-Buffer geschrieben, wenn der Buffer nicht leer ist?
Viele Grüße und schonmal ein Danke für die Mühe.
B-D

anz1_noch_available = Serial.available() > 0

ist der Übeltäter. Schau mal nach "operator precedence" in C++ und überlege, in welcher Reihenfolge der Ausdruck ausgewertet wird.

Ansonsten liest available() die Anzahl der Bytes im zugehörigen UART-Puffer aus - keine Zauberei.

1 Like

Es gibt immer "die Anzahl der noch aus dem RX-Buffer zu lesenden Zeichen zurück".
Immer.

Du hast ja schon zwei Tipps erhalten.

An deiner Stelle würde ich das Einlesen komplett umbauen.
Arbeite das Tutorial durch:

Da wirst du fündig wie du verlässlich von der seriellen Schnittstelle einliest.

Hallo Miq1,
herzlichen Dank für Deinen Hinweis auf die Auswertungsreihenfolge. Dadurch ist mir aufgegangen, dass der Compiler von rechts nach links auswertet, also nicht wie ein Mensch, der ja von links nach rechts liest. In anz1_noch_available = Serial.available() > 0 wird also erst festgestellt, ob true oder false, und danach wird dieses Ergebnis in integer umgerechnet, also in 1 oder 0 verwandelt.
Also nochmal vielen Dank, dass Du meinen Denkfehler aufgedeckt hast.
B-D

Hallo combie,
vielen Dank für Deinen Hinweis auf HardwareSerial.cpp; ich habe mir die Datei angeschaut. Leider reichen meine C-Kenntnisse aktuell nicht aus, um alles genau zu verstehen, ich kann vieles nur so ungefähr nachvollziehen. Z.B. fehlen mir Kenntnisse über das bitweise Verschieben. Es wird also noch geraume Zeit dauern, bis ich mich ganz durch die Datei "gekämpft" haben werde. Auch über die beiden Doppelpunkte in z.B. HardwareSerial::available(void) muss ich mich noch informieren.
Nichtsdestotrotz nochmal vielen Dank für Deine Anregung.

Hallo noiasca,
ich danke Dir für den Link zum Tutorial "Serial Input Basics". Weil dieses tolle Tutorial sehr ausführlich (das ist gut!) ist, werde ich noch eine Weile brauchen zum Durcharbeiten. Aber ich werde, und zwar bis zum Ende!
Ich war leider nicht auf die Idee gekommen, im Such-Fenster nach "Tutorial" zu suchen. Hätte aber in meinem Fall auch nichts gebracht, weil die Tutorials immer an eine Kategorie angehängt sind. Besser wäre m.E., eine eigene Kategorie "Tutorial" zu erstellen mit Links zu allen Tutorials und mit Anzeige der jeweiligen Überschrift.
Nochmal vielen Dank für den Hinweis. Ich finde es toll, dass im Arduino-Forum so viele Menschen in ihrer Freizeit anderen Menschen helfen, danke!

Sie wünschen wir spielen:

Latest Using Arduino/Introductory Tutorials topics - Arduino Forum

Gaaanz so einfach ist es nicht, links-nach-rechts gilt nur bei Operatoren gleichen Ranges. In dieser Tabelle kannst du sehen, dass der Vergleichsoperator einen höheren Rang als die Zuweisung hat. Es wird also zuerst geprüft, ob available() etwas größer als 0 zurückliefert, und das logische Ergebnis wird dann in den Datentyp deiner Variablen konvertiert und dann erst erfolgt die Zuweisung.

3 Likes

Hallo Miq1,
vielen Dank für den Hinweis auf die Ausführungsreihenfolge bei Operatoren. Die Tabelle werde ich nicht auswendig lernen, aber dort nachschauen, falls ich nochmal eine Kette von Befehlen programmiere.
Weil ich mir vom Compiler nicht vorschreiben lassen wollte, in welcher Reihenfolge er die Operatoren (<, xyz(), Umwandlung) bearbeitet, habe ich ihn mittels "()" gezwungen, als erstes "(anz1...=Serial.available() )" auszuführen und erst danach "Serial.available()>0". Hat geklappt: anz1... wird dann mit der Anzahl der noch im RX-Buffer befindlichen Zeichen angezeigt anstatt mit 1 oder 0.
Viele Grüße und herzlichen Dank von b-d.

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