Hallo, ich habe einen EEPROM 24C08 mit 8KB Speicher. Auf den beabsichtige Messwerte abzulegen. Zum Beispiel folgendermaßen: Datum Zeit Temp. 11.05.13 20:10 +25 Das Datum besteht aus drei 8Bit Int. Die Zeit aus zwei 8Bit Int. Die Temp. ist in einen 16Bit Int abgelegt. Wenn ich jetzt einen Datensatz speichern möchte, dann addiere ich doch lediglich die Größe der Datentypen. 3 Byte + 2 Byte + 2 Byte = 7 Byte Also hab ich 7 Byte für einen Datensatz. Bei 8k Speicher (also 8192 Byte) könnte ich 1170 x 7 Datensätze speichern? Ist das so richtig?
Daniel schrieb: > ich habe einen EEPROM 24C08 mit 8KB Speicher Das ist ein Missverständnis. Das EEPROM 24C08 verfügt über 8 kBit Speicher, mithin also 1 kByte. 8kByte hat z.B. das 24C64 EEPROM.
Ohhh danke. Da hab ich wohl wirklich was falsch verstanden. Also 1024 Bit / 7 Bit = 146 Datensätze?
Daniel schrieb: > Also 1024 > Bit / 7 Bit = 146 Datensätze? Das Ergebnis ist richtig, aber du hast dich von den Bits und Bytes verwirren lassen :-) 1024 Bytes hat das EEPROM, 7 Byte dein Datensatz, sind also 146 Datensätze. Du könntest pro Datensatz ein Byte sparen, indem du eine Art UNIX Zeit (4 Bytes) einführst.
Danke Matthias :) Genau Byte und nicht Bit. Jetzt war ich total durcheinander. Ich hab da noch eine Frage zur Geräteadresse. /AT24C08A, 8K SERIAL EEPROM: Internally organized with 64 pages of 16 bytes each, the 8K requires a 10-bit data word address for random word addressing. / Device Addressing: //The 8K EEPROM only uses the A2 device address bit with the next 2 bits being for memory page addressing. The A2 bit must compare to its corresponding hard-wired input pin. The A1 and A0 pins are no connect.// Device Adress: 1 0 1 0 A2 P1 P0 R/W Mit P1 und P0 wähle ich die entsprechenden Pages (64 Stück gesamt) aus, in die ich dann jeweils 16 Byte schreiben kann? Das heißt doch aber je nachdem welchen Speicherbereich ich ansprechen möchte, muss ich die Deviceaddress ändern?
Daniel schrieb: > Mit P1 und P0 wähle ich die entsprechenden Pages (64 Stück gesamt) aus Nö, du kannst mit P1 und P0 doch maximal 4 Pages auswählen. Das ist aber korrekt, denn im darauffolgenden Byte wird die Adresse innerhalb der Page ausgewählt. Das haben die Jungs gemacht, damit das so kompatibel wie möglich zu den kleineren 24C02 und 24C04 ist. Daniel schrieb: > Das heißt doch aber je > nachdem welchen Speicherbereich ich ansprechen möchte, muss ich die > Deviceaddress ändern? So isses. Page 0 würdest du also mit 0xA0 zum schreiben addressieren (wenn der Adresspin auf Masse liegt) und mit 0xA1 zum Lesen. Page 3 wäre also 0xA6/0xA7. Bei Adresspin auf Vcc entsprechend 0xA8/0xA9 für Page 0 und 0xAE/0xAF für Page 3.
Mit dem Adresspin meinst du A2? Kann ich dann nur zwei von denn 8K EEPROMS an einen Bus betreiben? Weil die ersten 4 Bit sind ja fest mit 0xA und danach wähle ich doch nur mit A2 die Adresse aus wie ich es verstehe. Page 0 entweder mit 10100000 = 0xA0 z.B. EEPROM 1 oder 10101000 = 0xA8 z.B. EEPROM 2
Daniel schrieb: > Mit dem Adresspin meinst du A2? Kann ich dann nur zwei von denn 8K > EEPROMS an einen Bus betreiben? Volltreffer, mehr als zwei von den Dingern gäben Adresskonflikte.
Danke dir. Ich melde mich später nochmal wenn ich Probleme beim beschreiben oder lesen bekomme.
So ganz hab ich es noch verstanden, wenn ich mit P1 und P0 nur 4 Pages ansteuere. Im Datenblatt steht doch 64 Pages of 16 bytes? Hab mir mal einen Bsp Code von Peter Fleury für einen 24C02 herausgesucht. Wenn ich mit der dort angegebenen Adresse von 0xA2 für meinen 24C08 arbeite, dann schreibe ich auf die Page 1 des Speichers. Wieviel Bytes kann ich dann schreiben bis ich die Adresse so ändern müsste, dass ich auf Page 2 schreibe? Der Speicher hat 1024 Bytes. Mit P1 und P0 lassen sich diese in 4 x 256 Byte teilen. Page Device Address Speicherbereich Adressbereich 1 --> 1010 0000 --> 256 byte --> 0x00-0xFF 2 --> 1010 0010 --> 256 byte --> 0x00-0xFF 3 --> 1010 0100 --> 256 byte --> 0x00-0xFF 4 --> 1010 0110 --> 256 byte --> 0x00-0xFF Das heißt wenn ich meine Datensätze fortlang schreiben will muss ich die deviceaddress mit ändern. Bsp. Beginnend mit 1010 0000 (device) kann ich danach 0x00 - 0xFF beschreiben. Wenn ich bei 0xFF angekommen bin, muss ich auf 1010 0010 (device) wechseln, da mir sonst wahrscheinlich die Page 1 wieder überschrieben würde. Gibt es keine Möglichkeit den Speicher von vorne bis hinten forlaufend zu beschreiben? Wenn ich jetzt meine Datensätze ablege, muss ich ja eine Funktion schreiben, die ständig darauf achtet, welche Page ich gerade bin und das ich nicht über 0xFF hinauskomme. Bei 7 byte für einen Datensatz, kann ich dann gerade 36 Sätze in eine Page schreiben (36 * 7 = 252), wobei die letzten 4 byte ungenutzt blieben.
Daniel schrieb: > Im Datenblatt steht doch 64 Pages of 16 bytes? Das bezieht sich auf den 'Page Write' Modus. Hier gilt tatsächlich, das eine Page 16 Bytes gross ist. Im Datenblatt werden P0 und P1 als 'Blockaddress' bezeichnet. Und 4 Blöcke à 256 Bytes sind ja auch genau 1024 Bytes. Da dein Datensatz 7 Bytes lang ist, und immer die Gefahr besteht, versehentlich eine Page Grenze zu überschreiten, kommt für dich sowieso nur Byte Write und Byte Read in Frage. Übrigens gibt es gerade beim 24C08 erhebliche Unterschiede sowohl in der Pinbelegung als auch in der Art und Weise des Schreibens zwischen den Herstellern. Es wird also Zeit, zu wissen, wessen Produkt du da verwendest. Das Zusammenbasteln der absoluten Adresse ist übrigens nicht so schwierig. Wenn deine Speicheradresse als word (16-bit) vorliegt, kannst du mit ein bisschen Schieben und Verodern das gut in den Griff kriegen. Welche Programmiersprache wird benutzt?
> Das Zusammenbasteln der absoluten Adresse ist übrigens nicht so > schwierig. Und wenn Page Write sowieso uninteressant ist, dann ist der Rest meist einfach nur eine Frage, wie man vom Adressbuss an die Pins des EEPROM geht. Dann muss man sich im Grunde überhaupt nicht mehr um diese Page Sache kümmern sondern gibt die Adressen einfach so aus wie sie sind. D.h. du kannst die ganze Sache mit den Pages einfach ignorieren. Niemand schreibt dir vor, dass das was du im Programm als "Adressbit 2" ansiehst, auch tatsächlich am Pin A2 beim EEPROM rauskommen muss. D.h. indem du dir das EEPROM geschickt an die Ausgangspins ankabelst, kannst du dafür sorgen, dass für dein Programm sich das EEPROM einfach wie eine durchgehende Speicherfläche präsentiert, ohne Schnickschnack.
:
Wiederhergestellt durch User
Ich hab meine Temp. auf 8 Bit reduziert. Eine Genauigkeit von 1°C reicht mir erstmal aus. Dann könnte ich doch so meinen ersten Datensatz in die ersten 256 byte folgendermaßen schreiben. Nutze die Peter Fleury Lib für IIC.
1 | #define Dev24C02 0xA0
|
2 | |
3 | void eepromSchreiben(int8_t date, int8_t month, int8_t years, int8_t hours, int8_t minutes, int8_t temp){ |
4 | |
5 | i2c_start(Dev24C02+I2C_WRITE); |
6 | i2c_write(0x00); //Schreibe ab Startadresse |
7 | i2c_write(date); |
8 | i2c_write(months); |
9 | i2c_write(years); |
10 | i2c_write(hours); |
11 | i2c_write(minutes); |
12 | i2c_write(temp); |
13 | i2c_stop(); |
14 | }
|
15 | |
16 | int main(void){ |
17 | int8_t date; |
18 | int8_t month; |
19 | int8_t years; |
20 | int8_t hours; |
21 | int8_t minutes; |
22 | int8_t temp; |
23 | |
24 | eepromSchreiben(date, month, years, hours, minutes, temp); |
25 | }
|
Wenn ich den nächsten Datensatz schreiben will, muss ich doch die Startadresse ändern. Ich möchte ja forlaufend schreiben. Muss ich mir jetzt noch eine Var generieren in der ich die letzte Speicheradresse ablege? @ Karl Heinz: Danke ich versuche das PageWrite zu ignorieren. So ganz habe ich deinen Post aber nicht verstanden.
Und ich muss mich korrigieren. Die i2c_write von Fleury erwartet ein unsigned char. Damit würde ich bei der temp Probleme bekommen, für den Fall das wir negative Temp haben.
Daniel schrieb: > @ Karl Heinz: Danke ich versuche das PageWrite zu ignorieren. So ganz > habe ich deinen Post aber nicht verstanden. Vergiss es bitte. Da hab ich mich ordentlich verhaut. Das ist ja ein I2C EEPROM. Daran hatte ich gar nicht mehr gedacht.
Ist meine Funktion zum Beschreiben denn richtig? Ich hab es gerade getestet und eigentlich sollte die richtig sein. Wo ich halt Probleme sehe ist bei den Temperaturen. Ich versteh die Fleurylib im Detail nicht und nutze nur seine Funktionen. Das i2c_write ein unsigned char erwartet macht mir aber Probleme wenn ich negative Temp haben.
Daniel schrieb: > Die i2c_write von Fleury erwartet ein unsigned char. Damit würde ich bei > der temp Probleme bekommen, für den Fall das wir negative Temp haben. Ignorier das einfach. Ob das Byte signed oder ein unsigned ist, ändert nichts an seinem Wert. Nur DU musst wissen, was es ist und es passend interpretieren.
Georg G. schrieb: > Ignorier das einfach. Ob das Byte signed oder ein unsigned ist, ändert > nichts an seinem Wert. Nur DU musst wissen, was es ist und es passend > interpretieren. Das klappt wunderbar. Danke. Versteh das zwar nicht ganz, weil int8_t -128 - 128 unsigned char 0 - 255 Die Größe beider Typen ist gleich. Dachte wenn das Byte per iic übertragen wird, das es schon eine Rolle spielt was für ein Datentyp ich hab. Ein Problem hab ich allerdings noch. Wenn ich jetzt den zweiten Datensatz speichern will, muss ich doch die Startadresse zum schreiben ändern. Muss ich mir dafür eine Variable erstellen, die permanten schaut bis wohin ich den Speicher bereits beschrieben habe?
Daniel schrieb: > Die Größe beider Typen ist gleich. Dachte wenn das Byte per iic > übertragen wird, das es schon eine Rolle spielt was für ein Datentyp ich > hab. Es sind in beiden Fällen 8 Nullen oder Einsen. Du kannst es als Zahl mit oder ohne Vorzeichen interpretieren oder als Schriftzeichen oder als... > Ein Problem hab ich allerdings noch. Wenn ich jetzt den zweiten > Datensatz speichern will, muss ich doch die Startadresse zum schreiben > ändern. Muss ich mir dafür eine Variable erstellen, die permanten schaut > bis wohin ich den Speicher bereits beschrieben habe? Das empfiehlt sich.
Daniel schrieb: > Georg G. schrieb: >> Ignorier das einfach. Ob das Byte signed oder ein unsigned ist, ändert >> nichts an seinem Wert. Nur DU musst wissen, was es ist und es passend >> interpretieren. > > Das klappt wunderbar. Danke. Versteh das zwar nicht ganz, weil > > int8_t -128 - 128 > unsigned char 0 - 255 Das macht aber nichts. Denn 8 Bit sind 8 Bit. Ob man da dann 1 Bit als Vorzeichenanzeiger interpretiert oder nicht, ist eine reine Frage der Interpretation des Bytes. Für I2C spielt diese Ebene keine Rolle mehr, da werden nur noch Bytes transportiert. > Die Größe beider Typen ist gleich. Eben. > Dachte wenn das Byte per iic > übertragen wird, das es schon eine Rolle spielt was für ein Datentyp ich > hab. Ja, ob er aus 1 Byte besteht, oder 2 Bytes oder 4 oder .... Aber was logisch gesehen hinter diesen Bytes steht, das interessiert auf dieser Ebene nicht mehr. Byte ist Byte. > Ein Problem hab ich allerdings noch. Wenn ich jetzt den zweiten > Datensatz speichern will, muss ich doch die Startadresse zum schreiben > ändern. Muss ich mir dafür eine Variable erstellen, die permanten schaut > bis wohin ich den Speicher bereits beschrieben habe? Ja. Darauf wird es wohl hinauslaufen. Von nichts kommt nichts. Information die du nicht hast, musst du dir entweder irgendwoher besorgen oder eben selber speichern. Das EEPROM kannst du nicht befragen. Den für das EEPROM ist jedes Byte wie jedes andere Byte. Du schreibst an irgendeine Adresse, du liest von irgendeiner Adresse. Mehr interessiert das EEPROM nicht.
Karl Heinz Buchegger schrieb: > Ja. Darauf wird es wohl hinauslaufen. Von nichts kommt nichts. > Information die du nicht hast, musst du dir entweder irgendwoher > besorgen oder eben selber speichern. Das EEPROM kannst du nicht > befragen. Den für das EEPROM ist jedes Byte wie jedes andere Byte. Du > schreibst an irgendeine Adresse, du liest von irgendeiner Adresse. Mehr > interessiert das EEPROM nicht. Ok. Ich hatte mir überlegt, dass ich nach jedem Speichervorgang (nach 6 Byte) im nächsten Byte die Adresse ablege. Das nützt mir ja aber auch nichts weil ich ja wieder wissen müsste wo ich lesen muss um die auszulesen. Das heißt ich erstelle eine Var der ich die Speicheradresse für den nächsten Schreibvorgang mitteile. Damit fahre ich im normalen Betrieb gut. Fällt mal die Spannung weg (Batteriewechsel) dann muss ich die ganzen Datensätze von Adresse 0x00 wieder von vorne auslesen. Oder hat jemand eine andere Idee?
Daniel schrieb: > Oder hat jemand eine andere Idee? Du kannsz ja auch die zuletzt benutzte Adresse im EEPROM an einer bestimmten, immer gleichen Speicheradresse ablegen :-)
Karl Heinz Buchegger schrieb: > Du kannsz ja auch die zuletzt benutzte Adresse im EEPROM an einer > bestimmten, immer gleichen Speicheradresse ablegen :-) :D Sehr gute Idee :) Dann mach ich das mal. Danke dir. Kannst du mir vielleicht sagen ob es wesentlich schwieriger und aufwendiger ist eine SD Karte zu beschreiben im Vergleich zum EEPROM?
Die Adresse einen beliebigen Datensatzes N ergibt sich doch aus Datensatzadresse = Startadresse + (Datensatzlänge * N). Da das EEPROM immer bei Adresse 0 anfängt, ist z.B. die Startadresse des Datensatzes 42 also 42*6 = 252. Daniel schrieb: > Kannst du mir vielleicht sagen ob es wesentlich schwieriger und > aufwendiger ist eine SD Karte zu beschreiben im Vergleich zum EEPROM? Ja isses, allerdings gibts da auch Bibliotheken. Wenn du allerdings mit dem kleinen EEPROM Schwierigkeiten hast, wachsen die mit der SD Karte eher noch.
Daniel schrieb: > Kannst du mir vielleicht sagen ob es wesentlich schwieriger und > aufwendiger ist eine SD Karte zu beschreiben im Vergleich zum EEPROM? Ein bisschen schon, ja. Wenn du mehr Speicherplatz willst gibt es EEPROMs aber auch idr. mit bis zu 1Mbit.
Matthias Sch. schrieb: > Die Adresse einen beliebigen Datensatzes N ergibt sich doch aus > Datensatzadresse = Startadresse + (Datensatzlänge * N). Da das EEPROM > immer bei Adresse 0 anfängt, ist z.B. die Startadresse des Datensatzes > 42 also 42*6 = 252. Genau. Aber woher weiß der Controller welchen Datensatz ich gerade schreiben will? Ich muss eine Var mitzählen lassen. Und wenn ich jetzt die Batterien wechseln muss? Dann ist der Wert der Var weg und da bietet es sich doch an die Startadresse im eeprom abzulegen, oder nicht?
Daniel schrieb: > Und wenn ich jetzt die Batterien wechseln muss? Dann ist der Wert der > Var weg und da bietet es sich doch an die Startadresse im eeprom > abzulegen, oder nicht? Aber aufpassen. Welches ist die größte Adresse die vorkommen kann? Passt die in 1 Byte? Welches ist die größte Datensatznummer, die vorkommen kann? Passt die in 1 Byte? Was ist aufwändiger zu schreiben: 1 Byte oder 2 Bytes? Was ist daher einfacher in der Handhabung, wenn man rein nur rechnet, dass die Information ja auch geschrieben und gelesen werden muss?
Gelöschte Werte sind bei EEPROMs immer 0xFF, was ein ungültiger Datensatz ist. Wenn du also eine Page löschst, bevor du sie anfängst zu beschreiben und immer nur in eine Richtung Datensätze anhängst, kannst du beim Start des Programms diese Variable ausrechnen (d.h. den ersten ungültigen Datensatz im EEPROM finden).
Eine andere Strategie wäre, immer einen Datensatz zu schreiben und das darauf folgende Byte(das wäre ja der Platz für den nächsten Datensatz) mit 0xFF zu beschreiben. Man ist dann unabhängig vom Page löschen und kann das EEPROM wie einen Ringbuffer behandeln, indem zumindest 169 Datensätze gültig sind.
Ich komm momentan nicht weiter. Will den Speicher der ersten 256 Byte löschen und überall eine 1 reinschreiben. Dazu habe ich die folgenden Funktionen. Man kann es auch mit einer machen.
1 | void deleteEeprom(uint8_t adress){ |
2 | i2c_start(Dev24C08+I2C_WRITE); |
3 | i2c_write(adress); |
4 | i2c_write(0x01); |
5 | i2c_stop(); |
6 | }
|
7 | |
8 | |
9 | void SpeicherDel(){ |
10 | int temp; |
11 | char tempC[3]; |
12 | |
13 | |
14 | for(uint8_t i = 0; i <= 254; i++){ |
15 | deleteEeprom(i); |
16 | sprintf(tempC,"%d", i); |
17 | lcd_setcursor(0,2); |
18 | lcd_string(tempC); |
19 | }
|
Wenn ich nun den Speicher probeweise auslese, haben nicht alle Bytes einen Wert von 1. Ich weiß nicht mehr weiter. Die Ausgabe für den folgenden Code lautet 01.18.01 04:01 Z.B. ab 0x02
1 | void History() |
2 | {
|
3 | int8_t minutes = 0; |
4 | int8_t hours = 0; |
5 | int8_t date = 0; |
6 | int8_t months = 0; |
7 | int8_t years = 0; |
8 | int8_t temp = 0; |
9 | |
10 | char minutesChar[4]; |
11 | char hoursChar[4]; |
12 | char dayChar[3]; |
13 | char dateChar[4]; |
14 | char monthsChar[4]; |
15 | char yearsChar[5]; |
16 | |
17 | i2c_start_wait(Dev24C08+I2C_WRITE); |
18 | i2c_write(0x02); |
19 | i2c_rep_start(Dev24C08+I2C_READ); |
20 | date = i2c_readAck(); |
21 | months = i2c_readAck(); |
22 | years = i2c_readAck(); |
23 | hours = i2c_readAck(); |
24 | minutes = i2c_readNak(); |
25 | i2c_stop(); |
26 | |
27 | //LCD Aufbereitung Zeit;
|
28 | sprintf(minutesChar, "%02d", minutes); |
29 | sprintf(hoursChar, "%02d", hours); |
30 | //LCD Aufbereitung Datum
|
31 | sprintf(dateChar, "%02d", date); |
32 | sprintf(monthsChar, "%02d", months); |
33 | sprintf(yearsChar, "%02d", years); |
34 | |
35 | lcd_setcursor(0,0); |
36 | lcd_string(dateChar); |
37 | lcd_string("."); |
38 | lcd_string(monthsChar); |
39 | lcd_string("."); |
40 | lcd_string(yearsChar); |
41 | |
42 | lcd_setcursor(10,0); |
43 | lcd_string(hoursChar); |
44 | lcd_string(":"); |
45 | lcd_string(minutesChar); |
Matthias Sch. schrieb: > Eine andere Strategie wäre, immer einen Datensatz zu schreiben und das > darauf folgende Byte(das wäre ja der Platz für den nächsten Datensatz) > mit 0xFF zu beschreiben. Eine 0xFF zu schreiben, heißt zu löschen (oder man kann es gleich bleiben lassen).
Fehler gefunden. Ich muss auch etwas warten, bis der eeprom zu Ende geschrieben hat. i2c_start_wait()
Michael A. schrieb: > Matthias Sch. schrieb: >> Eine andere Strategie wäre, immer einen Datensatz zu schreiben und das >> darauf folgende Byte(das wäre ja der Platz für den nächsten Datensatz) >> mit 0xFF zu beschreiben. > > Eine 0xFF zu schreiben, heißt zu löschen (oder man kann es gleich > bleiben lassen). Gut erkannt. Hättest du die Diskussion verfolgt, wüsstest du allerdings, das wir uns überlegt haben, wie man am besten den nächsten freien Datensatz findet. Dazu gab es eben die Ansätze des Page-löschens und mein Vorschlag, nur den auf den aktuellen Datensatz folgenden mit dem 0xFF als frei zu markieren. Lies es einfach nochmal. Es ging hier ja nicht darum, einen frischen EEPROM zu beschreiben, sondern ihn als Ringbuffer zu benutzen.
Matthias Sch. schrieb: > Dazu gab es eben die Ansätze des Page-löschens und > mein Vorschlag, nur den auf den aktuellen Datensatz folgenden mit dem > 0xFF als frei zu markieren. Man kann bei einem EEPROM ein Byte nicht mit 0xFF beschreiben. Beim Schreiben im EEPROM werden nur Nullen geschrieben. Die Einsen entstehen durchs Löschen.
Michael A. schrieb: > Man kann bei einem EEPROM ein Byte nicht mit 0xFF beschreiben. Beim > Schreiben im EEPROM werden nur Nullen geschrieben. Die Einsen entstehen > durchs Löschen. Du verwechselt das mit EPROM - die Dinger mit Quarzglasfenstern und so. Eine EEPROM Zelle (Lies den Threadtitel - es geht um ein I2C EEPROM) wird zwar vor dem Schreiben auch gelöscht, lässt sich aber dann mit jedem beliebigen Wert beschreiben, solange er in ein Byte passt.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.