Forum: Mikrocontroller und Digitale Elektronik Arduino u. I2C-EEPROM - wo kommt der Offset her


von Egon M. (kpc)


Lesenswert?

Hallo,
mir fällt partout nicht ein, woher bei dem Auslesen eines I2C-EEPROMs 
der Offset herkommt. Die Ausgabe des unten angefügten Programms beginnt 
ab einer eepromadresse von ca 5600, obwohl als Startwert säuberlich eine 
Null steht.

Ob vielleicht einer der Experten mal einen Blick auf das Programm werfen 
könnte? Ich habe schon an allen Stellen gedreht, aber ich komme einfach 
nicht weiter.
Vielen Dank!
VG
Egon

1
// i2c_eeprom_lesen_reduz-150807                       
2
// Ausgabe startet erst bei ca 5600
3
4
#include <EEPROM.h>
5
#include <Wire.h>
6
const int I2CADRESSE = 0x57;      // I2C-Adresse des EEPROM, alle Adress-Schalter auf low (und die Pullups auch)
7
8
void setup()
9
{
10
  Wire.begin();                   // join i2c bus (address optional for master)
11
  Serial.begin(9600);             // start serial for output
12
  unsigned int eepromaddresse;
13
  byte wert1, wert2, wert;
14
15
   for ( unsigned int eepromaddresse = 0; eepromaddresse < 8000; eepromaddresse++)
16
  {
17
    wert1 = liesEEPROM(I2CADRESSE, eepromaddresse);
18
    eepromaddresse++;
19
    wert2 = liesEEPROM(I2CADRESSE, eepromaddresse);
20
    eepromaddresse++;
21
22
    wert = wert1 << 8 | wert2;
23
24
    Serial.print(eepromaddresse -3);    // -3 heißt: anfängliche EEPROM-Adresse
25
    Serial.print("\t");
26
    Serial.print(wert, DEC);
27
    Serial.println();
28
  }                                    // Ende for
29
}                                      // Ende setup
30
31
void loop ()
32
{}
33
34
byte liesEEPROM(int I2CADRESSE, unsigned int eepromaddress)   // byte datenbyte=0xFF)
35
{
36
  byte  datenbyte;                                   // = 0x00;
37
  Wire.beginTransmission(I2CADRESSE);
38
  Wire.write ((byte) (eepromaddress >> 8));          // die oberen Bits?
39
  Wire.write ( (byte) (eepromaddress & 0xFF));
40
  Wire.endTransmission();
41
  Wire.requestFrom(I2CADRESSE, 1);                   //  1 heißt ein Byte ?
42
  if (Wire.available())
43
    datenbyte = Wire.read();
44
  return datenbyte;
45
}

von m.n. (Gast)


Lesenswert?

Egon M. schrieb:
> const int I2CADRESSE = 0x57;

Nimm mal 0x50.

von Egon M. (kpc)


Lesenswert?

Hallo m.n.
geht leider auch nicht besser; die Ausgabe fängt wieder erst bei ca 6000 
an und die Ausgaben für den Inhalt des EEPROMs sind allesamt = 0.

VG
Egon

von m.n. (Gast)


Lesenswert?

Egon M. schrieb:
> Auslesen eines I2C-EEPROMs

Welcher Typ, wie beschaltet?

von Egon M. (kpc)


Lesenswert?

m.n. schrieb:
> Egon M. schrieb:
>> Auslesen eines I2C-EEPROMs
>
> Welcher Typ, wie beschaltet?

Auf dem Chip steht 24LC256 und das Motorolasymbol. Montiert ist es 
mitsamt den Anschlußteilen auf einer kleinen Platine von DF Robot.
Angeschlossen ist es per I2C, also + / - SDA u. SCL.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?


von Egon M. (kpc)


Lesenswert?

Rufus Τ. F. schrieb:
> Egon M. schrieb:
>> 24LC256 und das Motorolasymbol
>
> Verwechselst Du das möglicherweise mit dem von Microchip?
>
> http://learningembedded.com/wp-content/uploads/microchip-logo.png
>
> http://cdn-www.xda-developers.com/wp-content/uploads/2011/02/motorola-logo.jpg

Hi,Rufus,
Du hast Recht, es ist Microchip!

