www.mikrocontroller.net

Forum: Compiler & IDEs PROGMEM initialisieren mit verschiedenen Typen


Autor: Klaus Me (meinzinet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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

Autor: Klaus Me (meinzinet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.
>uint8_t attribute ((progmem)) menu_main[] =
>{(uint8_t) 120, (int) 13245, (long) -145120, "Bezeichnung", ....}

was hier in Klammern geschrieben ist, soll den Datentyp darstellen, den 
ich eingeben will. Normalerweise müsste ich ja eine Reihe von Bytes 
eingeben.

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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...

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.
>
>>uint8_t attribute ((progmem)) menu_main[] =
>>{(uint8_t) 120, (int) 13245, (long) -145120, "Bezeichnung", ....}
> 

Du sagst aber doch, daß alles vom Typ uibt8_t sein soll! Also du musst 
dich schon entscheiden, was du willst...

In deinem Falle vielleicht
typedef struct
{
   uint8_t id;
   int ival;
   long lval;
   const char label[]; // ist was anderes als chost char * label !!
} item_t ; 

const item_t items[] PROGMEM = 
{
    ...
};

Johann

Autor: Klaus Me (meinzinet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Johann

Ich glaub war wohl zu schnell und ungenau definiert was ich machen will.
typedef struct
{
  uint8_t posx;
  uint8_t posy;
  uint8_t format;
  char    bezeichnung[20];
} display_text_t;

typedef struct
{
  uint8_t posx;
  uint8_t posy;
  uint8_t format;
  long    zahl;
} display_long_t;

typedef struct
{
  uint8_t posx1;
  uint8_t posy1;
  uint8_t posx2;
  uint8_t posy2;
} display_rechteck_t;


display_text_t __attribute__ ((progmem)) pgm_text= {0,0,CENTER_VIEW,"der text soll angezeigt werden"};
display_long_t __attribute__ ((progmem)) pgm_long = {0,0,CENTER_VIEW,9960435};
display_rechteck_t __attribute__ ((progmem)) pgm_rechteck = {0,0,100,100};
So und die die funktionierende Variante:
int main(void)
{
  ....

  display_text_P(&pgm_text);    // Funktion zeigt den Text am Display an 
  display_long_P(&pgm_long);  // Funktion stellt die Zahl  am Display an 
  display_rechteck_P(&pgm_rechteck); // Funktion zeichnet ein Rechteck am Display 
}
Nun will ich das aber so machen
uint8_t __attribute__ ((progmem))  pgm_display = {??????????}; // Hier müssten die Daten stehen die dann die selbe Anzeige ergeben wie im ersten Beispiel

void display( const char * pgm_ptr)
{
 while (1==1)
 {
  uint8_t display_typ= pgm_read_byte(pgm_ptr++);
  switch (display_typ)
  {
    case 1 : 
      display_text_P(pgm_ptr);
      pgm_ptr+= sizeof(display_text_t);
    break;

    case 2 :
     display_long_P(pgm_ptr);
     pgm_ptr+=sizeof(display_long_t);
    break;

    case 3 :
     display_rechteck_P(pgm_ptr);
     pgm_ptr+=sizeof(display_rechteck_t);
    break;

   case 99 : return; // kein weiteres element zum Anzeigen
  }
 }  
}

int main(void)
{
.....

display(&pgm_display);
}

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.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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.
display_text_t pgm_text PROGMEM = {0,0,CENTER_VIEW,"der text soll angezeigt werden"};

MFG
Falk

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Version 2a von Johann L. ausformuliert sieht etwa so aus:
typedef struct
{
  uint8_t posx;
  uint8_t posy;
  uint8_t format;
  char    bezeichnung[20];
} display_text_t;

typedef struct
{
  uint8_t posx;
  uint8_t posy;
  uint8_t format;
  long    zahl;
} display_long_t;

typedef struct
{
  uint8_t posx1;
  uint8_t posy1;
  uint8_t posx2;
  uint8_t posy2;
} display_rechteck_t;


typedef union
{
  display_text_t      u_text;
  display_long_t      u_long;
  display_rechteck_t  u_rechteck;
} display_irgendwas_t;

typedef enum
{
  eDisplayTypeText,
  eDisplayTypeLong,
  eDisplayTypeRechteck,
} eDisplayType;

struct { uint8_t eDisplayType, display_irgendwas_t display } pgm_display[] =
  {
    { eDisplayTypeText,     { .u_text     = { 12, 13, 2, "erster text" } } },
    { eDisplayTypeLong,     { .u_long     = { 13, 14, 1, 1234 } } },
    { eDisplayTypeRechteck, { .u_rechteck = { 15, 16, 18, 19 } } },
    { eDisplayTypeText,     { .u_text     = { 12, 13, 2, "zweiter text" } } },
  };


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)

Autor: Klaus Me (meinzinet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Klaus

vielen dank für den Code vorschlag.
Werde es so ähnlic machen, nur eben so dass alle unions gleich groß 
sind.

struct { uint8_t eDisplayType, display_irgendwas_t display } 
pgm_display[] =
  {
    { eDisplayTypeText,     { .u_text     = { 12, 13, 2, "erster text" } 
} },
    { eDisplayTypeLong,     { .u_long     = { 13, 14, 1, 1234 } } },
    { eDisplayTypeRechteck, { .u_rechteck = { 15, 16, 18, 19 } } },
    { eDisplayTypeText,     { .u_text     = { 12, 13, 2, "zweiter text" 
} } },
  };

Das mit dem Initialisieren hat mir noch gefeht. Danke

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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)
enum
{
   ITEMID_TEXT,
   ITEMID_LONG,
   ITEMID_RECT,

   ITEM_NUM_IDS
};

typedef struct
{
   // common
   uint8_t id;
   // item specific
   uint8_t posx;
   uint8_t posy;
   uint8_t format;
   char    label[20]; // Evtl ist hier ein char* besser (Platzverbrauch!)
} display_text_t;

...

typedef union
{
   uint8_t id;
   display_long_t    asLong;
   display_text_t    asText;
} display_item_t;

...

const display_item_t items[] PROGMEM = 
{
    [0] = { .id = ITEMIT_TEXT, .posx = ... },
    [1] = { ...
};

void foo (display_item_t * item)
{
    if (ITEMID_TEXT == item->id)
    {
        // Aha, ein Text
        // .id ist .text.id
        printf (item->asText.label);
    }
}

Johann

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.