Forum: Mikrocontroller und Digitale Elektronik EEProm-Adressen mit Präprozessor generieren


von Der M. (steinadler)


Lesenswert?

Hallo zusammen,

ich möchte für ein Projekt eine Header-Datei mit ca 50 EEprom-Adressen 
anlegen.

Gibt es eine Möglichkeit das mit dem Präprozessor zu machen?
Ich weiß net, wie ich den zum Rechnen bewegen soll

von Peter D. (peda)


Lesenswert?

Micha R. wrote:
> ich möchte für ein Projekt eine Header-Datei mit ca 50 EEprom-Adressen
> anlegen.

Was könnte der Fragesteller damit bloß gemeint haben ???


In einer Headerdatei wird nichts angelegt und Adressen schonmal 
garnicht.

Anlegen kann man nur Funktionen und Variablen, das macht man in einem 
Object (C-Source).
Ein Objekt kann dann der Linker an eine bestimmte Adresse linken, wenn 
man es wünscht.
Sonst legt er es an, wo Platz ist.


Peter

von Der M. (steinadler)


Lesenswert?

Nein Peter, so mein ich es nicht.

In der Datei soll nur sowas stehen, wie:
1
#define adresse1    0x0000
2
#define adresse2    0x0002
3
#define abc         0x00010

Ich wollte allerdings die Adressen zur Kompilierzeit automatisch 
erstellen lassen, so, dass ich ohne Probleme die Speichergröße ändern, 
bzw. neue Werte einfügen kann.

von TheMason (Gast)


Lesenswert?

@micha

prinzipiell ist das kein thema.
man muß sich nur vor augen halten das der präprozessor NUR eine REINE 
textersetzung macht.
das eigentliche rechnen übernimmt der compiler zum eigentlichen 
compilierzeitpunkt.

du kannst dir die adressen folgendermaßen generieren lassen :

const (char *) Data EEPROM [] = {"data 1", "data 2", "data 3"};

#define ADDR1  ( (char *) & (Data [0]) )
#define ADDR2  ( (char *) & (Data [1]) )
#define ADDR3  ( (char *) & (Data [2]) )

so würdest du dir für jeden eintrag ein Makro-generieren. Willst du 
diese Makro-generierung automatisch machen bedarf es noch etwas mehr.
du müsstest dann (mittels geeigneter Makros) dir die Daten sowie die 
Adresse automatisch Erzeugen lassen.

Beispiel :

Du machst eine Datei in dem deine zu generierende Daten als Tabellen 
organisiert sind :

DATA_START
  DATA_ENTRY (ENTRY_1, "data 1")
  DATA_ENTRY (ENTRY_2, "data 2")
  DATA_ENTRY (ENTRY_3, "data 3")
DATA_END

diese datei speicherst du unter (z.b.) "data_cfg.h"

in deiner Headerdatei die aus dieser Tabelle enums und die Adressen 
generiert machst du folgendes :

enum {
#define DATA_START
#define DATA_ENTRY(name,data)  name,
#define DATA_END
  #include "data_cfg.h"
#undef DATA_START
#undef DATA_ENTRY
#undef DATA_END
};

das erzeugt dir enums für deine array-einträge (das erlaubt dir 
namensmässig auf die einträge des arrays zuzugreifen.

mit :


#define DATA_START
#define DATA_ENTRY(name,data) const (char *) Ptr_##name = (char *) (& 
Data [name] );
#define DATA_END
  #include "data_cfg.h"
#undef  DATA_START
#undef  DATA_ENTRY
#undef  DATA_END

erzeugst du dir für jeden array eintrag eine zeiger konstante. der name 
der konstanten fängt immer mit Ptr_ an. also wird mit damit folgendes 
erzeugt :

Ptr_ENTRY_1 (zeiger auf "data 1")
Ptr_ENTRY_2 (zeiger auf "data 2")
Ptr_ENTRY_3 (zeiger auf "data 3")

und zu guter letzt erzeugst du mit

const (char *) Data [] EEPROM = {
#define DATA_START
#define DATA_ENTRY(name,data)  data,
#define DATA_END
  #include "data_cfg.h"
#undef DATA_START
#undef DATA_ENTRY
#undef DATA_END
};

in deinem c file das eigentliche Datenarray.

ich weiß zwar nicht ob diese beschreibung dir weiterhilft bzw. ob es zu 
deinem problem passt, aber ich arbeite recht exzessiv mit dem 
präprozessor, und damit habe ich schon einige konstruukte realisiert die 
das Programmieren und die erweiterbarkeit/wartbarkeit erheblich 
vereinfacht haben.

wenn es nicht zu dem passt was du suchst, sag doch mal genau was du 
brauchst dann kann ich dir vielleicht einen besseren ansatz geben.

gruß
rene

von Andreas K. (a-k)


Lesenswert?

Schon wieder jemand, der dem Präprozessor wundersame Fähigkeiten 
zuschreibt. Wo lernt man das?

Das Stichwort heisst hier "struct". Die EEPROM-Daten in eine solche 
hineinpacken und fertig.

von Der M. (steinadler)


Lesenswert?