von Peter D. (peda)


Lesenswert?

Beide Pullups (1,8k..10k) angeschlossen?

Hier mal meine Lib:

Beitrag "Re: I2C Problem mit Acknowledge Polling"

: Bearbeitet durch User
von Egon M. (kpc)


Lesenswert?

Peter D. schrieb:
> Beide Pullups (1,8k..10k) angeschlossen?

Ich selbst habe keine Pullups angeschlossen, allerdings sind auf der 
Platine EEPROM module von DF Robots fünf SMD-Teile zu sehen, von denen 
man annehmen könnte, sie seien welche.

>
> Hier mal meine Lib:
>
> Beitrag "Re: I2C Problem mit Acknowledge Polling"

Das muß ich mir später mal genauer ansehen. Schön wäre es, wenn ich dem 
vielleicht ungenügenden libs von Arduino mit ein paar delay's aufhelfen 
könnte, andernfalls müßte ich den I2C-Zugriff wieder wie früher manuell 
programmieren.

Vielleicht kommt aus dem parallelen Thread noch eine mundfertige Lösung 
heraus.
Was mich wundert, ist, daß es bei mir bisher immer gut gegangen ist, ich 
benutze ein ähnliches Programm schon seit 2-3 Jahren ohne Probleme.

von Frank L. (frank_l)


Lesenswert?

Egon M. schrieb:
> wert = wert1 << 8 | wert2;

Hi,

kann so nicht funktionieren. Alle Variablen sind byte was soll nach 
einen <<8 in wert noch stehen?

wert sollte mindestens integer sein.

Gruß
Frank

von Egon Mueller (Gast)


Lesenswert?

Frank L. schrieb:
> wert sollte mindestens integer sein.

Stimmt!
Das gezeigte Programm ist ein Schnipsel aus einem längeren Programm, das 
ich reduziert habe, um das Posting auf das Wichtigste zu beschränken.
Und zum Schluß habe ich darin noch herumfuhrwerkt, sodaß die im bisher 
funktionierenden, kompletten Programm vorhandene globale Definition wohl 
unter die Räder gekommen ist.

Übrigens, zu dem generellen I2C-Problem hier, ich habe gestern auf die 
schnelle ein paar delay(10) eingefügt - und es wwird besser!

VG
Egon

von m.n. (Gast)


Lesenswert?

Egon Mueller schrieb:
> Übrigens, zu dem generellen I2C-Problem hier, ich habe gestern auf die
> schnelle ein paar delay(10) eingefügt - und es wwird besser!

Du könntest auch wild verteilt noch einige Kondensatoren dazulöten. 
Vielleicht wird es noch besser, aber es wird niemals gut!

Also lass das blöde delay()-Gemache und such den richtigen Fehler.

von Tom (Gast)


Lesenswert?

Warum steht denn Dein Code in setup() und loop() ist leer?
Ich bin jetzt nicht der Arduino Experte, aber die paar Beispiele,
die ich mir angesehen habe, hatten den Code in loop().
Wer weiss, was Arduino beim Start von loop() so alles macht ;-)

von Egon M. (kpc)


Lesenswert?

Tom schrieb:
> Warum steht denn Dein Code in setup() und loop() ist leer?
> Ich bin jetzt nicht der Arduino Experte, aber die paar Beispiele,
> die ich mir angesehen habe, hatten den Code in loop().
> Wer weiss, was Arduino beim Start von loop() so alles macht ;-)

Es soll nur ein einziges mal ablaufen, dann kopiere ich sofort die 
Ausgabe vom Terminal und Schluß.

von Dirk K. (dekoepi)


Lesenswert?

Du gibst EepromAdresee -3 aus. Fängst bei 0 im unsigned int an, dürfte 
also 65532 ausgeben.

Die Adresse unten zum Schreiben schiebst du 8 Bits nach rechts. Das 
sollte verlässlich aus deiner 57 eine 0 machen.

Du meinst vielleicht eher einen Shift nach links für die Schreibadresse, 
also <<1 anstatt >>8?

Edit: Mist, EepromAdresse und I2CAdresse verwchselt. Das ist also ok. 
Ich vermute, es ist schlicht das "-3", und dann Fehler bei der 
Übertragung an den Terminal, dass du als Adresse 5532 siehst?

