Probleme mit dem seriellen Lesen

Hallo Forengemeinde,

ich möchte von einem Anzeigegerät einen Wert auslesen und diesen dann
weiter verarbeiten.

Dazu ein Auszug aus meinem sketch:

void setup() {
  // Inerruptroutine für pin 2 , funktion ereignistaster wird aufgerufen bei steigender flanke
  attachInterrupt(0, ereignisTaster, RISING);

  // initialize serial port:
  Serial.begin(9600, SERIAL_8N1);
  Serial1.begin(9600, SERIAL_8N1);
}


void loop() {
  if (tasterState) {

    // Istwert ausgeben (Befehl ans das Anzeigegerät)
    Serial1.write(escInt);
    Serial1.write(aInt);
    Serial1.write(nullInt);
    Serial1.write(zweiInt);
    Serial1.write(nullInt);
    Serial1.write(nullInt);
    Serial1.write(crInt);
    Serial1.write(lfInt);
    delay(100);

    // Istwert ausgeben (Befehl ans das Anzeigegerät)
    Serial1.write(escInt);
    Serial1.write(aInt);
    Serial1.write(nullInt);
    Serial1.write(zweiInt);
    Serial1.write(nullInt);
    Serial1.write(nullInt);
    Serial1.write(crInt);
    Serial1.write(lfInt);

    index = 0;
    inByte = 0;

    while (Serial1.available()) // Don't read unless
      // there you know there is data
    {
      if (index < 13){
        inByte = Serial1.read(); // Read a character
      inIstwert[index] = inByte; // Store it
      index++; // Increment where to write next
      Serial.println("schreibe");
      }
      else break;
    }


    Serial.println("Das habe ich empfangen: ");
    for (int i = 0; i < 13; i++) {
      Serial.print(inIstwert[i]);
      Serial.print(", ");
    }
    Serial.println("");

    tasterState = LOW;
  }
}




void ereignisTaster() {

   // Taster Entprellung - es kann nur 1 mal in der Sekunde der Interrupt ausgeführt werden
  if((millis() - alteZeit) > entprellZeit) { 
    // innerhalb der entprellZeit nichts machen
    tasterState = HIGH;
    alteZeit = millis(); // letzte Schaltzeit merken      
  } 
}

Nun habe ich aber das Problem, dass wenn ich den Istwert am Anzeigegerät
ändere und ihn dann erneut abfragen möchte, der Arduino diesen nicht bei
der ersten Abfrage erkennt.
Dazu ein kurzes Beispiel:

Der Wert auf der Anzeige beträgt 10,000.
Frage ich den Wert nun mittels Tastendruck ab so erhalte ich auf dem
seriellen Monitor:

schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
Das habe ich empfangen:
2, 43, 48, 48, 48, 48, 49, 48, 48, 48, 48, 13, 10,

Änder ich nun den Istwert am Anzeigegerät auf 99,999 so erhalte ich den
korrekten Wert leider erst bei der zweiten Abfrage:

schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
Das habe ich empfangen:
2, 43, 48, 48, 48, 48, 49, 48, 48, 48, 48, 13, 10, <--Wert geändert
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
Das habe ich empfangen:
2, 43, 48, 48, 48, 48, 49, 48, 48, 48, 48, 13, 10, <--erste Abfrage
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
schreibe
Das habe ich empfangen:
2, 43, 48, 48, 48, 48, 57, 57, 57, 57, 57, 13, 10, <--zweite Abfrage

Es kommt auch vor, dass ich den "richtigen" Wert erst nach der dritten
oder vierten Abfrage erhalte.
Ich kann mir dieses "Fehlverhalten" leider nicht erklären. Ich hoffe
mein Problem ist verständlich und es kann mir jemand weiterhelfen.

Freundliche Grüße
Markus

Lies und dokumentiere doch mal alles was du empfängst, und nicht nur die ersten 13 Zeichen.

