INT in EEPROM

Tach,

Versuche grade nen INT wert ins EEPROM zu Schaufeln jedoch geht da was schief…

long minlvl = 0;
long maxlvl = 0;
...
long eemin;
long eemax;
...
eemin=eepromReadLong(1);   //minlvl
eemax=eepromReadLong(10);   //maxlvl
...
long total =  liquidLevel.capacitiveSensorRaw(50);
...
      minlvl = total;
      eepromWriteLong(1, minlvl);
...
      maxlvl = total;
      eepromWriteLong(10, maxlvl);
...


void writeData(unsigned int addr, byte data) 
{
  Wire.beginTransmission(i2caddr);
  // set the pointer position
  Wire.write((int)(addr >> 8));
  Wire.write((int)(addr & 0xFF));
  Wire.write(data);
  Wire.endTransmission();
  delay(10);
}

// reads a byte of data from memory location addr
byte readData(unsigned int addr) 
{
  byte result;
  Wire.beginTransmission(i2caddr);
  // set the pointer position
  Wire.write((int)(addr >> 8));
  Wire.write((int)(addr & 0xFF));
  Wire.endTransmission();
  Wire.requestFrom(i2caddr,1); // get the byte of data
  result = Wire.read();
  return result;
}

void eepromWriteInt(int adr, int wert) {
// 2 Byte Integer Zahl im EEPROM ablegen an der Adresse
// Eingabe: 
//   adr: Adresse +0 und +1 wird geschrieben
//   wert: möglicher Wertebereich -32,768 bis 32,767
// Ausgabe: 
//   -
// 2 Byte Platz werden belegt.
//
// Matthias Busse 5.2014 V 1.0
 
byte low, high;
 
  low=wert&0xFF;
  high=(wert>>8)&0xFF;
  writeData(adr, low); // dauert 3,3ms 
  writeData(adr+1, high);
  return;
} //eepromWriteInt
 
int eepromReadInt(int adr) {
// 2 Byte Integer Zahl aus dem EEPROM lesen an der Adresse
// Eingabe: 
//   adr: Adresse +0 und +1 wird gelesen
// Ausgabe: int Wert
//
// Matthias Busse 5.2014 V 1.0
 
byte low, high;
 
  low=readData(adr);
  high=readData(adr+1);
  return low + ((high << 8)&0xFF00);
} //eepromReadInt

void eepromWriteLong(long lo, int adr) {
// long Wert in das EEPROM schreiben  
// Eingabe : adr Speicherplatz 
// Eingabe : lo Zahl, Wertebereich -2.147.483.648 bis 2.147.483.647
//
// Matthias Busse 23.5.2014 Version 1.0
 
byte by;
 
  for(int i=0;i< 4;i++) {
    by = (lo >> ((3-i)*8)) & 0x000000ff; 
    writeData(adr+i, by);
  }
} // eepromWriteLong

long eepromReadLong(int adr) {
// long int Wert aus 4 Byte EEPROM lesen
// Eingabe : adr bis adr+3
// Ausgabe : long Wert
// 
// Matthias Busse 23.5.2014 Version 1.0
 
long lo=0;
 
  for(int i=0;i< 3;i++){
    lo += readData(adr+i);
    lo = lo << 8;
  }
  lo += readData(adr+3);
  return lo;
} // eepromReadLong

minwert: MIN WERT GESETZT auf: 50024
maxwert: MAX WERT GESETZT auf: 786261

so jetzt beim auslesen des eeproms erhalte ich :

eemin: 51061
eemax: 13521

anstatt 50024/786261

wo stecktn hier der wurm ?

Was tust du da?
Wie soll ein int wert 50024 groß sein?
Oder gar 786261?

Vorschlag:
Denke über Zahlen und ihre Wertebereiche nach.

Sry ich meine Long nicht INT..

Ist nen Arduino DUE.. mit nem 24C256 EEPROM

btw: Warum kann ich nur alle 10min nen Post abgeben?

