EEPROM lesen/schreiben Problem

Hallo Arduino Freunde,

ich brauche wieder eure Hilfe :slight_smile:

Ich bastle mir für ein Schulprojekt auch eine Tankanzeige für mein Moped mit Arduino UNO, 4D Display und Durchflusssensor.
Das Programm läuft soweit, nur habe ich ein Problem mit dem Wert im EEPROM zu speichern.
Damit will ich den Wert (die Impulse vom Sensor) vor dem ausschalten des Mopeds sichern, damit ich bei der nächsten Fahrt den aktuellen Inhalt des Tanks wieder habe.

Mein Problem ist, wenn der Impuls Wert z.B.: auf ca. 500 steigt ich ihn speichere → den Arduino Aus/An schalte ich nur noch ca. 250 Impulse am Display habe ???

Bei kleinen Werten unter 500 Imp klappt es ohne Probleme!

Bitte helft mir :slight_smile:

hier mein Kompletter code die EEPROM Teile sind markiert!

// 4D Systems Programm " Tankanzeige "

#include <EEPROM.h>
#include <SimpleTimer.h>

    SimpleTimer timer;

    #include <genieArduino.h>
    Genie genie;
    #define RESETLINE 4



long Imp = 0;    //Impulse vom Durchflusssensor
int IST  = 0;

long Impp;

int FULL = 500;    // var 


//EEPROM========EEPROM========EEPROM========EEPROM========EEPROM======
int i; // zum EEPROM clearen

int addr = 0; // the current address in the EEPROM (i.e. which byte we're going to write to next)
//EEPROM========EEPROM========EEPROM========EEPROM========EEPROM======



void setup() {
  // put your setup code here, to run once:
  
Serial.begin(9600);
genie.Begin(Serial);

  pinMode(RESETLINE, OUTPUT);  // Set D4 on Arduino to Output (4D Arduino Adaptor V2 - Display Reset)
  digitalWrite(RESETLINE, 1);  // Reset the Display via D4
  delay(100);
  digitalWrite(RESETLINE, 0);  // unReset the Display via D4
  delay (3500); //let the display start up after the reset (This is important)
  
  
  genie.AttachEventHandler(myGenieEventHandler);// Attach the user function Event Handler for processing events
  
  timer.setInterval(10000, repeatMe);
  
  // Interrupt-----Durchflusssensor------------------------------------------------------- 
  pinMode(2,INPUT);// _enable_interrupt();
  attachInterrupt(0, Messung, RISING);
  // Interrupt----------Durchflusssensor-------------------------------------------------- 


//EEPROM========EEPROM========EEPROM========EEPROM========EEPROM======
Impp = EEPROM.read(addr);  // mili liter aus eeporm lesen
Imp = Impp;
//EEPROM========EEPROM========EEPROM========EEPROM========EEPROM======

genie.WriteContrast(1);
}






void loop() {
  // put your main code here, to run repeatedly:
  genie.DoEvents(); // This calls the library each loop to process the queued responses from the display
  timer.run();
 

 IST = (1000 * Imp /2500);  //Impulse auf milli-Liter umrechnen
 
genie.WriteObject(GENIE_OBJ_LED_DIGITS, 0,Imp);   // impulse werden am display ausgegeben
genie.WriteObject(GENIE_OBJ_LED_DIGITS, 1,IST);      // mili Liter werden am display ausgegeben

genie.WriteObject(GENIE_OBJ_METER, 0,FULL);   //Tankanzeige




}


//=====================================Display================
void myGenieEventHandler(void) 
{ 
genieFrame Event;
genie.DequeueEvent(&Event);  // Remove the next queued event from the buffer, and process it below

  if(Event.reportObject.cmd == GENIE_REPORT_EVENT){   //If the cmd received is from a Reported Event
    if (Event.reportObject.object == GENIE_OBJ_4DBUTTON){  // If the Reported Message was from a 4Dbutton{
      
      if (Event.reportObject.index == 0){       //4dbutton0   Reset Knopf  wird nach dem Tankvorgang gedrückt  dh. Tank wieder voll
      
      // Clear the EEPROM 
      // write a 0 to all 512 bytes of the EEPROM
      for ( i = 0 ; i < 1000 ; i++) {EEPROM.write(i, 0);}  
      
      Imp = 0;  //Impulse zurück setzen nach dem tanken
      FULL = 500; // Tankanzeige zurücksetzen
      
     
     }
     
//EEPROM========EEPROM========EEPROM========EEPROM========EEPROM======


      if (Event.reportObject.index == 1){       
 //4dbutton1   Save knopf     wird vor dem ausschalten des mopeds gedrückt um den Wert zu speichern
       // Clear the EEPROM
      // write a 0 to all 512 bytes of the EEPROM
      for ( i = 0 ; i < 1000 ; i++) {EEPROM.write(i, 0);} 
  
      Impp = Imp;
    
   
      EEPROM.write(addr, Impp);   //  Impulse speichern 
     }
     
  //EEPROM========EEPROM========EEPROM========EEPROM========EEPROM======
   
    }  }  } 
    
   //========================================Display====================
    
    