Musst es ja nicht unbedingt in deinem int array (?, Variablendefinition sind das wichtigste an einem Sketch) speichern.

   while (Serial1.available()) // Don't read unless
      // there you know there is data
   {
      Serial.print(index+1);
      Serial.print(". Byte gelesen : ");
      int  inByte = Serial1.read(); // Read a character
      Serial.print(inByte);

      if (index < 13){
      inIstwert[index] = inByte; // Store it
      index++; // Increment where to write next
      Serial.println(" gespeichert");
      } else
      Serial.println (" (verworfen)");
   }

Serial ist langsam. Bei 9600 Baud brauchst du 1 / 9600 * 10 Sekunden pro Zeichen. Das ist ca. 1ms. Direkt nach dem Abschicken eines Kommandos gleich die Antwort einzulesen ist vielleicht keine so gute Idee

Direkt nach dem Abschicken eines Kommandos gleich die Antwort einzulesen ist vielleicht keine so gute Idee

Eine gute Idee ist, wenn noch keine ganze Antwort da ist, es einfach in den nächsten Zyklen weiter zu versuchen...

Also die Sendegeschichte unabhängig vom Einlesen

if(TasterState) {  
   senden();
   TasterState = LOW;
}
empfangen();

Ein schönerer Variablen-Name als TasterState wäre übrigens

volatile bool TasterNeu;  // wird in ISR gesetzt ( max. 1 mal je sekunde ) und in loop zurückgesetzt

Zunächst mal vielen Dank für eure Tipps!

Serenifly:
Serial ist langsam. Bei 9600 Baud brauchst du 1 / 9600 * 10 Sekunden pro Zeichen. Das ist ca. 1ms. Direkt nach dem Abschicken eines Kommandos gleich die Antwort einzulesen ist vielleicht keine so gute Idee

Danke nochmal für den Hinweis! Daran hatte ich wohl einfach nicht gedacht. Ich hatte den Befehl zur Ausgabe des Istwertes zunächst 2mal hintereinander geschickt, weil ich sonst beim ersten Lesen NICHTS eingelesen hatte. Mit einer entsprechenden Wartezeit dazwischen ist dieses Problem gelöst und ich brauch den Befehl nur noch einmal zu senden. :slight_smile:

michael_x:
Lies und dokumentiere doch mal alles was du empfängst, und nicht nur die ersten 13 Zeichen.

Das habe ich gemacht und dabei folgendes Ergebnis mit deinem Sketch erhalten:

// erste abfrage (Wert = 22.222)

  1. Byte gelesen : 2 gespeichert
  2. Byte gelesen : 43 gespeichert
  3. Byte gelesen : 48 gespeichert
  4. Byte gelesen : 48 gespeichert
  5. Byte gelesen : 48 gespeichert
  6. Byte gelesen : 48 gespeichert
  7. Byte gelesen : 50 gespeichert
  8. Byte gelesen : 50 gespeichert
  9. Byte gelesen : 50 gespeichert
  10. Byte gelesen : 50 gespeichert
  11. Byte gelesen : 50 gespeichert
  12. Byte gelesen : 13 gespeichert
  13. Byte gelesen : 10 gespeichert
    // erste abfrage nach neuem wert
    // wert (11.111)
  14. Byte gelesen : 2 gespeichert
  15. Byte gelesen : 43 gespeichert
  16. Byte gelesen : 48 gespeichert
  17. Byte gelesen : 48 gespeichert
  18. Byte gelesen : 48 gespeichert
  19. Byte gelesen : 48 gespeichert
  20. Byte gelesen : 49 gespeichert
  21. Byte gelesen : 49 gespeichert
  22. Byte gelesen : 49 gespeichert
  23. Byte gelesen : 49 gespeichert
  24. Byte gelesen : 49 gespeichert
  25. Byte gelesen : 13 gespeichert
  26. Byte gelesen : 10 gespeichert

Ich hatte mich beim einlesen auf diese 13 Bytes beschränkt weil wirklich nur diese gesendet werden. Dies hatte ich zuvor auch schon mit einem Oszi überprüft. :slight_smile:
Ich weiß noch nicht genau warum aber mit deinem "Einlese-Algorithmus" funktioniert es eindeutig besser!