Mir gings drum, nicht für jede Adresse Speicherplatz zu verbraten.

von Peter D. (peda)


Lesenswert?

Micha R. wrote:
> Mir gings drum, nicht für jede Adresse Speicherplatz zu verbraten.

Das tust Du erst, wenn Du auch einen Pointer anlegst.

Structs und Enums verbraten erstmal garnichts.

Wenn Du eine Konstante als Pointer castest und auf dessen Inhalt 
zugreifst, wird die Adresse nicht als Variable angelegt.


Peter

von TheMason (Gast)


Lesenswert?

da gibts noch folgende möglichkeit (etwas dirty, sollte aber 
funktionieren):

du missbrauchst ein enum für "zeiger" :

enum {
#define DATA_START
#define DATA_ENTRY(name,data)  Ptr_##name = ((int) ((char *) &(Data 
[name]))),
#define DATA_END
  #include "data_cfg.h"
#undef DATA_START
#undef DATA_ENTRY
#undef DATA_END
};

setzt vorraus das intern die enums denselben zahlenbereich haben wie 
zeiger.
du baust dir damit folgendes zusammen

enum {
  Ptr_ENTRY_1 = ((int) ((char *) & (Data [ENTRY_1))),
  Ptr_ENTRY_2 = ((int) ((char *) & (Data [ENTRY_2))),
  Ptr_ENTRY_3 = ((int) ((char *) & (Data [ENTRY_3))),
};

enums brauchen kein speicherplatz auf dem controller. und sofern die 
maximale interne datenbreite für enums mindestens genausogroß ist wie 
deine zeigerbreite (z.b. 16 bit) funktioniert das wunderbar.

gruß
rene

von Peter D. (peda)


Lesenswert?

TheMason wrote:

> ich arbeite recht exzessiv mit dem
> präprozessor, und damit habe ich schon einige konstruukte realisiert die
> das Programmieren und die erweiterbarkeit/wartbarkeit erheblich
> vereinfacht haben.

Ja, Deinen Programmierstil erkennt man unter tausenden sofort heraus.

Ob sowas aber als noch wartbar empfunden wird, ist Ansichtssache.

Ich hab mich mit enums noch nie anfreunden können.


Peter

von TheMason (Gast)


Lesenswert?

>Ob sowas aber als noch wartbar empfunden wird, ist Ansichtssache.

ok ist etwas gewöhnungsbedürftig, aber gerade bei vielen einträgen und 
verschachtelten daten (z.b. array von zeiger auf structs die ihrerseits 
wieder zeiger auf daten bzw structs enthalten) nimmt die wartbarkeit 
meines programmierstils wieder zu. (z.b. Menüsteuerung mit Menüeinträgen 
in mehreren Sprachen)
das ganze lohnt sich erst ab einer gewissen komplexität bzw. anzahl von 
daten bei denen man sich schnell durch copy&paste die finger bricht.
obwohl es auch ganz schön ist eine konfiguration (z.b. Port-pins eines 
angeschlossenen LCD's) einfach in eine kleine konfigurationsdatei zu 
legen und dann auf jedem prozessor verwenden zu können, und bei änderung 
(HW/Platform) nur die Konfigurationsdatei anpassen zu müssen.

>Ja, Deinen Programmierstil erkennt man unter tausenden sofort heraus.

bin halt einfach nur ein fleißig fauler programmierer der nutzen/aufwand 
des mehrtippens wieder raus haben will :-) (sonst würde ich alles nur 
hard-coded programmieren und magic numbers nur so sprießen) :-))

falls interesse besteht kann ich ja mal aus meinem programmierstil einen 
artikel machen (der dann genauso wenig besucht wird wie mein Parser bzw. 
mein audio-projekt *mecker mecker :-)) mal schauen

gruß
rene

von Andreas K. (a-k)


Lesenswert?

struct EEPOM_Daten {
  int a;
  double b;
  char c[10];
};

Benötigt keinen Platz, legt aber die relativen Adressen fest. An diese 
Offsets kommst du mit dem quasi-standard Makro offsetof() ran. Gibt's 
den nicht schon, dann beispielsweise definieren mit:
  #define offsetof(s,m)  ((char *)&((s*)0)->m-(char*)0)
und benutzen wie
  offsetof(EEPROM_Daten,b)

Meist benutzt man das EEPROM jedoch für Parameter, die dann sowieso als 
live-Kopie im RAM liegen. Da kann man die dann auch gleich in dieser 
struct drin lassen und ohne offsetof en bloc hin und her kopieren.

@TheMason: enum zur Speicherung von Adressen. Autsch, das tut weh.

von TheMason (Gast)


Lesenswert?

@andreas

>enum zur Speicherung von Adressen. Autsch, das tut weh.

ich sag doch : nicht sauber aber funktioniert. aber mal im ernst : wenn 
ein enum 16 bit umfasst und letztenendes NUR einen wert darstellt und 
ein zeiger ebenfalls dasselbe darstellt (rein zahlenmässig) was spricht 
dann dagegen ?
doch nur die interne implementierung eines enums die dann vom compiler 
"falsch" interpretiert werden kann, oder ?
16 bit sind 16 bit.

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.