mpl1337:
Sry ich meine Long nicht INT..
Ist nen Arduino DUE.. mit nem 24C256 EEPROM

Dann ist es egal.
Auf dem DUE sind int und long jeweils 4 Byte groß. (?)

Die Lib, welche du verwendest geht offensichtlich von 2 Byte pro int aus.

Am besten man macht sowas mit einer Funktion die einen void* nimmt. Oder mit Templates. Dann ist der Datentyp vollkommen egal.

Hier mal mit einem Array simuliert:

byte eeprom[100];

void setup()
{
  Serial.begin(9600);

  unsigned int var1 = 0x0A0B;
  unsigned long var2 = 0X33445566;
  float var3 = 459.4;

  unsigned int adr = 0;

  write(&var1, sizeof(var1), adr);
  adr += sizeof(var1);
  write(&var2, sizeof(var2), adr);
  adr += sizeof(var2);
  write(&var3, sizeof(var3), adr);

  adr = 0;
  var1 = 0;
  var2 = 0;
  var3 = 0.0;

  read(&var1, sizeof(var1), adr);
  adr += sizeof(var1);
  read(&var2, sizeof(var2), adr);
  adr += sizeof(var2);
  read(&var3, sizeof(var3), adr);

  Serial.println(var1, HEX);
  Serial.println(var2, HEX);
  Serial.println(var3);
}

void loop()
{
}

void write(void* data, unsigned int size, unsigned int adr)
{
  byte* ptr = (byte*)data;

  for (unsigned int i = 0; i < size; i++)
  {
    eeprom[adr + i] = *ptr;
    ptr++;
  }
}

void read(void* data, unsigned int size, unsigned int adr)
{
  byte* ptr = (byte*)data;

  for (unsigned int i = 0; i < size; i++)
  {
    *ptr = eeprom[adr + i];
    ptr++;
  }
}

Das funktioniert dann auch mit komplexen Datentypen wie structs!

Template Version folgt…

Dann in C++ und Templates.

Das in eine Datei namens EepromUtil.h:

#include "Arduino.h"

byte eeprom[100];

template<typename T>
void write(const T& data, unsigned int adr)
{
  byte* ptr = (byte*)&data;

  for (unsigned int i = 0; i < sizeof(T); i++)
  {
    eeprom[adr + i] = *ptr;
    ptr++;
  }
}

template<typename T>
void read(T& data, unsigned int adr)
{
  byte* ptr = (byte*)&data;

  for (unsigned int i = 0; i < sizeof(T); i++)
  {
    *ptr = eeprom[adr + i];
    ptr++;
  }
}

Das Array ist wieder nur als Test!

Dann der Haupt Code:

#include "EepromUtil.h"

void setup()
{
  Serial.begin(9600);

  unsigned int var1 = 0x1122;
  unsigned long var2 = 0XAABBCCDD;
  float var3 = 459.4;

  unsigned int adr = 0;

  write(var1, adr);
  adr += sizeof(var1);
  write(var2, adr);
  adr += sizeof(var2);
  write(var3, adr);

  adr = 0;
  var1 = 0;
  var2 = 0;
  var3 = 0.0;

  read(var1, adr);
  adr += sizeof(var1);
  read(var2, adr);
  adr += sizeof(var2);
  read(var3, adr);

  Serial.println(var1, HEX);
  Serial.println(var2, HEX);
  Serial.println(var3);
}

void loop()
{
}

Da Templates typ-sicher ist, ist nun der Typ in der Funktion bekannt und man kann einfach sizeof(T) machen. So muss man die Größe nicht mehr übergeben

Du kannst dir auch mal die EEPROM Klasse in neueren Arduino Versionen ansehen. Da gibt es z.B. eine update() Funktion wo der Wert nur geschrieben wird wenn er sich geändert hat. Das ist natürlich für das interne EEPROM gedacht, aber den Code kann man auch kopieren und für externe EEPROM anpassen.

