mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Speicherplatz Frage C & EEMEM


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Uwe K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin,

sehe ich das richtig, dass ich mit EEMEM, Speicher für den EEPROM 
alloziere und gleichzeitig diese Variablen auch als "normale" nutzen 
kann=
typedef struct
{
  enum 
  {
    IS_INIT,
    MES_MESZ,
    ALERT,
    ALERT_CYCLES,
    BRIGHT,
    SOUND_ENABLE,
    MOTOR_ENABLE,
    SYNC_HOUR,
    SYNC_MINUTE,
    AUTO_CHANGE_MINUTE,
    AUTO_CHANGE_SECOUND,
    
    DIMM_HOUR_ON,
    DIMM_HOUR_OFF,
    DIMM_MINUTE_ON,
    DIMM_MINUTE_OFF,
    
    ALERT_HOUR_I,
    ALERT_HOUR_II,
    ALERT_HOUR_III,
    ALERT_HOUR_IIII,
    ALERT_HOUR_IIIII,
    ALERT_HOUR_IIIIII,
    ALERT_HOUR_IIIIIII,
    ALERT_HOUR_IIIIIIII,
    
    ALERT_MINUTE_I,
    ALERT_MINUTE_II,
    ALERT_MINUTE_III,
    ALERT_MINUTE_IIII,
    ALERT_MINUTE_IIIII,
    ALERT_MINUTE_IIIIII,
    ALERT_MINUTE_IIIIIII,
    ALERT_MINUTE_IIIIIIII,
    
    DCF77_NUM_OF_RECORDS,
      
    SYSTEM_CONFIG,
      
    MAX_8_BYTE_ENTRYS,
  }byte8_entrys;
  
  uint8_t byte8[ MAX_8_BYTE_ENTRYS - 1 ];
  
}var_t; var_t eep EEMEM;

