Unerwartetes Verhalten bei For-Schleife

Hallo zusammen ich habe Folgendes Problem:

Ich habe habe in loop eine einen Kleinen Jobverteiler, des nach unterschielichen Zeiten diverse Funktionen aufrufen soll.

void loop() {
  now = millis();
  /*Aufgaben die im Normalen Zyklus abgearbeitet werden*/
  if (now > lastNormalCycle + (Zyklus1 * 1000)) {
    lastNormalCycle = now;

    printBME280Data(&Serial);
    Serial.println("Zylus Datenlesen");

    Zyklus1 = NormalZyklus;
  }

  /*Zyklus in dem die Temperaturanzeige aktuallisiert wird*/
  if (now > lastAnzeigeCycle + (Zyklus2 * 1000)) {
    lastAnzeigeCycle = now;

    DatenAnzeigen();
    Serial.println("Zylus Datenanzeige");

    Zyklus2 = AnzeigeZyklus;
  }
  /*Zyklus in dem das Array für den Graphen aktualisiert wird*/
  if (now > lastArrayCycle + (5 * 1000)) {
    lastArrayCycle = now;

    //WriteArray();
    Serial.println("Zylus Array");
    
    Zyklus3 = ArrayZyklus;
  }
}

Das Funktioniert auch Wunderbar wie man an der Seriellen Ausgabe sieht:

21:50:18.486 -> Zylus Datenlesen
21:50:18.486 -> Zylus Datenanzeige
21:50:18.738 -> Zylus Array
21:50:20.473 -> Temp: 19.40°C		Humidity: 58.43% RH		Pressure: 996.25hPa
21:50:20.473 -> Zylus Datenlesen
21:50:22.477 -> Temp: 19.40°C		Humidity: 58.44% RH		Pressure: 996.23hPa
21:50:22.477 -> Zylus Datenlesen
21:50:23.749 -> Zylus Array
21:50:24.483 -> Temp: 19.41°C		Humidity: 58.43% RH		Pressure: 996.27hPa
21:50:24.483 -> Zylus Datenlesen
21:50:26.494 -> Temp: 19.41°C		Humidity: 58.43% RH		Pressure: 996.21hPa
21:50:26.494 -> Zylus Datenlesen
21:50:28.513 -> Temp: 19.40°C		Humidity: 58.42% RH		Pressure: 996.26hPa
21:50:28.513 -> Zylus Datenlesen
21:50:28.746 -> Zylus Array
21:50:30.480 -> Temp: 19.41°C		Humidity: 58.43% RH		Pressure: 996.21hPa
21:50:30.480 -> Zylus Datenlesen
21:50:32.512 -> Temp: 19.41°C		Humidity: 58.43% RH		Pressure: 996.25hPa
21:50:32.512 -> Zylus Datenlesen
21:50:33.725 -> Zylus Array
21:50:34.497 -> Temp: 19.41°C		Humidity: 58.41% RH		Pressure: 996.19hPa
21:50:34.497 -> Zylus Datenlesen
21:50:36.521 -> Temp: 19.41°C		Humidity: 58.38% RH		Pressure: 996.17hPa
21:50:36.521 -> Zylus Datenlesen
21:50:38.497 -> Zylus Datenanzeige

Wenn ich jetzt die Funktion WriteArray() mit dazu neheme, dann wird diese Ständig ausgeführt ohne auf das Ablaufen der zeit zu warten.

void WriteArray() {

  Serial.println ("Array FiFo für Graph wird geschrieben");
  Serial.print ("Startzeit: ");
  Serial.println (millis());

  for (int i = 240; i >= 1; i--) {
    tempArray[i] = tempArray[i - 1];
    Serial.print (i);
    Serial.print ( "-" );
    Serial.println ( tempArray[i]);
  }
  tempArray[0] = temp;
  Serial.print ("Aktuelle Temp für Array: ");
  Serial.println (tempArray[0]);

  Serial.print ("Endzeit: ");
  Serial.println (millis());
  delay(200);
}

Hier das ergebniss der Seriellen ausgabe, es ist lediglich die Funktion WriteArray einkomentiert.

