For schleife zählt dopellt

Hallo,
ich bin Paul und bin gerade dabei ein Projekt für die Schule zu machen.
Meine Idee war eine Abfrage über den Seriellen Monitor zu machen und dementsprechend Text-Dateien auf einer SD-Card zu erstellen. Ich bin soweit dass die Dateien erstellt werden, jedoch hab ich zwei Probleme:

  1. Problem
    Ich möchte den Inhalt der durch Serial.read() ausgelsen wird in einen Integer umwandeln. Ich habe es schon mit atoi, atol und atof probiert aber irgendwie haut es nicht so richtig hin. Habt ihr eine Idee wie ich das lösen kann?

  2. Problem
    Für jedes Zimmer soll es eine eigene Abfrage geben, was ich mit einer for schleife gelöst habe, jedoch zählt diese zweimal also von Zimmer 1 springt es Auf Zimmer 3 dann Zimmer 5 usw.

Ich wäre euch sehr dankbar wenn ihr mir weiter helfen könntet

Lg Paul

Hier der Code:

if(Serial.available() > 0) {
     char Rx = Serial.read();
     char test[] = "12.34";
     String Zimmerzahl = "0";
      if(Rx == '2') {
        int Zahl = atof(test);
      for(int i=0;i<100;i++) {
        Zimmerzahl = String(i+1);
        
        String Zimmer = "Zimmer" + Zimmerzahl;
       
        myFile = SD.open(Zimmer + ".txt", FILE_WRITE);
        myFile.close();
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Wie viele Lampen");
        lcd.setCursor(0, 1);
        lcd.print("hat Zimmer " + Zimmerzahl + " ?");
        delay(100);
        while(!Serial.available());
        char Rx = Serial.read();
        myFile = SD.open(Zimmer + ".txt");
        myFile.println(Rx);
        myFile.close();
      }
      } else {
        Serial.flush();
      }
      }

Sketchfragmente sind immer schlecht, Fehler zu suche.
Also bitte den kompletten Sketch posten.