Autor: Falk B. (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Uwe K. (Gast)

>sehe ich das richtig, dass ich mit EEMEM, Speicher für den EEPROM
>alloziere

Ja.

> und gleichzeitig diese Variablen auch als "normale" nutzen
>kann=

Nö. Auf die EEPROM-Variablen, hier eep,  kann man nur mittels der 
eeprom_read/write Funktionen zugreifen. Das einzige, was man natürlich 
mehrfach wiederverwenden kann, ist deine Typdefinition var_t.

Autor: Peter D. (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Uwe K. schrieb:
> ALERT_MINUTE_IIIIIII,
>     ALERT_MINUTE_IIIIIIII,

Wer kommt denn auf sowas verrücktes. Den Code möchte ich nicht pflegen 
müssen.

Autor: M. K. (sylaina)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Wer kommt denn auf sowas verrücktes. Den Code möchte ich nicht pflegen
> müssen

Das hab ich mich auch grad gefragt, zumindest lateinische Nummerierung 
hätte ich hier in Verwendung, wahrscheinlicher aber arabische 
Nummerierung.

Autor: Arduino Fanboy D. (ufuf)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Wer kommt denn auf sowas verrücktes.

Ach da muss nur der "Sinn und Zweck" von Arrays nochmal verinnerlicht 
werden.

Es gibt noch viel zu lernen!
z.B. dass das durchnummerieren von Variablen, oder sonstigen 
Bezeichnern, böse ist.

: Bearbeitet durch User
Autor: M. K. (sylaina)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Arduino F. schrieb:
> Ach da muss nur der "Sinn und Zweck" von Arrays nochmal verinnerlicht
> werden.

Jetzt hör aber auf, das wird ja noch einfacher :D

Autor: Heiko L. (zer0)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gibt es diese Speicherklassen eigentlich in generalisierter Form oder 
nur, wenn ein entsprechendes EEPROM verbaut ist?
Oder anders: Kann man virtuelle Addressräume frei definieren?

Autor: Arduino Fanboy D. (ufuf)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Suchtipp: "avr gcc sections"

Autor: Heiko L. (zer0)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, Sections wären schon einmal nicht schlecht. Aber was, wenn z.B. das 
System eigentlich nur 16-bit Addressen unterstützt, man aber virtuell 
32-bit braucht?
Einfaches Beispiel: Man klemmt ein externes EEPROM mit 4Mbit an einen 
Attiny oder sowas. Die Addressen im EEPROM könnte man bequem den 
Compiler berechnen lassen, wenn man an 32-bit Addressen heran käme.

: Bearbeitet durch User
Autor: Arduino Fanboy D. (ufuf)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Soweit mir bekannt, wird das nicht gelingen.

Das einzige mir bekannte Mittel um was zu bauen ist sizeof() in 
Verbindung mit offsetof(). Aber einen größeren Wertebereich als size_t 
hat das auch nicht.

Autor: Heiko L. (zer0)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sowas befürchte ich auch. Einige AVR-Header für größere Chips besorgen 
sich aber in der Tat die längeren Addressen via &-Operator. Meine 
Vermutung war nun, dass das entweder gelingt, weil die Addressen erst 
beim Speichern in eine Variable geclamp'd oder gewrapped werden, oder es 
an einer speziellen Speicherklasse der Variablen liegt (siehe 
morepgmspace.h).
Mir ist an der Stelle das Konzept vom GCC nicht klar. Bei VC war so 
etwas eine Eigenschaft des Zeigertyps. "pointer to progmem_far" oder 
sowas kann logischerweise nur gelingen, wenn progmem_far definiert ist.
Ich muss das wohl bei Gelegenheit mal selbst austesten...

: Bearbeitet durch User
Autor: Uwe K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Uwe K. schrieb:
>> ALERT_MINUTE_IIIIIII,
>>     ALERT_MINUTE_IIIIIIII,
>
> Wer kommt denn auf sowas verrücktes. Den Code möchte ich nicht pflegen
> müssen.

Klär mich bitte auf. Wie würdest du das lösen?

Autor: NurEinGast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Für das menschliche Auge leichter zu unterscheiden wäre
ALERT_MINUTE_1
ALERT_MINUTE_2
ALERT_MINUTE_3
...
ALERT_MINUTE_7
ALERT_MINUTE_8

Wenn Du irgendwo mitten im Code ALERT_MINUTE_IIIIIII findest, muss man 
abzählen. Der Unterschied ALERT_MINUTE_IIIIIIII zu ALERT_MINUTE_IIIIIII 
ist nicht auf den ersten Blick zu erkenenn. Das ist Fehleranfällig.

Autor: HildeK (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Uwe K. schrieb:
> Klär mich bitte auf. Wie würdest du das lösen?

Na wenigsten so: ALERT_MINUTE_7 bzw. ALERT_MINUTE_8. Das ist schon mal 
um Faktor 1000 besser lesbar.

Autor: x^2 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es ist übrigens eine sehr mäßige Idee einen enum Typ zu nutzen, um eine 
solche Variable zu definieren. Der Grund ist, dass C dir die Größe einer 
enum Variable nicht garantiert. Es garantiert dir lediglich, dass alle 
Werte darin gespeichert werden können. Konkret könnte zum Beispiel 
uint8, uint16 oder uint32 verwendet werden. Dies kann sich sogar mit der 
Optimierungsstufe des Compilers ändern. Der GCC hat Flags womit du 
explizit die Größe von enum Variablen packen kannst.

Verändert sich irgendwas (Compiler, Optimierungsstufe, ...) kann so dein 
EEPROM Inhalt nicht mehr zur Variable passen, ohne dass das 
offensichtlich wäre.

Es ist auch keine gute Idee eine struct zu verwenden, da ein naives 
Lesen/Speichern a la

var_t x;
read_ee(0x1000, &x, sizeof(x));
write_ee(0x1000, &x, sizeof(x));

Annahmen über das Padding und Alignment in dieser Struktur macht.

Autor: HildeK (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
NurEinGast schrieb:
> Wenn Du irgendwo mitten im Code ALERT_MINUTE_IIIIIII findest, muss man
> abzählen.

Ja. Und wenn du mit dem Editor nach ALERT_MINUTE_II suchst, dann findet 
er auch ALERT_MINUTE_III, ALERT_MINUTE_IIII usw.

Autor: M. K. (sylaina)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Uwe K. schrieb:
> Klär mich bitte auf. Wie würdest du das lösen?

Besser wäre:
...
uint8_t ALERT_MINUTE_I;
uint8_t ALERT_MINUTE_II;
uint8_t ALERT_MINUTE_III;
uint8_t ALERT_MINUTE_IV;
...
Ist aber immer noch recht komplex lesbar (das ist lateinische/römische 
Nummerierung), daher wäre es noch besser arabische Zahlen zu benutzten:
...
uint8_t ALERT_MINUTE_1;
uint8_t ALERT_MINUTE_2;
...
Das ist noch besser lesbar, jedoch immer noch recht komplex 
automatisierbar (Programmierer sind ein recht schreibfaules Volk ;)) 
weshalb der ein und andere von uns wohl auf die Idee käme, es so zu 
definieren:
...
uint8_t ALERT_MINUTE[8];
...
Da könnte man z.B. mit ner for-Schleife ruck-zuck alle Werte durchgehen, 
auslesen, verändern, etc.pp.

: Bearbeitet durch User
Autor: Uwe K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
x^2 schrieb:
> Annahmen über das Padding und Alignment in dieser Struktur macht.

Das heißt?

Autor: M. K. (sylaina)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Uwe K. schrieb:
> Das heißt?

Dass man schon beim Coden davon ausgeht, wie der Compiler den ganzen 
Kladeradatsch im Speicher anlegen werden wird. Das kann Probleme machen 
wenn man sich verschätzt hat, eine andere Optimierungsfunktion des 
Compilers wählt, den Datensatz erweitern will usw.

Autor: Uwe K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
M. K. schrieb:
> Uwe K. schrieb:
>> Das heißt?
>
> Dass man schon beim Coden davon ausgeht, wie der Compiler den ganzen
> Kladeradatsch im Speicher anlegen werden wird. Das kann Probleme machen
> wenn man sich verschätzt hat, eine andere Optimierungsfunktion des
> Compilers wählt, den Datensatz erweitern will usw.
typedef enum
{
  SYNC_ERROR_CNT,
  SYNC_SUCCESS_CNT,
  
  MAX_BYTE16_ENTRYS,  
}bit16_enum;

uint16_t arr[MAX_BYTE16_ENTRYS-1];

Was kann der Kompilert dort anders machen mit einer anderen 
Kompilierungsstufe?

Wenn ich mich auf die Byte Reihenfolge nicht verlassen kann..

Autor: x^2 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Uwe K. schrieb:
> typedef enum
> {
>   SYNC_ERROR_CNT,
>   SYNC_SUCCESS_CNT,
>
>   MAX_BYTE16_ENTRYS,
> }bit16_enum;
>
> uint16_t arr[MAX_BYTE16_ENTRYS-1];
>
> Was kann der Kompilert dort anders machen mit einer anderen
> Kompilierungsstufe?
>
> Wenn ich mich auf die Byte Reihenfolge nicht verlassen kann..

In deinem ursprünglichen Beitrag hattest du ein Struktur-Member mit 
einem enum Typ. Jetzt steht hier nur noch ein typedef (in einem 
struct??). Sagen wir du hättest das hier:
struct
{
   bit16_enum type;
   uint8_t byte[MAX_8_BYTE_ENTRYS - 1];
}

Dein Compiler könnte z.B. folgendes machen:
[type_0][byte:0][byte:1][...]
[type_0][type_1][byte:0][byte:1][...]
[type_0][type_1][type_2][type_3][byte:0][byte:1][...]

Mit O0 könnte er (auf einer 32-bit architektur) 32-bit enums machen 
(letztere Variante) und für Os das enum packen und erstere Variante 
nehmen. In deinem EEPROM steht dann letzere Variante. Und dein Os Code 
lädst dann type_1 in byte:0

Autor: x^2 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schau dir z.B. beim GCC mal "-fshort-enums" an:

https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html

Damit kannst du explizit enums packen lassen.

Autor: Uwe K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

enum bit16_enum
{
  SYNC_ERROR_CNT,
  SYNC_SUCCESS_CNT,
  
  MAX_BYTE16_ENTRYS,  
};

/*
*  Fall 1.: Hier wird in der Struktur "enum" verwendet..
*/
typedef struct  
{  
  enum bit16_enum  bit16Desc;
  uint16_t byte16[ MAX_BYTE16_ENTRYS - 1 ];
}error_t; error_t err; error_t erreep EEMEM;



typedef enum
{
  SYNC_ERROR_CNT,
  SYNC_SUCCESS_CNT,
  
  MAX_BYTE16_ENTRYS,  
}bit16_t;

/*
*  Fall 2.: Hier wird in der Struktur mit einem Datentyp gearbeitet..
*/
typedef struct  
{  
  bit16_t  bit16Desc;
  uint16_t byte16[ MAX_BYTE16_ENTRYS - 1 ];
}error_t; error_t err; error_t erreep EEMEM;

Wo ist der Unterschied? Gibt es einen?

Autor: Uwe K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sollte man "enums" lieber nicht als Member einer Struktur mitgeben?

Autor: Ichkriegmich Nichtmehr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Faszinierend.

Eine Variable mit <byte16> zu benennen grenzt schon
wahrlich an Genialität.

Autor: x^2 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Uwe K. schrieb:
> Sollte man "enums" lieber nicht als Member einer Struktur
> mitgeben?

Ja. Zumindest dann nicht, wenn die Größe aus irgend einem Grund eine 
Rolle spielt. Ich tendiere dazu immer Typen fester Breite zu nehmen und 
mit enums nur dazu passende Konstanten.

Autor: Uwe K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ichkriegmich Nichtmehr schrieb:
> Faszinierend.
>
> Eine Variable mit <byte16> zu benennen grenzt schon
> wahrlich an Genialität.

Stimmt schon. Da muss ich noch dran feilen.

Autor: Uwe K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
x^2 schrieb:
> Uwe K. schrieb:
>> Sollte man "enums" lieber nicht als Member einer Struktur
>> mitgeben?
>
> Ja. Zumindest dann nicht, wenn die Größe aus irgend einem Grund eine
> Rolle spielt. Ich tendiere dazu immer Typen fester Breite zu nehmen und
> mit enums nur dazu passende Konstanten.

In meinem Fall, sollten die "enums" einfach nur den Index der aktuell 
benötigen Variable "ersichtlicher" machen.

Die enums sind ja in diesem Fall auch konstant.

Autor: M. K. (sylaina)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Uwe K. schrieb:
> Die enums sind ja in diesem Fall auch konstant.

Wann sind sie das denn nicht?

Autor: Peter D. (peda)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Enums sind immer vom Typ int, d.h. je nach Architektur signed 16 oder 32 
Bit. Daher ist enum als Typangabe zwar zulässig, aber ungebräuchlich.

Unter c sind Enums einfach nur eine anderer Schreibweise für 
fortlaufende Defines, d.h. sie schränken nicht den Wertebereich von 
Variablen ein.
Z.B.:
enum Wochentag{SO, MO, DI, MI, DO, FR, SA}
heute, gestern;

int i;

void test(void)
{
  heute = SA;
  gestern = -1000;
  i = MI;
}

: Bearbeitet durch User

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.