danke für deine mühe jedoch bin ich nicht in der lage das so anzupassen das es auf meinem arduino DUE läuft ich werde das einfach weglassen und den wert bei jedem neustart des arduinos neu einlesen. Ich hock schon den ganzen tag dadran und bin keinen schritt weiter gekommen :confused:

Dann nimm halt meinen Code (am besten die Template Version). Da muss du nur zwei Zeilen ändern

Byte schreiben:

eeprom[adr + i] = *ptr;

Byte lesen:

*ptr = eeprom[adr + i];

Da ersetzt du den Array Zugriff durch deine I2C Funktion und es sollte gehen. Wobei dann der I2C Kram ebenfalls in den Header muss.
*ptr ist einfach das aktuelle Byte. Entweder in der Quell- oder der Ziel-Variable.

Und eben das Array entfernen. Wobei du die 100 Byte auf dem Due nicht vermissen wirst :wink:

Arduino: 1.6.5 (Windows 8.1), Platine: “Arduino Due (Programming Port)”

In file included from terra.ino:12:0:
EepromUtil.h: In instantiation of ‘void read(T&, unsigned int) [with T = long unsigned int]’:
terra.ino:92:16: required from here
EepromUtil.h:48: error: invalid conversion from ‘byte ()(unsigned int) {aka unsigned char ()(unsigned int)}’ to ‘byte {aka unsigned char}’ [-fpermissive]
ptr = readData[adr + i];
^
EepromUtil.h: In instantiation of ‘void write(const T&, unsigned int) [with T = long int]’:
terra.ino:139:22: required from here
EepromUtil.h:36: error: assignment of read-only location '
(writeData + ((sizetype)(adr + i)))’
writeData[adr + i] = ptr;
^
EepromUtil.h:36: error: cannot convert ‘byte {aka unsigned char}’ to ‘void(unsigned int, byte) {aka void(unsigned int, unsigned char)}’ in assignment
invalid conversion from 'byte (
)(unsigned int) {aka unsigned char (*)(unsigned int)}’ to ‘byte {aka unsigned char}’ [-fpermissive]

das ist die komplette EepromUtil.h jetzt

#include "Arduino.h"

#define i2caddr 0x50
void writeData(unsigned int addr, byte data) 
{
  Wire.beginTransmission(i2caddr);
  // set the pointer position
  Wire.write((int)(addr >> 8));
  Wire.write((int)(addr & 0xFF));
  Wire.write(data);
  Wire.endTransmission();
  delay(10);
}

// reads a byte of data from memory location addr
byte readData(unsigned int addr) 
{
  byte result;
  Wire.beginTransmission(i2caddr);
  // set the pointer position
  Wire.write((int)(addr >> 8));
  Wire.write((int)(addr & 0xFF));
  Wire.endTransmission();
  Wire.requestFrom(i2caddr,1); // get the byte of data
  result = Wire.read();
  return result;
}

template<typename T>
void write(const T& data, unsigned int adr)
{
  byte* ptr = (byte*)&data;

  for (unsigned int i = 0; i < sizeof(T); i++)
  {
    writeData[adr + i] = *ptr;
    ptr++;
  }
}

template<typename T>
void read(T& data, unsigned int adr)
{
  byte* ptr = (byte*)&data;

  for (unsigned int i = 0; i < sizeof(T); i++)
  {
    *ptr = readData[adr + i];
    ptr++;
  }
}

da gibts wieder konflikte mit verschiedenen typen… :frowning:

Oh je, Oh je :frowning: :frowning: :frowning: :frowning: Das solltest du nicht so wörtlich nehmen

1.) Inkludiere im Header Wire.h. Sonst sind die Wire Funktionen wahrscheinlich nicht bekannt. Im Haupt-Sketch musst du es dann wahrscheinlich trotzdem nochmal inkludieren (da spinnt die IDE etwas)

2.) Dann verwende deine Funktion so wie du sie geschrieben hast!

writeData(adr + i, *ptr);
*ptr = readData(adr + i);