Und hier

  for(int i=0;i<100;i++) {
        Zimmerzahl = String(i+1);

zählst du doch auch doppelt hoch.

ninxon:

  1. Problem
    Ich möchte den Inhalt der durch Serial.read() ausgelsen wird in einen Integer umwandeln. Ich habe es schon mit atoi, atol und atof probiert aber irgendwie haut es nicht so richtig hin. Habt ihr eine Idee wie ich das lösen kann?

Ich sehe nicht, das Du irgendwo versuchst das gelesene Zeichen in eine Zahl umzuwandeln.

Das hier

    int Zahl = atof(test);

ist Mist.
Du versuchst eine Zeichenkette als Komma behaftete Zahl in einen Integer zu schieben.
Zahl müsste ein float werden, sonst gehen die Nachkommastellen verloren.
Du kannst test auch vom Dezimalpunkt befreien und als Ganzzahl weiterverarbeiten - nur merken, wo . mal stand...

  1. Problem
    Für jedes Zimmer soll es eine eigene Abfrage geben, was ich mit einer for schleife gelöst habe, jedoch zählt diese zweimal also von Zimmer 1 springt es Auf Zimmer 3 dann Zimmer 5 usw.

Du musst zusehen, das Du den Seriellen Puffer leer bekommst, bevor Du weiter machst.
Denn es werden nicht nur "sichtbare" Zeichen übertragen, sondern eben auch das Steuerzeichen.
Das wird bei Serial.available() > 0 mit erkannt.

Im Übrigen ist es ganz schlecht nen Schnipsel hinzuschmeissen und keine Kommentare drin zu haben - das ist reines raten!

War dein Beitragstitel eine Feststellung? Oder ist damit eine Frage verknüpft?Ja, deine FOR-Schleife zählt doppelt, weil du das so drin stehen hast.

for(int i=0;i<100;i++) {
        Zimmerzahl = String(i+1)

Ich verstehe auch warum du nochmal +1 rechnest.
Warum fängst du deine FOR-Schleife nicht bei 1 an zu zählen, dann sparst du dir das +1.
Also:

for(int i=1;i<100;i++) {
        Zimmerzahl = String;

Was immer auch das String zu bedeuten hat. String und Zahl passt irgendwie nicht.

Hallo zusammen,
Danke nochmal für eure schnellen Antworten. Ich habe mir eure Kritik und Ideen zu Herzen genommen und nun nochmal den kompletten Code mit Kommentaren hier eingefügt. Ich möchte als Projekt in der Schule eine Haussteuerung bauen. Ich bin jetzt im Moment dabei die Abfrage zu machen wie viele Zimmer es in diesem Haus gibt und was jeweils in diesem Zimmer vorhanden ist.
Ich habe immer noch das Problem:
Wie ich die Daten aus dem Seriellen Monitor in einen Integer umwandeln kann?
Wie ich den Seriellen Puffer leeren kann?
Warum meine for-Schleife doppelt zählt?

#include <Wire.h>
#include <SD.h>
#include <SPI.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

char Rx = ' ';
int pinCS = 53;
File myFile;

void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  pinMode(pinCS, OUTPUT);
  lcd.setCursor(0, 0);
  lcd.print("Homesystem");
  lcd.setCursor(0, 1);
  lcd.print("by Marco & Paul");
  if (SD.begin()) {    // Überprüfen ob Sd-Card funktioniert
    Serial.println("SD-Card ready!");
  } else {
    Serial.println("SD-Card failed!");
    return;
  }

  //Abfrage für die EInstellungen


  if (SD.exists("SYSTEM.txt")) {  //Abfrage ob System.txt exestiert
    Serial.println("File exestiert bereits");
    return;
  } else {  //Datei nicht da
    lcd.setCursor(0, 0);
    lcd.print("Willkommen!");
    lcd.setCursor(0, 0);
    lcd.print("Loading...");
    Serial.println("File nicht vorhanden!");
    myFile = SD.open("SYSTEM.txt", FILE_WRITE);  //Neue Datei wird erstellt
    myFile.println("Einstellungen: ");
    myFile.close();
    if(SD.exists("SYSTEM.txt")) {   //Erneute Abfrage ob Datei vorhanden ist
      Serial.println("File wurde erstellt!");
      SD.open("SYSTEM.txt");
      myFile.println("Einstellungen: ");
      myFile.close();
      
      //Abfrage der Zimmer

      if(Serial.available() > 0) {
     char Rx = Serial.read();   //Serial wird ausgelesen
     String Zimmerzahl = "0";
        Serial.flush();
        int Zahl = atoi(Rx);   //Rx wird umgewandelt zu Int
      for(int i=1;i<=Zahl;i=i+1) {  //Schleife so oft wie Abfrage
        Zimmerzahl = String(i);   //I wird in String umgewandelt für den Dateinamen
        String Zimmer = "Zimmer" + Zimmerzahl;  //Name für die Datei wird erzeugt
        myFile = SD.open(Zimmer + ".txt", FILE_WRITE);  //Datei wird erstellt
        myFile.close();           //Datei wird geschlossen
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Wie viele Lampen");
        lcd.setCursor(0, 1);
        lcd.print("hat Zimmer " + Zimmerzahl + " ?");
        delay(100);
        Serial.flush();
        while(!Serial.available());  //Warten bis erneute Eingabe
        char Rx = Serial.read();    //Serial wird ausgelesen
        myFile = SD.open(Zimmer + ".txt");  //Die Datei wird geöffnet
        myFile.println(Rx);     //Das ausgelesene wird in die Datei geschrieben
        myFile.close();         //Datei wird geschlossen
      }
      
      }
      
    } else {
      Serial.println("File konnte nicht erstellt werden");
    }
  }



}

void loop() {

     
    
  
    
}

HotSystems:
Sketchfragmente sind immer schlecht, Fehler zu suche.
Also bitte den kompletten Sketch posten.

Und hier

  for(int i=0;i<100;i++) {

Zimmerzahl = String(i+1);




zählst du doch auch doppelt hoch.

Wo genau zähle ich denn Doppelt hoch?

ninxon:
Wo genau zähle ich denn Doppelt hoch?

Einmal in der for-Schleife und dann in der folgenden Variablenübergabe.

Aber in deinem aktuellen Sketch hast du es ja geändert.

HotSystems:
Einmal in der for-Schleife und dann in der folgenden Variablenübergabe.

Bei

Zimmerzahl = String(i+1);

wird aber der Wert von i nicht geändert. Da wird nur der Wert vor der Parameterübergabe eins erhöht. Doppelt hochgezählt wird da nichts.

@ninxon: Was verstehst Du überhaupt unter 'doppelt zählt'? Was wirkt sich da wie aus?

MicroBahner:
Bei

Zimmerzahl = String(i+1);

wird aber der Wert von i nicht geändert. Da wird nur der Wert vor der Parameterübergabe eins erhöht. Doppelt hochgezählt wird da nichts.

@ninxon: Was verstehst Du überhaupt unter 'doppelt zählt'? Was wirkt sich da wie aus?

Erstmal vielen dank für deine Antwort. Nun um auf deine Frage zu kommen das doppelt zählen äußert sich so, dass es nicht abfragt Zimmer1,Zimmer2,Zimmer 3 usw sonder es macht Zimmer2,Zimmer4,Zimmer6 usw
Lg paul

ninxon:
das doppelt zählen äußert sich so, dass es nicht abfragt Zimmer1,Zimmer2,Zimmer 3 usw sonder es macht Zimmer2,Zimmer4,Zimmer6 usw

Weil Du den seriellen Puffer nach der Übertragung nicht leerst!

Dein Serial.flush() macht nicht das, was Du willst.
https://www.arduino.cc/reference/de/language/functions/communication/serial/flush/

Ich habe Dir das ganz oben schon genauso geschrieben!

Hallo,

das Werte ausgelassen werden, davon kann ich nichts feststellen.
Du solltest allerdings bei String die Methode toInt verwenden.

Democode:

void setup(void)
{
  Serial.begin(9600);
  Serial.println(F("\nStart #### #### #### ####"));
  
  for (int i=0; i<11; i++)
  {
    Serial.print("i "); Serial.print(i);  // das ist dein i++ im Schleifenkopf
    Serial.print('\t');
    Serial.print("i+1 "); Serial.println(i+1);
  }  

  Serial.println();
  
  String myString = "13";
  long zimmerNummer = 1;
  
  for (int i=0; i<11; i++)
  {
    Serial.print("i "); Serial.print(i);  // das ist dein i++ im Schleifenkopf
    Serial.print('\t');
    zimmerNummer = i + myString.toInt();
    Serial.print("zimmerNummer "); Serial.println(zimmerNummer);
  } 
}

void loop(void)
{
 
}

Serial.read() machen und auf ein Zeichen abfragen reicht nur für einzelne Zeichen. Also einen Buchstaben oder eine Ziffer von 0-9. Das kann bei deiner Anwendungen auch ausreichen. z:B. wenn deine Zimmer-Nummern nur bis 9 gehen. Dann brauchst du aber kein atoi() o.ä.

atoi() erwartet kein Zeichen sondern ein Null-terminiertes char Array (auch C String genannt. Nicht zu verwechseln mit der Arduino String Klasse). Das hier kann also nicht funktionieren:

char Rx = Serial.read();   //Serial wird ausgelesen

 int Zahl = atoi(Rx);   //Rx wird umgewandelt zu Int

Wenn du die Ziffern 5 eingibst hast du dann eben ‘5’. Um damit etwas als String zu machen muss man nichts konvertieren. Das irgendwie in einen anderen String einzubauen geht direkt. Es ist ja schon ein ASCII Zeichen. Um auf die eigentliche Ziffer 5 zu kommen müsstest du nur ‘0’ subtrahieren (siehe ASCII Tabelle). Das wird hier aber gar nicht unbedingt nötig sein.

Und wenn man mehrere Zeichen hat (z.B. ‘1’ und ‘0’ für “10”) muss man das erst mal in ein Array einlesen. Und dabei das Zeitverhalten der seriellen Schnittstelle berücksichtigen. Also nicht versuchen das nächste Zeichen direkt danach in einer Schleife einzulesen.

Die zwei Fälle musst du unbedingt unterscheiden

Wenn du mehr als eine Ziffer einlesen willst braucht du erst mal eine vernünftige Einlese-Funktion:

const unsigned int READ_BUFFER_SIZE = 11;    //Platz für 10 Zeichen + Terminator

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

void loop()
{
  char* str = readLine(Serial);
  if (str != nullptr)      //ist wahr wenn das LF eingelesen wurde
  {
    Serial.print("Eingelesen: ");
    Serial.println(str);
    Serial.print("Als Integer: ");
    Serial.println(atoi(str));
    Serial.println();
  }
}

char* readLine(Stream& stream)
{
  static byte index;
  static char buffer[READ_BUFFER_SIZE];

  while (stream.available())
  {
    char c = stream.read();

    if (c == '\n')              //wenn LF eingelesen
    {
      buffer[index] = '\0';     //String terminieren
      index = 0;
      return buffer;            //melden dass String fertig eingelesen wurde
    }
    else if (c >= 32 && index < READ_BUFFER_SIZE - 1)   //solange noch Platz im Puffer ist
    {
      buffer[index++] = c;    //Zeichen abspeichern und Index inkrementieren
    }
  }
  return nullptr;                //noch nicht fertig
}

Ein automatisches Linefeed im seriellen Monitor als Endzeichen nehmen. Dann alles bis dahin in ein char Array einlesen. Und erst wenn man das LF hat die Zeichenkette terminieren und dann konvertieren.

Die while()-Schleife bricht in aller Regel nach einem Zeichen ab weil das nächste noch nicht da ist. Deshalb muss man die Funktion ständig in loop() aufrufen und den Rückgabe-Wert auswerten. Das hat auch den Vorteil dass man nebenbei noch andere Dinge tun kann

Die fertige Serial. toInt() Methode geht auch. Dabei sollte man allerdings die Timeout-Zeit deutlich nach unten setzen:
https://www.arduino.cc/reference/en/language/functions/communication/serial/settimeout/
Sonst blockiert der Code ständig eine Sekunde lang auch wenn man gar nichts eingibt

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