Arduino EEPROM Ewige Ringliste, Read funktioniert nicht vor Write?



  • Hallo, aus der Doku werde ich nicht so richtig schlau, habe mir eine Ringliste gebastelt:

    #include <EEPROM.h>
    
    class Ringliste {
      public:
        Ringliste() {
          for (int i = 0; i < EEPROM.length(); i++) {
            EEPROM.write(i, 255);
          }
        }
        void writeTemp(float t) {
          int v1 = (millis() / 10000) % 256;
          int v2 = (int) t;
          int v3 = ((int) (t * 10)) % 10;
          EEPROM.write(index + 0, v1);
          EEPROM.write(index + 1, v2);
          EEPROM.write(index + 2, v3);
          index += 3;
          if (index + 2 >= EEPROM.length()) {
            index = 0;
          }
          Serial.setTimeout(1000);
          String st = Serial.readString();
          if ( st.startsWith("ringliste")) {
            for (int i = 0; i + 2 < EEPROM.length(); i += 3) {
              int a = EEPROM.read(i + 0);
              if (a == 255) {
                break;
              }
              int b = EEPROM.read(i + 1);
              int c = EEPROM.read(i + 2);
              Serial.print(a);
              Serial.print(" ");
              Serial.println( (float)b + ((float)c / 10) );
            }
          }
        }
      private:
        int index = 0;
    };
    
    Ringliste ringliste;
    

    Die Ringliste soll einfach die Temperatur speichern und sie ggf bei dem Signal "ringliste" wieder ausgeben. Aber zu Beginn soll der EEPROM gecleart werden. Das dauert sehr lange...

    Wenn ich in der Schleife im Konstruktor ein

            int a = EEPROM.read(i);
            if (a == 255) {
              break;
            }
    

    hinzufüge, dann wird der EEPROM nicht gecleart (also ist der Wert immer 255). Warum?

    Aus der Doku:

    read()
    Description
    
    Reads a byte from the EEPROM. Locations that have never been written to have the value of 255
    

    aber der EEPROM wurde zuvor ja mal beschrieben.

    Und meine zweite Frage wär, ich brauche 3 Byte, um ein Zeit-Temperatur-Werte-Paar zu speichern, ginge das auch mit 2 Byte? Die Temp ist ja meist zwischen 20.0 und 29.9 Grad...



  • Habe writeTemp etwas geändert um komme jetzt mit 1/3 der Bytes aus:

        void writeTemp(float t) {
          int v1 = round( (t * 255.0) / 31.0 );
          EEPROM.write(index + 0, v1);
          index += 1;
          if (index >= EEPROM.length()) {
            index = 0;
          }
          Serial.setTimeout(1000);
          String st = Serial.readString();
          if ( st.startsWith("ringliste")) {
            for (int i = 0; i < EEPROM.length(); i += 1) {
              int a = EEPROM.read(i + 0);
              if (a == 255) {
                break;
              }
              Serial.print(i);
              Serial.print(" ");
              Serial.println( ((float)a * 31.0) / 255.0 );
            }
          }
        }
    
    09:44:17.092 -> 23.10
    09:44:17.132 -> 65.00 %
    09:44:24.034 -> 23.30
    09:44:24.072 -> 65.00 %
    09:44:50.121 -> 23.30
    09:44:50.121 -> 65.00 %
    09:45:16.162 -> 23.40
    09:45:16.201 -> 65.00 %
    09:45:42.251 -> 23.10
    09:45:42.251 -> 65.00 %
    09:46:08.302 -> 23.40
    09:46:08.302 -> 67.00 %
    09:46:34.372 -> 23.50
    09:46:34.372 -> 67.00 %
    09:47:00.433 -> 23.50
    09:47:00.433 -> 65.00 %
     //    "ringliste" gesendet
    09:47:01.432 -> 0 23.10
    09:47:01.432 -> 1 23.34
    09:47:01.472 -> 2 23.34
    09:47:01.472 -> 3 23.34
    09:47:01.472 -> 4 23.10
    09:47:01.472 -> 5 23.34
    09:47:01.472 -> 6 23.46
    09:47:01.512 -> 7 23.46
    

    Geht das noch etwas besser ohne Rundungsfehler?


    Bearbeitung, so gibt es keine Rundungsfehler:

        void writeTemp(float t) {
          int v1 = round( ((t - 16.0) * 255.0) / 16.0 );
          EEPROM.write(index + 0, v1);
          index += 1;
          if (index >= EEPROM.length()) {
            index = 0;
          }
          Serial.setTimeout(1000);
          String st = Serial.readString();
          if ( st.startsWith("ringliste")) {
            for (int i = 0; i < EEPROM.length(); i += 1) {
              int a = EEPROM.read(i + 0);
              if (a == 255) {
                break;
              }
              a = round( ((float)a * 16.0) / 25.5 );
              Serial.print(i);
              Serial.print(" ");
              Serial.println( (a / 10.0) + 16.0 );
            }
          }
        }
    

    , nur unter 16 Grad oder über 32 Grad ist es unteroptimal...



  • Hier nochmal die komplette Klasse:

    class Ringliste {
      public:
        Ringliste() {
        }
        void writeTemp(float t) {
          int v1 = packFromFloat(t);
          EEPROM.write(index, v1);
          index += 1;
          if (index >= EEPROM.length()) {
            index = 0;
          }
    
          Serial.setTimeout(1000);
          String st = Serial.readString();
          if ( st.startsWith("ringliste")) {
            Serial.print("index = ");
            Serial.println( index );
            for (int i = 0; i < EEPROM.length(); i += 1) {
              int a = EEPROM.read(i);
              if (a == 255) {
                break;
              }
              Serial.print(i);
              Serial.print(" ");
              Serial.println( unpackToFloat(a) );
    
              EEPROM.write(i, 255);
            }
            index = 0;
          }
        }
      private:
        int index = 0;
        int packFromFloat(float t) {
          return round( ((t - 16.0) * 255.0) / 16.0 );
        }
        float unpackToFloat(int a) {
          return (round( ((float)a * 16.0) / 25.5 ) / 10.0) + 16.0;
        }
    };
    


  • @EinNutzer0
    Mal ein paar Fragen.

    1.) Warum speichert du jeden Wert ins EEPROM? Das ist gefühlt so, als würde ich für eine Berechnung alle Werte auf der Festplatte schieben. Funktioniert da nicht auch ein Ringpuffer ala

    int Buffer[256];
    int ReadPos;
    int WritePos;
    

    2.)

    Serial.setTimeout(1000);
    String st = Serial.readString();
    

    Sieht ein wenig merkwürdig aus. Prüfe mal ob die Funktion Serial.readString() eine Sekunde lang blockiert wenn keine serielle Daten ankommen. Ggf. musst du folgendes tun (ohne deine Umgebungsentwicklung zu kennen):

    if (Serial.InBufferCount() > 8)
    {
        String st = Serial.readString();
        if ( st.startsWith("ringliste")) {
          //....
       }
    }
    


  • @Quiche-Lorraine sagte in Arduino EEPROM Ewige Ringliste, Read funktioniert nicht vor Write?:

    @EinNutzer0
    Mal ein paar Fragen.

    1.) Warum speichert du jeden Wert ins EEPROM? Das ist gefühlt so, als würde ich für eine Berechnung alle Werte auf der Festplatte schieben. Funktioniert da nicht auch ein Ringpuffer ala

    int Buffer[256];
    int ReadPos;
    int WritePos;
    

    Hatte einfach mal aus Interesse durch die Erklärungen geschaut. Selbst wenn der EEPROM genutzt werden sollte, macht da EEPROM.Update nicht mehr Sinn?

    https://www.arduino.cc/en/Tutorial/EEPROMUpdate

    The purpose of this example is to show the EEPROM.update() method that writes data only if it is different from the previous content of the locations to be written. This solution may save execution time because every write operation takes 3.3 ms; the EEPROM has also a limit of 100,000 write cycles per single location, therefore avoiding rewriting he same value in any location will increase the EEPROM overall life.



  • @fairiestoy
    Jaein.

    the EEPROM has also a limit of 100,000 write cycles per single location, therefore avoiding rewriting he same value in any location will increase the EEPROM overall life.

    Das macht mir Sorgen. Nach 100000 Schreibzyklen geht eine EEPROM Zelle über den Jordan. Wenn nun die Temperaturwerte alle 10 Hz kommen, so dauert es nach meiner Rechnung cirka 30 Tage bis das komplette EEPROM ausfällt.

    Das EEPROM.Update macht der auf jeden Fall mehr Sinn, aber das wird die Lebensdauer im Worst Case nicht verlängern.



  • @Quiche-Lorraine
    Ich muss mich korrigieren. Gemäß dem letzten Code von EinNutzer0 wird eine Zelle pro Wert immer zweimal beschrieben. Einmal um den Wert hineinzuschreiben und einmal um diesen zu löschen in dem FF hineingeschrieben wird.

    Als halbiert sich die Zeit auf 15 Tage bis das EEPROM ausfällt.



  • Danke für die Info mit Update...

    Die Temperaturen kommen ca alle 30 Sekunden. Das EEPROM kann 4 kilobyte speichern. Also könnte ich theoretisch 34 Stunden lang die Temperaturen speichern. Eigentlich ist das nicht wenig...



  • @EinNutzer0 sagte in Arduino EEPROM Ewige Ringliste, Read funktioniert nicht vor Write?:

    Danke für die Info mit Update...

    Die Temperaturen kommen ca alle 30 Sekunden. Das EEPROM kann 4 kilobyte speichern. Also könnte ich theoretisch 34 Stunden lang die Temperaturen speichern. Eigentlich ist das nicht wenig...

    Nicht wenig bis total Ausfall? Ich finde schon....



  • @EinNutzer0 sagte in Arduino EEPROM Ewige Ringliste, Read funktioniert nicht vor Write?:

    Danke für die Info mit Update...

    Die Temperaturen kommen ca alle 30 Sekunden. Das EEPROM kann 4 kilobyte speichern. Also könnte ich theoretisch 34 Stunden lang die Temperaturen speichern. Eigentlich ist das nicht wenig...

    Du bist noch nicht auf den Punkt von @Quiche-Lorraine eingegangen, ob ein Ringpuffer nicht möglich wäre. Oder das du deine Daten auf einem externen Speicher unterbringst (welche Form auch immer dieser externe Speicher hat).


Log in to reply