: Bearbeitet durch User
von Egon Mueller (Gast)


Lesenswert?

m.n. schrieb:
> Egon Mueller schrieb:
>> Übrigens, zu dem generellen I2C-Problem hier, ich habe gestern auf die
>> schnelle ein paar delay(10) eingefügt - und es wwird besser!
>
> Du könntest auch wild verteilt noch einige Kondensatoren dazulöten.
> Vielleicht wird es noch besser, aber es wird niemals gut!
>
> Also lass das blöde delay()-Gemache und such den richtigen Fehler.

Die Wirkung der delay() sieht wenigstens nach einem Hinweis aus, wo man 
weitersuchen könnte. Allerdings kommt man damit dem Offsetproblem wohl 
nicht näher.
mfg
Egon

von Host (Gast)


Lesenswert?

Egon M. schrieb:
> for ( unsigned int eepromaddresse = 0; eepromaddresse < 8000;
> eepromaddresse++)
>   {
>     wert1 = liesEEPROM(I2CADRESSE, eepromaddresse);
>     eepromaddresse++;
>     wert2 = liesEEPROM(I2CADRESSE, eepromaddresse);
>     eepromaddresse++;
>
>     wert = wert1 << 8 | wert2;
>
>     Serial.print(eepromaddresse -3);    // -3 heißt: anfängliche
> EEPROM-Adresse

Wenn Du ausgehend von Adresse = 0 zweimal 1 drauf addierst, dann landest 
Du bei Adresse = 2. Wenn Du davon dann 3 abziehst, landest Du bei 65535.

von Host (Gast)


Lesenswert?

Okay, grade gesehen, eepromaddresse ist unsigned int, gibt also keinen 
negativen Wert beim subtrahieren von 3. Vielleicht verstümmelt die 
Serial.Print-Routine ja den Wert.

von Daniel S. (daniel_s49)


Lesenswert?

Egon M. schrieb:
> Wire.requestFrom(I2CADRESSE, 1);
> if (Wire.available())
>     datenbyte = Wire.read();


Was passiert, wenn das if false ist? Dann hast du eine Anfrage gestellt, 
einen Wert aus dem EEPROM auszulesen, holst ihn aber nicht ab? Wie 
verhält sich der EEPROM dann?
Bauchgefühl sagt eher
while (!Wire.available());
datenbyte = Wire.read();

Könnte erklären, wieso Delays helfen.


Mit der Adresse würde ich, wie Host, auf die Serial.print() tippen. 
(Kenne die Arduino-Libs nicht und bin vielleicht deshalb skeptisch).
Gibt die auch den falschen Wert aus, wenn du die -3 weglässt?
Oder Zählvariable in der Schleife mitlaufen lassen -> wird die Schleife 
tatsächlich 2666 mal durchlaufen?

Und dass eepromadresse in der setup() doppelt deklariert ist, schiebe 
ich mal auf das Umkopieren, richtig? (sollte aber sicher fallen und kein 
Problem darstellen)

von Jobst M. (jobstens-de)


Lesenswert?

Egon M. schrieb:
1
for ( unsigned int eepromaddresse = 0; eepromaddresse < 8000; eepromaddresse++)
2
    {
3
        eepromaddresse++;
4
        eepromaddresse++;
5
    }

Du zählst in 3er Schritten !?


Gruß

Jobst

von Egon Mueller (Gast)


Lesenswert?

Mit den Dreierschritten bzw. eepromadresse -3 ist das einfach: Zum 
Speichern der Meßwerte werden vier Speicherzellen benötigt.
Beim Auslesen der Meßwerte werden diese vier Werte, aus denen nach 
Umrechnung zwei geworden sind, einer einzigen Eepromadresse zugeordnet, 
damit sie in einem Diagramm dargestellt werden können. Gewählt wurde die 
erste der vier Adressen, also Eepromadresse -3. Mehr steckt da nicht 
dahinter.

Wegen der anderen Sachen muß ich demnächst mal in die Arduino-libs 
hineinschauen.

VG
Egon

von Dirk K. (dekoepi)


Lesenswert?

Welchen Speicherbaustein verwendest du genau, dass man mal aufs 
Datenblatt gucken kann? Die SPI-Eproms, die ich kenne, machen in der 
Standardkonfiguration ein Auto-Inkrement der Adresse.
Edit: Grade gesehen, 24LC256, 
http://ww1.microchip.com/downloads/en/devicedoc/21203N.pdf - S. 11, 
Sequential Read. Da steht auch was, das man zwei Bytes lesen sollte, da 
das erste Rückgabe-Byte ein Control-Byte ist? Hab mir das nicht genauer 
angesehen, würde aber erstmal das Lupfen der Augenbraue bewirken.

Nach wie vor kommt das "ungefähr 5600 als Startadresse" (vielleicht mal 
etwas präziser werden könnte helfen!) recht gut mit dem abgeschnittenen 
65532 -> 5532 (respektive 65535->5535) hin. Wäre an dieser Stelle jedoch 
ein reiner Anzeigefehler, da die -3 nur beim PRINT erscheinen.

Der Code passt mit dieser Beschreibung nicht zusammen. Klassisch würde 
man 4 Bytes lesen, du liest und adressierst jedoch 2! Zusammen mit dem 
Control-Byte kommt da dann Quark zusammen. (Obwohl du das noch gar nicht 
moniert hast, sondern nur deine angezigte Adresse eigentlich falsch ist, 
mit eingegrenzter Ursache.) Ohne komische Verrenkungen zur Anzeige mit 
"-3" wäre auch gut. Und dann das saubere Warten auf die Rückgabe mit dem 
while() anstatt if(). Irgendwie ist da ein Durcheinander.

: Bearbeitet durch User
von Jobst M. (jobstens-de)


Lesenswert?

Du lässt Dir die Werte nach dem Schema

1 2 4 5 7 8 10 11 13 14 16 17 19 20 ...

ausgeben. Das hat weder mit 2 noch mit 4 zu tun.
In einem Schleifendurchlauf wird eepromaddresse 3x inkrementiert.
Was Du mit Deinem -3 da hast, ist nicht das Problem, sondern nur eine 
weitere Baustelle.


Gruß

Jobst

von c-hater (Gast)


Lesenswert?

Egon Mueller schrieb:

> Mit den Dreierschritten bzw. eepromadresse -3 ist das einfach: Zum
> Speichern der Meßwerte werden vier Speicherzellen benötigt.
> Beim Auslesen der Meßwerte werden diese vier Werte, aus denen nach
> Umrechnung zwei geworden sind, einer einzigen Eepromadresse zugeordnet,
> damit sie in einem Diagramm dargestellt werden können.

Das ist doch kompletter Schwachsinn.

Wenn vier Speicherzellen zum Speichern benötigt werden, muß man erstens 
auch tatsächlich genau vier schreiben und später auch genau vier lesen. 
Merkst du was? Eine drei kommt da sowas von absolut garnicht vor...

Wenn man nun diese vier Speicherzellen zusammenfassen will, dann ist ihr 
gemeinsames Merkmal die EEPROM-Addresse der ersten Zelle (das ist wohl 
das, was du versucht hast), dann ist aber nur jede vierte (und nicht 
dritte und schon garnicht jede) EEPROM-Addresse hierfür gültig.

Kurzfassung: Du solltest einfach C lernen. Und zwar, bevor du es 
verwendest...

von Joachim B. (jar)


Lesenswert?

c-hater schrieb:
> Wenn vier Speicherzellen zum Speichern benötigt werden, muß man erstens
> auch tatsächlich genau vier schreiben und später auch genau vier lesen.
> Merkst du was? Eine drei kommt da sowas von absolut garnicht vor...

auch wenn du c nicht magst, ich mag deine klaren Worte.

von Peter D. (peda)


Lesenswert?

Woher weißt Du überhaupt, daß der Fehler erst beim Lesen passiert?
Hast Du den EEPROM vor dem Einlöten programmiert?

von Egon M. (kpc)


Lesenswert?

Peter D. schrieb:
> Woher weißt Du überhaupt, daß der Fehler erst beim Lesen passiert?
> Hast Du den EEPROM vor dem Einlöten programmiert?

Ich habe es nicht eingelötet, es war ein Baustein, fix und fertig von 
DF-Robot geliefert und dazu habe ich die unter Arduino verfügbare lib 
verwendet (im Pgm. an #include <Wire.h> zu sehen). Da das Programm seit 
mindestens zwei Jahren problemlos die beiden Meßwerte und eine 
EEPROM-Adresse für die x-Achse (egal, welche, hauptsache immer z.B. die 
erste) ausgegeben hat, hatte ich bisher keinen Grund, heinzuschauen. 
Nachdem es nun nicht mehr funktioniert und nachdem, was ihr hier 
schreibt, sollte ich wohl die libs genauer betrachten und möglicherweise 
die I2C-Ansprache wieder von Hand programmieren, wie ich das früher bei 
nackten ATmegas tun mußte. Aber Arduino ist halt so schön bequem, da 
spart man sich viel Arbeit.

VG
Egon

von Egon M. (kpc)


Lesenswert?

Joachim B. schrieb:
> c-hater schrieb:
>> Wenn vier Speicherzellen zum Speichern benötigt werden, muß man erstens
>> auch tatsächlich genau vier schreiben und später auch genau vier lesen.
>> Merkst du was? Eine drei kommt da sowas von absolut garnicht vor...
>
So?
Angenommen, ein Speichervorgang beginne bei 100:
erstes Byte  Zelle 100
zweites Byte Zelle 101
drittes Byte Zelle 102
viertes Byte Zelle 103.

Ausgabe der Adresse für das erste Byte 103 - 3 = 100.

Mal abgesehen von einem Controlbyte, von dem dekoepi geschrieben hat, 
das ich ich kenne und daher nie berücksichtigt habe.

von Markus F. (mfro)


Lesenswert?

Frank L. schrieb:
>> wert = wert1 << 8 | wert2;
>
> Hi,
>
> kann so nicht funktionieren. Alle Variablen sind byte was soll nach
> einen <<8 in wert noch stehen?

Du solltest Dir dringend die Regeln für integer promotion nochmal 
durchlesen!

von Jobst M. (jobstens-de)


Lesenswert?

Egon M. schrieb:
> Angenommen, ein Speichervorgang beginne bei 100:
> erstes Byte  Zelle 100
> zweites Byte Zelle 101
> drittes Byte Zelle 102
> viertes Byte Zelle 103.
>
> Ausgabe der Adresse für das erste Byte 103 - 3 = 100.

Und was glaubst Du, wie es weiter geht?
Dein Code macht vermutlich nicht das, was Du glaubst/möchtest ...
(Ganz sicher dann nicht, wenn zwei Datensätze 2 oder 4 Bytes auseinander 
liegen)



Gruß

Jobst

von Egon M. (kpc)


Lesenswert?

Peter D. schrieb:
> Woher weißt Du überhaupt, daß der Fehler erst beim Lesen passiert?
>
Weiß ich nicht, aber ich finde die Schreiberei plausibel. Hier ist der 
Ausschnitt, wo in das EEPROM geschrieben wird:
1
      int Templuft = int (Lufttemp);     // Lufttemp ist float, muß zu int werden (umbenannt in Templuft)
2
      highluft = highByte(Templuft);     // damit es in low- und highbyte zerlegt werden kann (wg. des EEPROMs)
3
      lowluft = lowByte(Templuft);
4
  
5
           schreibEEPROM(eepromadresse,highluft);
6
           eepromadresse++;
7
           schreibEEPROM(eepromadresse,lowluft);
8
           eepromadresse++;

von Egon M. (kpc)


Lesenswert?

Jobst M. schrieb:
> Egon M. schrieb:
>> Angenommen, ein Speichervorgang beginne bei 100:
>> erstes Byte  Zelle 100
>> zweites Byte Zelle 101
>> drittes Byte Zelle 102
>> viertes Byte Zelle 103.
>>
>> Ausgabe der Adresse für das erste Byte 103 - 3 = 100.
>
> Und was glaubst Du, wie es weiter geht?

Ich hatte gehofft,beim nächsten Schreibzugriff
erstes Byte  Zelle 104
zweites Byte Zelle 105
drittes Byte Zelle 106
viertes Byte Zelle 107.

Verwendete Adresse 107 -3 = 104

Was spricht dagegen, welchen Abgrund gibt hier nun schon wieder?

Gruß
Egon

von Egon M. (kpc)


Lesenswert?

Markus F. schrieb:
> Frank L. schrieb:
>>> wert = wert1 << 8 | wert2;
>>
>> Hi,
>>
>> kann so nicht funktionieren. Alle Variablen sind byte was soll nach
>> einen <<8 in wert noch stehen?
>
> Du solltest Dir dringend die Regeln für integer promotion nochmal
> durchlesen!

Hi Markus,
meinst Du mich? Das wert1 << 8 ist lt. Arduino-Manual auch für 
byte-Variablen zulässig, und wert ist tatsächlich int, auch wenn es in 
dem gezeigten Programmschnipsel vielleicht untergegangen sein könnte.

Gruß
Egon

von c-hater (Gast)


Lesenswert?

Egon M. schrieb:

>            schreibEEPROM(eepromadresse,highluft);
>            eepromadresse++;
>            schreibEEPROM(eepromadresse,lowluft);
>            eepromadresse++;

Im Idealfall (keinerlei Fehlerbehandlung!!!) zwei Bytes geschrieben, OK. 
Aber es sollten doch angeblich vier pro Datensatz sein...

Und immer noch weit und breit keine Drei zu sehen...

von Jobst M. (jobstens-de)


Lesenswert?

Egon M. schrieb:
> Was spricht dagegen, welchen Abgrund gibt hier nun schon wieder?

Du zählst dafür nicht genug!

Vielleicht solltest Du Dir einfach mal die Adressen, anstelle der 
Inhalte ausgeben lassen!


Gruß

Jobst

von Markus F. (mfro)


Lesenswert?

Egon M. schrieb:
> Markus F. schrieb:
>> Frank L. schrieb:
>>>> wert = wert1 << 8 | wert2;
>>>
>>> Hi,
>>>
>>> kann so nicht funktionieren. Alle Variablen sind byte was soll nach
>>> einen <<8 in wert noch stehen?
>>
>> Du solltest Dir dringend die Regeln für integer promotion nochmal
>> durchlesen!
>
> Hi Markus,
> meinst Du mich? Das wert1 << 8 ist lt. Arduino-Manual auch für
> byte-Variablen zulässig, und wert ist tatsächlich int, auch wenn es in
> dem gezeigten Programmschnipsel vielleicht untergegangen sein könnte.
>
> Gruß
> Egon

Hallo Egon,

nein, ich mein' nicht dich. Frank L. (und genau den mein' ich) hat oben 
geschrieben, daß dein Code an der Stelle so nicht funktionieren würde, 
was natürlich - wie Du schon richtig bemerkt hast, aber mit Arduino nix 
zu tun hat - falsch ist.

Gruß,
Markus

von Egon M. (kpc)


Lesenswert?

Hallo,
wenigstens  e i n  Problem ist gelöst, das mit dem Offset. Ich wage kaum 
zu schreiben, welch primitiven Fehler das war:
wenn das Programm hochgeladen ist, muß man im Arduino-IDE anwählen: 
Werkzeuge - serieller Monitor, dann erfolgt die Ausgabe. Je langsamer 
man umschaltet, desto mehr von der Ausgabe ist schon durchgerauscht und 
auf dem Monitor nicht mehr zu sehen, sodaß man an einen geheimnisvollen 
Offset denkt.

Ich habe jetzt vor die Ausgaberoutine geschrieben: delay(5000), dann 
kann ich gemächlich auf den seriellen Monitor umschalten und verpasse 
nichts mehr.

Ich vermute, daß das bei neueren Arduino-IDE-Versionen geändert worden 
ist, denn früher konnte ich beobachten, daß die LED, die die Ausgabe 
begleitet, erst aufleuchtete, wenn der serielle Monitor angeklickt 
worden ist und deshalb ist von der Ausgabe nichts verloren gegangen. Bei 
der neueren IDE-Version leuchtet diese LED sofort. Oder es liegt an der 
anderen Hardware, früher lief es auf einem Iteaduine 2.2, jetzt auf 
einem Leonardo.

Also, nichts für ungut!

Gruß
Egon

von Dirk K. (dekoepi)


Lesenswert?

Leonardo macht keinen Reset bei Serial-Connect, die Beobachtung liegt an 
deinem Board.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.