21:53:11.832 -> Zylus Datenlesen
21:53:11.832 -> Zylus Datenanzeige
21:53:12.092 -> Array FiFo für Graph wird geschrieben
21:53:12.092 -> Startzeit: 5001
21:53:12.092 -> 240-0.00
...
21:53:12.284 -> 2-0.00
21:53:12.284 -> 1-0.00
21:53:12.284 -> Aktuelle Temp für Array: 19.44
21:53:12.284 -> Endzeit: 5197
21:53:12.509 -> Zylus Array
21:53:12.509 -> Array FiFo für Graph wird geschrieben
21:53:12.509 -> Startzeit: 5397
21:53:12.509 -> 240-0.00
...
21:53:12.697 -> 2-0.00
21:53:12.697 -> 1-19.44
21:53:12.697 -> Aktuelle Temp für Array: 19.44
21:53:12.697 -> Endzeit: 5595
21:53:12.877 -> Zylus Array
21:53:12.877 -> Array FiFo für Graph wird geschrieben
21:53:12.877 -> Startzeit: 5795
21:53:12.877 -> 240-0.00
...
21:53:13.121 -> 2-19.44
21:53:13.121 -> 1-19.44
21:53:13.121 -> Aktuelle Temp für Array: 19.44
21:53:13.121 -> Endzeit: 5993
21:53:13.306 -> Zylus Array
21:53:13.306 -> Array FiFo für Graph wird geschrieben
21:53:13.306 -> Startzeit: 6193
21:53:13.306 -> 240-0.00
....
21:53:13.494 -> 2-19.44
21:53:13.494 -> 1-19.44
21:53:13.494 -> Aktuelle Temp für Array: 19.44
21:53:13.494 -> Endzeit: 6391
21:53:13.703 -> Zylus Array
21:53:13.703 -> Array FiFo für Graph wird geschrieben
21:53:13.703 -> Startzeit: 6591
21:53:13.703 -> 240-0.00
....
21:53:13.893 -> 2-19.44
21:53:13.893 -> 1-19.44
21:53:13.893 -> Aktuelle Temp für Array: 19.44
21:53:13.893 -> Endzeit: 6789
21:53:14.109 -> Zylus Array
21:53:14.109 -> Temp: 19.43°C		Humidity: 58.44% RH		Pressure: 996.20hPa
21:53:14.109 -> Zylus Datenlesen
21:53:14.109 -> Array FiFo für Graph wird geschrieben
21:53:14.109 -> Startzeit: 6991
21:53:14.109 -> 240-0.00
....
21:53:14.296 -> 2-19.44
21:53:14.296 -> 1-19.44
21:53:14.296 -> Aktuelle Temp für Array: 19.43
21:53:14.296 -> Endzeit: 7195
21:53:14.471 -> Zylus Array
21:53:14.471 -> Array FiFo für Graph wird geschrieben
21:53:14.520 -> Startzeit: 7395
21:53:14.520 -> 240-0.00
....
21:53:14.712 -> 2-19.44
21:53:14.712 -> 1-19.43
21:53:14.712 -> Aktuelle Temp für Array: 19.43
21:53:14.712 -> Endzeit: 7593
21:53:14.879 -> Zylus Array
21:53:14.879 -> Array FiFo für Graph wird geschrieben
21:53:14.879 -> Startzeit: 7793
21:53:14.879 -> 240-0.00

21:53:15.071 -> 2-19.43
21:53:15.111 -> 1-19.43
21:53:15.111 -> Aktuelle Temp für Array: 19.43
21:53:15.111 -> Endzeit: 7991
21:53:15.291 -> Zylus Array
21:53:15.291 -> Array FiFo für Graph wird geschrieben
21:53:15.291 -> Startzeit: 8191
21:53:15.291 -> 240-0.00
....
21:53:15.492 -> 2-19.43
21:53:15.492 -> 1-19.43
21:53:15.492 -> Aktuelle Temp für Array: 19.43
21:53:15.492 -> Endzeit: 8389
21:53:15.664 -> Zylus Array
21:53:15.698 -> Array FiFo für Graph wird geschrieben
21:53:15.698 -> Startzeit: 8590

Dabei ist die Funktion WriteArray() eigentlich nur eine Forschleife die einen Ringpuffer beschreibt.
Woran kann das denn liegen?

Dein Code ist bis zur Untestbarkeit verstümmelt.
Zudem verwendest du eine Addition bei der Zeit Berechnung.

Touch_BME280_V0.2.zip (33.9 KB)

Hier der Kompette Code.

Aber in anderen Projekten und ohne die For-Schleife geht es ja auch.
nur mit der Forschleife geht es nicht.

Vielleicht noch eine info zur Hardware:

  • AZ-Touch 2,4"
  • ESP 32
  • BME280

WriteArray braucht 200 ms (delay) sowie eine unbestimmte Zeit zum Schreiben, da es mehr als 64 Zeichen ausgibt. Das ist schonmal ein Unterschied.

Ausserdem kann man viele mögliche Fehler nicht erkennen, da der wichtigste Teil des Sketches (Variablendefinitionen) fehlt.

Das komplette Programm hochgeladen.
siehe den Post davor.

Dann sind die anderen Projekte genauso kaputt, ohne dass du es bisher bemerkt hast.

Die Addition habe ich ja schon genannt.
Dann rechnest du mit Vorzeichen behafteten Zahlen, trotz möglichem Überlauf. Das mündet in ein undefiniertes Verhalten.

