Hallo!
Ich stehe hier gerade vor einem kleinen Problem und weiß nicht so recht
weiter und im Inet kann ich auch nicht so richtig was finden!
Ich habe eine Struktur:
1
structheizung
2
{
3
union
4
{
5
doublewert;
6
uint8_tbyte[4];
7
}Tag_temp;
8
9
union
10
{
11
doublewert;
12
uint8_tbyte[4];
13
}Nacht_temp;
14
15
union
16
{
17
doublewert;
18
uint8_tbyte[4];
19
}Manuell_temp;
20
21
unsignedcharaktiv;
22
unsignedcharZeit;
23
unsignedcharZeit_Tag[MAX_TIMERS];
24
unsignedcharZeit_Stunde[MAX_TIMERS];
25
unsignedcharZeit_Minute[MAX_TIMERS];
26
unsignedcharZeit_Wert[MAX_TIMERS];
27
unsignedcharanheizen;
28
};
diese möchte ich jetzt mit einer Schleife durch zählen und jedes Byte in
ein FRAM (ähnlich Eeprom) schreiben. Und das ganze muss man dann auch
wieder laden können und zurück in Struktur geben.
So wie stelle ich sowas am besten an und stimmt die Reihenfolge der
Bytes nach dem einlesen dann noch?
Ich hoffe mir kann einer helfen!
Danke
Gruß Denny
>So wie stelle ich sowas am besten an
Mit einem Pointer auf deine Struktur.
> und stimmt die Reihenfolge der>Bytes nach dem einlesen dann noch?
Wenn du es richtig machst stimmt es dann auch wieder.
Schau dir zum Thema "Welches element einer struct bekommt welchen Teil
des Speichers" nochmal ein paar Tuts an.
Ansonsten kann ich mich meinen Vorredner nur anschließen.
Hallo Denny,
ich würde AUF JEDEN FALL jedes Element einzeln lesen und schreiben (also
nicht einen byte * auf den Anfang setzen und bis sizeof (struct heizung)
kopieren.
Weil:
- ein Compiler kann überall Lücken einfüllen.
- ein Compiler kann alle Elemente des structs in beliebiger Reihenfolge
anordnen!
und am schlimmsten:
- die nächste Version den Compilers kann es komplett anders machen!
"Hilfe, ich habe mein Programm erneuert, und jetzt sind meine
gespeicherten Messwerte Müll!".
Am einfachsten kleine Lese- und Schreibroutinen für die elementaren
Datentypen schreiben und damit dann die einzelnen Elemente
transferieren.
Also z.B.
void WriteInt( unsigned eeprom_adresse, int wert);
Hallo!
@Wolfgang
Vielen Dank für die Hinweise. Dann werde ich es so lassen wie ich es
jetzt habe, da schreibe ich jede Variable einzeln. Ich dachte man könnte
es so ein wenig vereinfachen und schneller machen. Gerade weil in der
Struktur noch ein paar Arrays sind.
Danke
Denny
Ich finde die Antwort von Wolfgang ein wenig problematisch, wenn sie
auch sicherlich gut gemeint ist.
Das Problem ist, das ein Anfänger, weder das Ursprungsproblem wirklich
beurteilen kann, noch die Probleme die Wolfgang aufwirft beurteilen
kann.
Die einfachste Variante ist dann aber die mit dem gecasteten Zeiger, mit
dem der Inhalt unter Zuhilfename von sizeof kopiert oder weggeschrieben
wird.
1. Selbst wenn die struct nicht gepackt ist, werden allenfalls die
Lücken mitkopiert, aber sie schaden nicht. (pragma pack ist trotzdem
noch ein guter Tip).
2. Es ist zwar richtig, das ein Compiler die Strukturmitglieder beliebig
anordnen kann, aber er macht es bei ein und der selben Struktur immer
gleich. (Eigentlich habe ich bis jetzt nur Compiler gesehen, welche die
Elemente entsprechend der Reihenfolge in der Deklaration anordnen.
Selbst Optimierungen die sich aus einer anderen Reihenfolge ergeben
würden sah ich bis jetzt nicht). Wenn also die Reihenfolge bei dem
selben Compiler immer gleich ist, gibt es mit der Zeigermethode keine
Probleme.
Nichts desto trotz sind Wolfgangs Tips unter folgenden Bedingungen
relevant. Es wird ein anderer Prozessor mit anderer Wortbreite verwendet
oder der Compiler ist ein völlig anderer. Trifft eines von beidem zu
sollte man mal in das Map-File gucken. Dennoch wird mit grosser
Wahrscheinlichkeits nichts passieren.
Und die Methode von Wolfgang, die Elemente zu Fuss zu schreiben, ist
eigentlich die naheliegendste und sicherste. Der TO könnte das
vermutlich wissen, fragt aber dennoch. Man sollte mal fragen wieso
eigentlich.
An den TO der Tip: Schau Dir mal im Map-File an, wie die Struktur im
Speicher aussieht. Dann kannst Du beides beurteilen und weisst auch
warum der "Trick" (es ist eigentlich keiner) mit dem Zeiger
funktioniert.
Da Du schon mit unions arbeitest, sollte Dir die Idee mit einem
sozusagen überdeckendem anderen Datentyp bekannt sein.
Und wenn deine Struktur wirklich so aussieht und da nicht auch noch was
dazukommt, solltest du die Idee mit den union noch einmal überdenken.
Diese 3 union bringen nichts ausser Konfusion.
Also ich weise dem Double in der Union meine gemessene Temperatur zu und
dann schreibe ich aus dem Array die einzelnen Bytes in ein I2C Epprom.
Kann man das auch anders lösen?
Gruß Denny
> Wie kann man dann soetwas lösen mit den Unions?
Du nimmst den pointer auf dein struct, castest den auf byte* und
schreibst sizeof(heizung) Bytes ins EEPROM.
Solange du den compiler nicht wechselst, ist das kein Problem. Du darfst
aber optionen wie pack oder alignment nicht ändern.
Wenn du es "richtig" machen willst und alle Teile der struct einzeln
wegschreiben willst, wirds aufwendiger. Dann kannst du gleich noch ein
Versions-tag vornedran setzen falls später mal Erweiterungen zur struct
kommen.
Die unions hast du etwas misbraucht, die verwendet man zusammen mit z.B.
einem enum oder typ-Identifizierung um verschiedene Inhalte übereinander
zu legen und so Speicherplatz einzusparen. Für deinen Falls tut es ein
casting auf byte.
Gruß,
Nick
Über den double solltest du aich noch einmal nachdenken.
Ist es wirklich notwenidig, dir Temperatur auf 5 Nachkommastellen zu
halten. Ist es wirklich notwendig Temperaturen in der Größenordnung von
ein paar Millionen halten zu können?
Oder ist es nicht eher so, dass 1 Nachkommastelle mehr als ausreichend
ist? Kannst du überhaupt so genau messen?
Du könntest zb mit dir vereinbaren, dass dein Pgm die Temperatur in
Zehntelgrad speichert. Ein Wert von 231 wären dann 23.1 Grad. Dann ist
ein int völlig ausreichend.
> Oder ist es nicht eher so, dass 1 Nachkommastelle mehr als ausreichend> ist? Kannst du überhaupt so genau messen?>> Du könntest zb mit dir vereinbaren, dass dein Pgm die Temperatur in> Zehntelgrad speichert. Ein Wert von 231 wären dann 23.1 Grad. Dann ist> ein int völlig ausreichend.
Ja eine stelle nach dem Komma ist völlig ausreichend.
1
unsignedinttemp1;
2
3
temp1=(unsignedint)(temperatur*10);
Wäre das so richtig?
Hat einer mal ne Seite wo das mit dem Casten genau steht? Habe ich noch
nicht ganz verstanden.
Danke
Gruß Denny
> Hat einer mal ne Seite wo das mit dem Casten genau steht?
Das hast du doch schon gemacht.
"temp1 = (unsigned int)(temperatur * 10);"
Das (unsigned int) ist eines.
Allerdings in dem Zusammenhand flasch. Schreib einfach
temp1 = temperatur * 10. Darfst aber auch runden.
Gruß,
Nick
Dem Compiler ist nach C-Standard nicht erlaubt, struct-Mitglieder
umzusortieren. Sie müssen in der vorgegebenen Reihenfolge angeordnet
sein. Das Padding kann verhindert werden, indem das Attribut 'packed'
mitgegeben wird (bei WinAVR sind structs bereits implizit gepackt, wer
ganz sicher gehen will gegen zukünftige Änderungen, schreibt das
Attribut noch dazu). Somit ist es völlig OK, die struct byteweise
einzulesen und rauszuschreiben, solange man innerhalb derselben
Architektur bleibt.
Die Warnungen gegen ein Umordnen sind gut gemeint, aber nicht
zutreffend.
Hazeh Zimmerer schrieb:
> Dem Compiler ist nach C-Standard nicht erlaubt, struct-Mitglieder> umzusortieren. Sie müssen in der vorgegebenen Reihenfolge angeordnet> sein. Das Padding kann verhindert werden, indem das Attribut 'packed'
Kannst du mir das mit dem "packed" erklären und wo muss das hin?
> mitgegeben wird (bei WinAVR sind structs bereits implizit gepackt, wer> ganz sicher gehen will gegen zukünftige Änderungen, schreibt das> Attribut noch dazu). Somit ist es völlig OK, die struct byteweise> einzulesen und rauszuschreiben, solange man innerhalb derselben> Architektur bleibt.
Hättest du da mal ein Beispiel wie sowas gemacht wird?
Gruß Denny
In der Praxis kannst Du aber davon ausgehen, dass bei einer
8-Bit-Architektur Packen keinen Sinn hat, weil nie ein Padding gemacht
wird, und Dir dies sparen.
>> Somit ist es völlig OK, die struct byteweise>> einzulesen und rauszuschreiben, solange man innerhalb derselben>> Architektur bleibt.>> Hättest du da mal ein Beispiel wie sowas gemacht wird?
Korrektur: das schreibts an die Stelle ins EEProm, an der's auch im
SRAM steht, was natürlich sinnlos ist. Bei eeprom_write_byte gehört als
erstes Argument die EEProm-Adresse mit Postinkrement hin.
Im gcc-Tutorial gibt es da einen schönen Abschnitt darüber.
Padding ist natürlich grundsätzlich ein Thema. Allerdings ist es auf
einem AVR müssig darüber nachzudenken, weil es im gcc in diesem Fall
keines gibt.
Hallo!
Ich will ja nicht ins interne Epprom schreiben sondern in ein I2C Eeprom
und
da gibs leider solche Funktionen nicht!
Benutze dafür die Lib von Peter Fleury.
Karl heinz Buchegger schrieb:
> Man kann natürlich auch ganz einfach die>> eeprom_write_block und eeprom_read_block benutzen.
Klar. Allerdings wollte der Threadersteller ins FRAM schreiben, weshalb
ich ein anderes Beispiel gewählt habe.
Denny S. schrieb:
> Hallo!>> Ich will ja nicht ins interne Epprom schreiben sondern in ein I2C Eeprom> und> da gibs leider solche Funktionen nicht!> Benutze dafür die Lib von Peter Fleury.>>
1
>i2c_write(byte1);
2
>i2c_write(byte2);
3
>
>> Mal als Beispiel.
Ah. Entschuldigung. Der Thread ist schon etwas zu lang.
Also doch: Eine Schleife drüber.
Aber verpack dir die Block-Schreiberei/Leserei in eine eigene Funktion.
Kannst ja die eeprom_read_block als Vorbild dafür nehmen, wie die
Funktionssignatur aussehen könnte.
Hallo!
Ich habe das mit den Schleifen nun gemacht und geht auch FAST gut.
Ich benutze mehrere Structuren die ich nach ein ander einlese, aber bei
2 funktioniert es nicht richtig. Obwohl immer wieder die gleiche
Funktion aufgerufen wird.
Dort liest er falsche Werte ein!
Hier mal die Funktionen:
Ich habe das ja nach dem Beispiel oben im Thread gemacht.
Könnte es sein das es an der falschen Größe der Variablen liegt?
Sind Adressen immer uint8_t oder sollten sie nicht uint16_t sein?
Benutze ja ein Atmega2561 und der sollte mehr als 255 Adressen haben!
Gruß Denny
> Könnte es sein das es an der falschen Größe der Variablen liegt?> Sind Adressen immer uint8_t oder sollten sie nicht uint16_t sein?
In Deinem geposteten Code sehe ich nur eine Variable, die eine Adresse
beinhaltet:
1
>uint8_t*writepointer=(uint8_t*)&ZIMMER[z];
Die ist 16 Bit.
Dass sizeof(ZIMMER[z]) nie größer als 256 werden kann, hast Du schon
abgeklopft, nehme ich an. Hast Du auch abgeklopft, ob die Gesamtlänge
ins EEProm passt?