Ich möchte parameter und Strings im Flash Speicher ablegen, die später
von einer Funktione gelesen und abgearbeitet werden.
Das soll so auschauen
uint8_t _attribute_ ((progmem)) menu_main[] = {hier die
parameter......}
Nun ist das etwas unübersichtlich wenn ich nur 8bity werte reinschreiben
kann.
Ich möchte das gerne so eingeben können :
uint8_t _attribute_ ((progmem)) menu_main[] =
{(uint8_t) 120, (int) 13245, (long) -145120, "Bezeichnung", ....}
Ich kann aber auch kein struct mit den bentötigten typen definieren,
weil nicht immer die selben datentypen benötigt werden.
Im Prinzip schaut es so aus:
typedef struct
{
...
} struct_a;
typedef struct
{
...
} struct_b;
typedef struct
{
...
} struct_c;
uint8_t _attribute_ ((progmem)) menu_main[] =
{
(uint8_t) datentyp1, ((struct_a) {....},
(uint8_t) datentyp2, ((struct_b) {....},
(uint8_t) datentyp1, ((struct_a) {....},
(uint8_t) datentyp3, ((struct_c) {....}
};
Der erste Parameter im Flash soll den nachfolgenden Datentyp
spezifizieren.
Der nachfolgende Datentyp ist in Größe und Aufbau unterschiedlich.
Danach folgt wieder ein Parameter der den nächsten Datentypen
spezifiziert.
Wie kann man soetwas realisieren. Ich meine wie kann ich dem compiler
mitteilen welchen Datentyp ich jetzt in uint8_t array umgewandelt haben
möchte.
Schönen Dank für alle hilfreichen Antworten.
Klaus
@Klaus Me (meinzinet)
>uint8_t attribute ((progmem)) menu_main[] =>{(uint8_t) 120, (int) 13245, (long) -145120, "Bezeichnung", ....}
So macht man aber auch in "normalem" C keine Structs.
>Ich kann aber auch kein struct mit den bentötigten typen definieren,>weil nicht immer die selben datentypen benötigt werden.
Doch, kann und muss man. Und dann kann man auch relativ leicht die ganze
Sache definieren, das Attribut PROGMEM sorgt für die Platzierung im
Flash.
Was du hier machen willst ist ein über Hackertrick auf Assemblerebene,
nicht schön und nicht sehr praktikabel.
MFG
Falk
Wie man structs macht weiss ich schon.
Ich wollte eigentlich wissen wie ich die Initialisierung des arrays
schreiben muss , so dass ich zB. ein integer eigeben kann und der
compiler automatisch 2 Bytes daraus macht.
Mir ist immer noch nicht klar, warum du keine structs nehmen willst.
Vieleicht solltest du nochmal klar formulieren, was du am Ende erreichen
willst und die voreiligen Halbschluesse weglassen...
Klaus Me wrote:
> Wie man structs macht weiss ich schon.>> Ich wollte eigentlich wissen wie ich die Initialisierung des arrays> schreiben muss , so dass ich zB. ein integer eigeben kann und der> compiler automatisch 2 Bytes daraus macht.>
display_text_P(&pgm_text);// Funktion zeigt den Text am Display an
6
display_long_P(&pgm_long);// Funktion stellt die Zahl am Display an
7
display_rechteck_P(&pgm_rechteck);// Funktion zeichnet ein Rechteck am Display
8
}
Nun will ich das aber so machen
1
uint8_t__attribute__((progmem))pgm_display={??????????};// Hier müssten die Daten stehen die dann die selbe Anzeige ergeben wie im ersten Beispiel
2
3
voiddisplay(constchar*pgm_ptr)
4
{
5
while(1==1)
6
{
7
uint8_tdisplay_typ=pgm_read_byte(pgm_ptr++);
8
switch(display_typ)
9
{
10
case1:
11
display_text_P(pgm_ptr);
12
pgm_ptr+=sizeof(display_text_t);
13
break;
14
15
case2:
16
display_long_P(pgm_ptr);
17
pgm_ptr+=sizeof(display_long_t);
18
break;
19
20
case3:
21
display_rechteck_P(pgm_ptr);
22
pgm_ptr+=sizeof(display_rechteck_t);
23
break;
24
25
case99:return;// kein weiteres element zum Anzeigen
26
}
27
}
28
}
29
30
intmain(void)
31
{
32
.....
33
34
display(&pgm_display);
35
}
Nun meine Frage : wie kann ich pgm_display die Daten zuweisen, dass auch
die selbe Anzeige am Display erscheint.
Nun eine Möglichkeit wäre alles in 8bit Zahlen umrechnen und
einzutragen.
Verständlichweise suche ich nach einer Möglichkeit dies sichtbarer und
komfortabler zu machen.
@Nun meine Frage : wie kann ich pgm_display die Daten zuweisen, dass
auch
>die selbe Anzeige am Display erscheint.
1. Structs sind die saubere und einfache Lösung.
2. Um verschiedene Structs an ein Funktion zu übergeben kann man einen
Cast bzw. void Pointer nutzen. Nicht schön, aber halbwegs konform. Über
den Zugriff auf das erste Byte, kann man dann in der Funktion einen
neuen Cast auf den richtigen Struct machen und komfortabel auf die Daten
in C Manier zugreifen. Keinerlei notwenigikeit, alles zu Fuss
zusammenzusetzen.
Richtig sauber wird es erst durch nutzung verketteter Structs, sprich es
gibt eine Art Header-Struct, welches IMMER gleich ist. Dort sind dann
die Pointer auf die unterschiedlichgen Nutzdaten drin.
>Nun eine Möglichkeit wäre alles in 8bit Zahlen umrechnen und>einzutragen.
Völliger Blödsinn. Dann kannst du auch gleich den C-Compiler
wegschmeissen. Du denkst noch viel zu Bastlermässig.
>Verständlichweise suche ich nach einer Möglichkeit dies sichtbarer und>komfortabler zu machen.
Siehe oben.
MfG
Falk
P.S. Und nutze doch einfch die fertigen Defines ala PROGMEM, solche
Sachen wie _atribute_ will ich als normaler Programmierer nicht sehen.
Das ist was für die Kompilerbauer.
1
display_text_tpgm_textPROGMEM={0,0,CENTER_VIEW,"der text soll angezeigt werden"};
Klaus Me wrote:
> Hallo Johann>> Ich glaub war wohl zu schnell und ungenau definiert was ich machen will.> [...]> Zentnerweise C-Code> [...]> Nun eine Möglichkeit wäre alles in 8bit Zahlen umrechnen und> einzutragen.> Verständlichweise suche ich nach einer Möglichkeit dies sichtbarer und> komfortabler zu machen.
Eigentlich steht's oben geschrieben
1) Alle Datensätze sehen gleich aus: Definier dir eine Struktur
2) Die Datensätze sehen nicht gleich aus
2a) Definier dir jeweils Strukturen, die du in eine Union packst.
In einer id merkst du, wie das Zeug zu interpretieren ist.
Nachteil: Es geht Platz verloren, wenn nicht alle Sichten
gleich groß sind, was insbesondere bei char[20] und vielen
Einträgen übel aufstößt.
2b) Definier jeweils Strukturen, die nacheinander die Komponenten
einer großen Bandwurm-Struktur bilden.
Nachteil: schlechter zu pflegen, die interpretation ist implizit.
Dafür kleinerer Code. Bei vielen Einträgen ist zu überlegen, den
Code dafür auf dem Host per Code-Generator erzeugen zu lassen.
3) Schreib ein Assembler-Modul, wo du die Daten per .byte, .word etc
reinhackst. Dann meckert kein Compiler. Alternativ in ein globales
asm("") schreiben.
Wie schon erwähnt hat dies den Nachteil, daß alle Einträge gleich groß
sind, nämlich so groß wie das grösste Element der union.
Dementsprechend muss man beim Auslesen in der Schleife seinen Zeiger
NICHT um sizeof(display_long_t) oder sizeof(display_rechteck_t)
weiter setzen, sondern immer um sizeof(display_irgendwas_t), egal
welchen Typ man ausliest - wenn man es unbedingt über ein char*
hinmurksen will.
(Probiert mit gcc 4.3.2; ältere mögen vielleicht die Initialisierung
der Art .u_text=... nicht)
Klaus Wachtler wrote:
> (Probiert mit gcc 4.3.2; ältere mögen vielleicht die Initialisierung> der Art .u_text=... nicht)
Das hat nix mit der gcc-Version zu tun, sondern mit dem verwendeten
C-Standard.
Übliche Praxis ist, eine Id in die Union aufzunehmen, die allen
Komponenten gemein ist und durch sie überlagert wird. Dadurch kann auf
die Id zugegriffen werden, ohne eine bestimmte Sicht anzusprechend (die
man ja noch garnicht weiß zu dem Zeitpunkt)
1
enum
2
{
3
ITEMID_TEXT,
4
ITEMID_LONG,
5
ITEMID_RECT,
6
7
ITEM_NUM_IDS
8
};
9
10
typedefstruct
11
{
12
// common
13
uint8_tid;
14
// item specific
15
uint8_tposx;
16
uint8_tposy;
17
uint8_tformat;
18
charlabel[20];// Evtl ist hier ein char* besser (Platzverbrauch!)