Ups, übersehen... Ist nicht meine Funktion ist ausm netz. Werde es später korrigieren und nochmal probieren :slight_smile:

Danke für die Hilfe

so habs versucht aber irgendwie scheine ich da was falsch zu machen bzw nicht ganz verstehen…

unsigned long minlvl = 10000; // sensor auswertung dauert mir beim testen zulange, werte zwischen 0-10000 zu erwarten
unsigned long maxlvl = 90000; // sensor auswertung dauert mir beim testen zulange, werte zwischen 0-10000 zu erwarten
unsigned long eemin;
unsigned long eemax;
unsigned int adr = 0;

write(minlvl, adr);
adr += sizeof(minlvl);

write(maxlvl, adr);
adr += sizeof(maxlvl);

read(eemin, adr);
adr += sizeof(eemin);
read(eemax, adr);
adr += sizeof(eemax);

Serial.println(eemin);
Serial.println(eemax);

und output auf der seriellen ist:

4092785136
4160157172

ohhmmaaann habs:

write(minlvl, 0);
write(maxlvl, 10);

read(eemin, 0);
read(eemax, 10);

das mit der adresse war mein fehler :smiley:

Kann sein dass die read()/write() Methoden noch falsch sind

Wire.write((int)(addr >> 8));
Wire.write((int)(addr & 0xFF));

Caste da mal auf byte statt int. Du willst die write() Methode die ein einzelnes Byte schreibt! Nicht int

Oder versuche mal Wire.write(addr). Dann wird die unsigned int Methode aufgerufen

Wire hat nämlich Methoden für 1 Byte, 2 Bytes und 4 Bytes. Da muss man dann schon die richtige aufrufen

Das EEPPROM kann übrigens Page Read/Write. Also man kann einmal adressieren und dann x Bytes lesen und schreiben. So hat man jetzt etwas mehr Datenverkehr, weil jedes Byte einzeln adressiert wird. Aber wenn man nur ein paar Werte hier und da überträgt ist das vollkommen egal.

ja ne ich experimentiere da nicht weiter dran. Funzt jetzt :slight_smile: ich leg die adressen selber fest und gut ist =)

Das sollte aber nicht so sein. Ein unsigned long belegt 4 Bytes. Und danach muss man korrekt das nächste Byte adressieren können

Wenn du das von int auf byte änderst ist das schlimmste was passieren kann dass es sich danach genauso wie vorher verhält.

wenn ich ja mit Adresse 0 Anfange und die 4 Byte reinschiebe mach ich mit dem nächsten unsigned long bei adresse 4 weiter... oder was meinst du?

sizemax = sizeof(maxlvl);
sizemin = sizeof(minlvl);

liefert mir 4

habs jetzt mal als byte gemacht und es hat sich nichts geändert :slight_smile:

Klar sollte so das sein. Der Fehler liegt wahrscheinlich auf der untersten Ebene. Für mich sieht für mich so aus dass was bei der Adressierung der Speicherzellen im EEPROM schief geht.

nee dein sample sketch funktioniert vollkommen.

nur ich habe beim rauskopieren einen fehler gemacht und vergessen vor dem lesen zurück auf 0 zu gehen

write(var1, adr);
adr += sizeof(var1);
write(var2, adr);
adr += sizeof(var2);
write(var3, adr);

adr = 0; <----------- habe ich vergessen

read(var1, adr);
adr += sizeof(var1);
read(var2, adr);
adr += sizeof(var2);
read(var3, adr);

Ah gut :slight_smile:

Wenn du genau weißt was du machst kannst das mit sizeof() natürlich auch weglassen und die Adressen per Hand setzen. Also einmal auf 0 und einmal auf 4. Aber so muss man sich nicht um die Größe der Datentypen kümmern. Das ist vor allem dann praktisch wenn man einige verschiedene Datentypen hat. Oder wenn man komplexe Datentypen wie structs ins EEPROM schreibt. Oder auch wenn Code sowohl auf dem Due und UNO/Mega laufen soll, da int und double da unterschiedlich groß sind.