Was soll die For Schleife überhaupt tun?
Das sieht wie das rum kopieren eines Ringbuffers aus.

Dann greifst du in der Schleife über die Arraygrenzen hinweg!
Auch "undefined Behavior"

Genau die For-Schleife soll ein Ringpuffer sein.

sorry aber ich versteh jetzt nicht wo ich das problem in der For-Schleife sein soll?

meinst du ```
tempArray[i] = tempArray[i - 1];


aber da kopiere ich doch nur die vorige stelle des array in die aktelle position. 

oder meinst du 
`(now > lastArrayCycle + (5 * 1000)`

Der Vorteil von RingPuffern ist ja gerade, dass man "NICHT" kopieren muss. Dafür wurden sie erfunden. Das ist ihr Daseinszweck.

tempArray[i] = tempArray[i - 1];

Der größte erlaubte Index ist 239 und du schreibst ganz Stumpf erstmal in die Zelle 240 welche überhaupt nicht existiert.

Ja, auch, da stecken gleich 2 satte Fehler drin!
Der Vorzeichenbehaftete Überlauf bei der Addition
Und der nicht kompensierte Millis Überlauf.

Hallo,

Mir ist auch nicht ganz klar, was genau das "seltsame Verhalten" ist.
Wie schon von anderen angemerkt, gibt es ein paar Punkte die Du vielleicht mal prüfen kannst:

  1. Serial.print zum debugging benötigt auch seine Zeit. Wie hast du die Baudrate in Serial.begin() eingestellt? Versuch mal alle Serial.print/Serial.println Aufrufe aus deiner writeArray-funktion auszukommentieren, und schau nach ob das timing dann besser wird.

  2. Wenn du das array als tempArray[240] definiert hast, sind nur [0] bis [239] als index erlaubt. Leider kann C dich nicht daran hindern, auch ausserhalb der array-Grenzen zu schreiben, damit wird dann meistens irgendetwas anderes überschrieben. --> Pack mal testweise zwei mehr Elemente ins array, also tempArray[242].
    --> oder (auch nur testweise) vor den array-zugriff folgendes einbauen: "if ((i<1) || (i>239)) Serial.println("upps");"

  3. Dein "ringbuffer" array ist leider kein echter ring-buffer - du schaufelst ja bei jedem Aufruf alle Elemente des arrays durch die Gegend.

  4. millis() hat den Typ "unsigned long", das sind beim AVR 32bit. Dieser Wert läuft irgendwann über, und fängt dann wieder bei 0 an. Deshalb ist es keine gute Idee z.B. zu schreiben "if(now > (lastAnzeigeCycle + 5000))". Besser "if((now - lastAnzeigeCycle) > 5000)", das sollte auch bei überlauf funktionieren.

Ich hoffe das hilft dir weiter,
Frank.

@frankly007
Ok das mit dem überlauf und dem Array versteh ich. Werde es mal ändern und testen.
Mir ist natürlich auch klar, dass es kein wirklicher Ringpuffer ist, aber ich will später mal ein auf einem LCD display ein Diagramm zeichnen.

aber das ist alles nicht das womit ich Probleme habe.

mein Problem liegt darin, dass wenn ich die Forschleife nicht ausführe, die unterschiedlichen funktionen zu unterschiedlichen zeiten ausgeführt werden.
soweit so gut.
wenn ich aber die For-Schleife aktiviere, dann wird die For-Schleife ausgeführt, die daten wander auch schön wieter, aber die schleife wird alle 400ms neu angestoßen. obwohl am restlichen code nichts geändert ist. Nur die For-Schleife durch läuft.

Vielleicht hat es damit was zu tun, dass ich quasie den 240. Paltz im array beschreibe ob wohl es diesen garnicht gibt?

ich werde es auf jeden fall mal testen.

Schön...
Ich verstehe nur nicht das Wort "aber" in dem Satz.
Zudem kann ich dir garantieren, dass Daten weder besser noch schöner werden, beim Kopieren.

Und nochmal: Das mündet in ein undefiniertes Verhalten.
Das bedeutet, dass dein Prozessor dann eine Pizza bestellen oder/und dir dein Wohnzimmer tapezieren darf.

Auf die Zeitrechnungen bist du noch gar nicht eingegangen.
Das verstehe ich als: ignorieren.

Sorry das ich nicht jeden satz komtiert habe:
Das mit der Zeitberechnung sehe ich ein, und hab es auch schon in meinem Programm geändert, aber noch nicht getestet weil ich aktell den Az-Touch nicht zur Hand habe.

Problem gefunden!!!
Es war tatsächlich die Falsche Adressierung des Arrays.
nach dem ich die Schleife von i= 240 auf i=239 geändert habe läuft es wie gewünscht. Und naürlach auch nach Änderung der IF-Bedingung für die Zeitliche Steuerung.

Vielen dank an alle die Tips gegeben haben