michael_x:
Musst es ja nicht unbedingt in deinem int array (?, Variablendefinition sind das wichtigste an einem Sketch) speichern.

Die Vorgehensweise mit dieser Anzeige soll so sein, dass ich den aktuellen Wert abspeicher, ein paar Parameter der Anzeige änder und anschließend den Wert wieder in die Anzeige schiebe. Daher empfand ich es als sinnvoll mir die Werte in einem Byte-Array abzulegen um ausgewählte Werte wieder senden zu können. Fällt dir dazu ein geeignetere Datenstruktur ein?

michael_x:
Eine gute Idee ist, wenn noch keine ganze Antwort da ist, es einfach in den nächsten Zyklen weiter zu versuchen...

Also die Sendegeschichte unabhängig vom Einlesen

if(TasterState) {  

senden();
  TasterState = LOW;
}
empfangen();

Ich hab das mal ausprobiert und es funktioniert prima! Für mein weiteres Vorgehen wird das allerdings nicht gehen, da ich, wenn der Taster einmal gedrückt wird, mehrfach senden und lesen muss. Dabei sind die eingelesenen Daten ausschlaggebend für die weitere Vorgehensweise. Zum Beispiel: Lesen - wo stehe ich im Moment im Menü?, Schreiben - Daraus ergibt sich die weitere Navigation durch das Menü.

Hier nochmal der aktuelle Code der einmaligen Lesen und Schreibens mit Variablendeklaration;) :

int aInt = 65;
int fInt = 70;
int sInt = 83;
int tInt = 84;

int nullInt = 48;
int einsInt = 49;
int zweiInt = 50;
int dreiInt = 51;
int vierInt = 52;
int fuenfInt = 53;
int sechsInt = 54;
int siebenInt = 55;
int achtInt = 56;
int neunInt = 57;


// Kommunikation

int escInt = 27;
int crInt = 13;
int lfInt = 10;

// Hilfsvariablen

volatile bool tasterNeu;  // wird in ISR gesetzt ( max. 1 mal je sekunde ) und in loop zurückgesetzt
int delaytime = 100;

byte inIstwert[100]; // Allocate some space for the string
byte inByte; // Where to store the character read
byte index = 0; // Index into array; where to store the character

volatile unsigned long alteZeit = 0, entprellZeit = 1000;

void setup() {
  // Inerruptroutine für pin 2 , funktion ereignistaster wird aufgerufen bei steigender flanke
  attachInterrupt(0, ereignisTaster, RISING);

  // initialize serial port:
  Serial.begin(57600, SERIAL_8N1);
  Serial1.begin(57600, SERIAL_8N1);
}


void loop() {
  if (tasterNeu) {

    // Istwert ausgeben
    Serial1.write(escInt);
    Serial1.write(aInt);
    Serial1.write(nullInt);
    Serial1.write(zweiInt);
    Serial1.write(nullInt);
    Serial1.write(nullInt);
    Serial1.write(crInt);
    Serial1.write(lfInt);
    delay(delaytime);

    tasterNeu = LOW;
  }

  
  index = 0;
  inByte = 0;


  while (Serial1.available()) // Don't read unless
    // there you know there is data
  {
    Serial.print(index + 1);
    Serial.print(". Byte gelesen : ");
    int  inByte = Serial1.read(); // Read a character
    Serial.print(inByte);

    if (index < 13) {
      inIstwert[index] = inByte; // Store it
      index++; // Increment where to write next
      Serial.println(" gespeichert");
    } else
      Serial.println (" (verworfen)");
  }
}




void ereignisTaster() {

  // Taster Entprellung - es kann nur 1 mal in der Sekunde der Interrupt ausgeführt werden
  if ((millis() - alteZeit) > entprellZeit) {
    // innerhalb der entprellZeit nichts machen
    tasterNeu = HIGH;
    alteZeit = millis(); // letzte Schaltzeit merken
  }
}

Vielen Dank euch beiden für die Hilfe! Mein Eingangsproblem wurde damit gelöst. :slight_smile:

Freundliche Grüße
Markus