//====================Externer Interrupt=================================
void Messung()
{
Imp++;
}
//====================Externer Interrupt================================

//======================================Timer======================
void repeatMe() {

int x = 500;
FULL = x - IST;  

   
}
//======================================Timer======================

Aus dem Handbuch:

EEPROM.write()

Description

Write a byte to the EEPROM.

Und wie groß ist die größte in ein Byte passende Zahl?

 // write a 0 to all 512 bytes of the EEPROM

for ( i = 0 ; i < 1000 ; i++) {EEPROM.write(i, 0);}

Du schreibst die Werte von 0 bis 1000 in einen Speicher, welcher:
Erstens, keine 1000 Speicherplätze hat.
Zweites keine Speicherplätze hat, welche die Zahl 1000 fassen könnten.

Ich vermute, du würdest viel lieber mit EEPROM.put() und EEPROM.get() arbeiten.

Mofritz: Mein Problem ist, wenn der Impuls Wert z.B.: auf ca. 500 steigt ich ihn speichere -> den Arduino Aus/An schalte ich nur noch ca. 250 Impulse am Display habe ??!?

Das glaube ich.

Bei kleinen Werten unter 500 Imp klappt es ohne Probleme!

Das glaube ich nicht. Das geht bestimmt nur bis 255.

Und warum speicherst du den Wert in alle Zellen des EEProms?

Vielen Dank für eure Antworten!

Ja ich Holzkopf 2^8 255 max.

Und warum speicherst du den Wert in alle Zellen des EEProms?

Gute Frage. Ich habe mir nur etwas aus den Beispiel Prog. zusammen gestellt.

Ich vermute, du würdest viel lieber mit EEPROM.put() und EEPROM.get() arbeiten.

Habe ich gerade versucht, klappt aber nicht. error: 'class EEPROMClass' has no member named 'get'

Habt ihr eine Idee wie ich meinen Code verändern muss, damit es klappt.

Ich müsste eine Zahl bis max.Wert 13000 speichern können.

Mofritz: ... Ja ich Holzkopf 2^8 255 max. ...

In manchen Situationen ist ein Holzkopf nützlicher als eine weiche Birne :-) Flüche sind jedenfalls immer gut.

Gruß

Gregor

Du brauchst nur diese Anweisung:

EEPROM.write(addr, Impp);

und teilst den Wert auf und schreibst es in zwei Zellen, also 2 Adressen.

z.B. wie hier

oder hier

Mofritz: Habe ich gerade versucht, klappt aber nicht. error: 'class EEPROMClass' has no member named 'get'

Das ist aber erstaunlich! Denn in der Doku ist diese explizit aufgeführt. https://www.arduino.cc/en/Reference/EEPROM Die Parameter sind natürlich etwas anders, als bei Read und Write. Welche Wunder....

Im Glaskugelmodus: Ich vermute, dass du die Fehlermeldung bis zur Aussagelosigkeit verstümmelt hast.... Mach dir nichts draus, typischer Anfängerfehler: Was ich nicht verstehe, wird ausgeblendet, und hat auch keinen anderen zu interessieren.

HotSystems: und teilst den Wert auf und schreibst es in zwei Zellen, also 2 Adressen.

Das gibts mit put und get geschenkt. Es vermeidet sogar unnütze Überschreibungen.

long Imp = 0;    //Impulse vom Durchflusssensor

Warum sind hier negative Zahlen erlaubt?

combie: Das gibts mit put und get geschenkt. Es vermeidet sogar unnütze Überschreibungen.

Das ist dann natürlich noch besser. Habe ich bisher noch nicht gebraucht, werde es aber auch testen.

Hast du vielleicht eine alte IDE Version? Die neue EEPROM Lib gibt es seit 1.6.2

Ansonsten geht es auch einfach mit Templates: http://playground.arduino.cc/Code/EEPROMWriteAnything

Void Zeiger würden es auch tun, aber dann müsste man noch die Länge übergeben

Viel bequemer und flexibler geht es mit der EEPROMex library.

Die kann mit etlichen Zahlenformaten umgehen und du brauchst eine integer nicht zu zerlegen. Außerdem kannst du mit dem Update-Befehl vermeiden, dass du Zellen immer wieder mit den gleichen Werten überschreibst, obwohl sich ggf. nichts geändert hat.

Hier findest du alle erforderlichen Infos und den download link zum github.

Vielen Dank für eure Antworten!

Ich bekomme es nicht hin, werde es morgen weiter versuchen...

rpt007: Viel bequemer und flexibler geht es mit der EEPROMex library.

Und wenn man sich anschaut was die macht, sieht man gleich dass es auch nur Templates sind. Halt mit netten Zusatz-Funktionen außen herum, so dass man sich z.B. nicht mehr selbst um die Adressen kümmern muss.

@Serenifly:

Genau so ist es. Aber: wenn ich mir dadurch Zeit und Nerven sparen kann und es tut, was es soll, dann ist das zumindest für mich die richtige Wahl. Ich bin kein gelernter Informatiker, sondern inzwischen "einigermaßen erfahrener Anwender", der das Rad nicht neu und von der Basis-Pike erfinden will und nicht kann.

Mir geht es darum, meine Projekte effizient und effektiv umzusetzen. Dabei scheue ich mich auch nicht, vorhandene und für mich bewährte libraries einzusetzen, wenn ich verstanden habe, was sie tun und mein Projekt voranbringen.

Naja…

Ich bevorzuge alle EEPROM Daten in einer Struktur anzulegen.
Und diese in die EEMEM Section zu stopfen.

Vorteile:

  1. Übersichtlich
  2. Die IDE erzeugt eine *.eep Datei. (upload über ISP möglich)
  3. Keinerlei Adressberechnungen nötig, macht alles der Compiler.

Siehe:

#include <EEPROM.h>

#define EEP(element) (int)&element // Adresse auflösen

struct EEPROM_Daten
{
  unsigned long zeitstempel;
  byte irgendwas;
  // hier können noch viele weitere Felder angelegt werden
};

EEPROM_Daten eepdata  EEMEM = {10,21}; // default werte für *.eep Datei


void setup() 
{
   Serial.begin(9600); 
   EEPROM.begin();
   
   //   EEPROM.put(EEP(eepdata.zeitstempel),millis());

   unsigned long zeitstempel;
   EEPROM.get(EEP(eepdata.zeitstempel),zeitstempel);
   Serial.println ( zeitstempel);  
}

void loop() {}

Man kann dann die ganze Struktur vom EEPROM ins RAM transferieren, oder auch nur einzelne Elemente.

Hallo Arduino Freunde, vielen Dank für eure Antworten und Unterstützung!

Auch ich habe es nun geschafft. :astonished:

Viel bequemer und flexibler geht es mit der EEPROMex library.

Damit muss ich aber nicht mehr vorher die EEPROM clearen um sie zu beschreiben? Richtig?

Ich bevorzuge alle EEPROM Daten in einer Struktur anzulegen.

Habe es auch mit get() und put() versucht, habe aber anscheinend nicht die passende oder aktuelle Arduino Version dafür. Werde mir es nochmal genauer anschauen, wenn ich wieder mehr Zeit habe.

Muss ich mir Gedanken machen, ob meine EEPROM nach 100.000 Schreib-Zugriffe nicht mehr 100%tige Leistung bringt? Wenn ich im Soll-Betrieb max. 2-3-mal am Tag einen Speichervorgang ausführe??

Muss ich mir Gedanken machen, ob meine EEPROM nach 100.000 Schreib-Zugriffe nicht mehr 100%tige Leistung bringt? Wenn ich im Soll-Betrieb max. 2-3-mal am Tag einen Speichervorgang ausführe??

3 mal am Tag? Das macht ca 91 Jahre.....

Ja, es lohnt sich darüber Gedanken zu machen!

Alternativ kannst du ja ein I2C EEProm verwenden, das hält dann 900 Jahre durch.

Damit muss ich aber nicht mehr vorher die EEPROM clearen um sie zu beschreiben? Richtig?

Nein, das erledigt die lib für dich. Du musst allerdings den EEPROM.update Befehl verwenden, um zu vermeiden, dass ein gleicher Wert nochmals in die gleiche Zelle geschrieben wird. Die lib vergleicht beim update-Befehl, ob sie die Speicherzelle überschreiben muss oder ob der alte Wert identisch mit dem neuen ist.

Mehr dazu auch hier.

OK ! Vielen Dank