Forum: Mikrocontroller und Digitale Elektronik Frage zu Pointern - Menu


von Alexander (Gast)


Lesenswert?

Hallo zusammen!

Ich bin momentan dabei ein Menu auf einem gLCD zu realisieren, es klappt 
auch, jedoch verstehe ich nicht warum es klappt: Folgender Code:

const typedef struct PROGMEM {
        const char *Beschreibung;
        int menuabbrechen;
        int menuok;
        int menuhoch;
        int menurunter;
        void (*abbrechen)(void);
        void (*ok)(void);
        void (*hoch)(void);
        void (*runter)(void);
}menueintrag ;

const menueintrag menu [] PROGMEM = {
/*000*/ {"Modus aendern",-1, 1,16, 8,nop,menu_OK,nop, nop},
...
};

So sieht meine Menustructur aus. Immer wenn ich jetzt mich mit den 
Tasten durch das Menu manövriere, führe ich dieses aus:

void grafik_update_menu(){
glcd_deleteRectangle(0,50,53,58,1);
glcd_putsf(0,50,(PGM_P)pgm_read_word((&menu[menu_aktuell].Beschreibung)) 
,1);
}

Dann steht auch entsprechend das richtige auf dem LCD. Achso die 
Ausgabemethode fürs LCD:

void glcd_putsf(int x, int y, const char* str, unsigned char 
deleteBackGround ){
  int cc;
  cc=0;
  while(*str){
    cc=glcd_putchar(x,y,*str, deleteBackGround);
    x+=cc;
    str++;
  }
}

So und jetzt die Frage:
In meinem Menu habe ich ja einen Pointer auf das erste Element des char 
Arrays (const char *Beschreibung).
Wenn ich mir jetzt das Array menueintrag erzeuge, zeigt doch der Pointer 
der Beschreibung in diesem Falle z.B. auf die Adresse von dem "M"? Bzw. 
der Inhalt des Pointers ist die Adresse von dem "M".
Soweit klingt mir das ja alles logisch, aber in dem ausgeben 
(glcd_putsf) steht ja dann: 
(PGM_P)pgm_read_word((&menu[menu_aktuell].Beschreibung))
Damit greife ich doch dann auf die Adresse des Pointers drauf zu, aber 
die ist doch eigentlich unwichtig.
Kann mir das einer erklären, oder habe ich einfach nur ein Brett vorm 
Kopf?

Allen schon mal einen guten Rutsch

Alexander

von Nils S. (kruemeltee) Benutzerseite


Lesenswert?

Das & zeigt auf die erste Adresse von deiner Struktur "menueeintrag" und 
die wird solange hochgezählt bis das struct durch ist.

von Karl H. (kbuchegg)


Lesenswert?

Alexander schrieb:

> Soweit klingt mir das ja alles logisch, aber in dem ausgeben
> (glcd_putsf) steht ja dann:
> (PGM_P)pgm_read_word((&menu[menu_aktuell].Beschreibung))
> Damit greife ich doch dann auf die Adresse des Pointers drauf zu, aber
> die ist doch eigentlich unwichtig.
> Kann mir das einer erklären, oder habe ich einfach nur ein Brett vorm
> Kopf?

Deine Menüstruktur liegt im Flash

const typedef struct PROGMEM

Damit liegt auch der Pointer, der auf den Text zeigt, im Flash.
Und um an den Wert des Pointers zu kommen, musst du logischerweise 
diesen Pointerwert aus dem Flash lesen.

Du brauchst also den Wert von
  menu[menu_aktuell].Beschreibung
Wie kriegst du ihn?
Indem du die Funktion pgm_read_word benutzt. Die holt den Wert aus dem 
Flash. Und dazu braucht sie die Adresse im Flash, von wo der Wert geholt 
werden soll.
    &menu[menu_aktuell].Beschreibung

von Alexander (Gast)


Lesenswert?

Hallo!

Danke schon mal für die Antworten!

Verstehe ich das damit richtig, dass ich dem pgm_read_word eine Adresse 
mitgeben muss, wo er den Wert(in diesem Fall die erste Adresse von dem 
chracter Array) herholen soll? Und diese Adresse gebe ich dann an meine 
putsf Routine weiter, damit sie den Text ausgeben kann?

Und dann noch eine weitere Frage:
Dieses (PGM_P) ist doch ein Cast Operator, damit das was dahinter steht 
als Pointer zu einem String im Flash angesehen wird. Aber liegt denn in 
meinem konkreten Fall der Pointer nicht sowieso im Flash?

Und eine letze Frage noch, macht es bei einem struct einen Unterschied 
wo ich das const hinschreibe, ob davor, oder vor alle Variabeln innen?
Also sind diese Sachen quasi alle die gleichen?


const typedef struct PROGMEM {
        char *Beschreibung;
        int menuabbrechen;
        int menuok;
        int menuhoch;
        int menurunter;
        void (*abbrechen)(void);
        void (*ok)(void);
        void (*hoch)(void);
        void (*runter)(void);
}menueintrag ;

typedef struct PROGMEM {
        const char *Beschreibung;
        const int menuabbrechen;
        const int menuok;
        const int menuhoch;
        const int menurunter;
        const void (*abbrechen)(void);
        const void (*ok)(void);
        const void (*hoch)(void);
        const void (*runter)(void);
}menueintrag ;

Oder bezieht sich das const vor dem typdef nur auf die struct selber, 
die const vor den Varablen aber auf die Variblen selber?

Sry, aber da ich gerade von Codevision auf gcc umsteige bereitet mir das 
noch einige Probleme, da das in Codevision doch ein bisschen anders 
(meinesherachtens leichter) geht.

Gruß

Alexander

von Alexander (Gast)


Lesenswert?

Kann mir das keiner erklären?

von Nils S. (kruemeltee) Benutzerseite


Lesenswert?

Hat dir das keiner erklärt?

von Alexander (Gast)


Lesenswert?

Hi!

Naja, es blieben halt son paar Kleinigkeiten offen, aber gut, die habe 
ich inzwischen beseitigt.
Habe jedoch jetzt zum gleichen Thema eine neue Frage, nach deren 
Antowort ich hier im Forum auch schon gesucht habe (und auch im ganzen 
netz).

Wenn ich wieder diese Strucktur habe:

const typedef struct PROGMEM {
        char *Beschreibung;
        int menuabbrechen;
        int menuok;
        int menuhoch;
        int menurunter;
        void (*abbrechen)(void);
        void (*ok)(void);
        void (*hoch)(void);
        void (*runter)(void);
}menueintrag ;

typedef struct PROGMEM {
        const char *Beschreibung;
        const int menuabbrechen;
        const int menuok;
        const int menuhoch;
        const int menurunter;
        const void (*abbrechen)(void);
        const void (*ok)(void);
        const void (*hoch)(void);
        const void (*runter)(void);
}menueintrag ;


Wie greife ich dann auf eine Funktion zu?
Ich habe da schon diverses probiert, aber dabei schmiert entweder der 
Controller ab, oder er meldet Fehler beim compilieren:

(pgm_read_word(&menueintrag[menu_aktuell].ok))();

Das geht nämlicht nicht, kann mir da einer von euch einen Tipp zu geben?

Gruß

Alexander

von Hc Z. (mizch)


Lesenswert?

> Verstehe ich das damit richtig, dass ich dem pgm_read_word eine Adresse
> mitgeben muss, wo er den Wert(in diesem Fall die erste Adresse von dem
> chracter Array) herholen soll?

Ja.  Du hast aber eine Falle drin:
1
const menueintrag menu [] PROGMEM = {
2
/*000*/ {"Modus aendern",-1, 1,16, 8,nop,menu_OK,nop, nop},
3
...
4
};
Der Pointer ist im Flash, richtig.  Er zeigt auf "Modus aendern".  Das 
aber ist ein normaler String, und der liegt - so wie es geschrieben ist 
- im Ram, frisst also wertvollen Platz.

Du müsstest
1
char modus_aendern[] PROGMEM = "Modus aendern";
voranstellen und statt des Strings die neue Variable eintragen, um den 
String auch im Flash unterzubringen.

Evtl. geht auch PSTR("Modus aendern") in der Initilisierung, aber ich 
glaube, das frisst der Compiler nicht.

> Und diese Adresse gebe ich dann an meine
> putsf Routine weiter, damit sie den Text ausgeben kann?

Ja, allerdings muss die sich den String dann ebenfalls aus dem Flash, 
z.B. mit pgm_read_byte(), holen (darf den Pointer also nicht direkt 
verwenden).

von Alexander (Gast)


Lesenswert?

Einer ne idee zu der Sache mir den Funktionspointern?

von Hc Z. (mizch)


Lesenswert?

Du musst das Ergebnis von pgm_read_word auf den passenden function 
pointer casten:
1
(*(void(*)(void))pgm_read_word(&menuein...))();

von Alexander (Gast)


Lesenswert?

Hallo!

Danke Hc Zimmerer, aber leider meldet er dabei einen Fehler:

"expected expression before 'menueintrag' "

ich weiß da nicht mehr weiter...

von Hc Z. (mizch)


Lesenswert?

Bist Du mit den Klammern durcheinander gekommen?  Zitat aus einem 
lauffähigen Programm für AVR ... Momentchen noch ... hier, das ist sie:
1
 (*(void(*)(void))pgm_read_word(&entry->func))();
Falls das nicht weiterhilft, stell' doch mal die Zeile hier rein, die 
angemeckert wird (Antwort von mir aber diesen Abend nicht mehr).

von Alexander (Gast)


Lesenswert?

So sieht die Zeile aus

(*(void(*)(void))pgm_read_word(&menueintrag[menu_aktuell].ok))();

von Hc Z. (mizch)


Lesenswert?

Hmmm ... menueintrag kenne ich bisher nur als typedef einer struct, 
nicht als Variable.  Falls das nicht weiterhilft, drösle das Ganze doch 
einmal auf à la:
1
{
2
   void (*f)(void);
3
   f =(void*)pgm_read_word(&menueintrag[menu_aktuell].ok);
4
   f();
5
}
Hiermit sind der Cast, das Auslesen des Flash, und das Aufrufen der 
Funktion jeweils in einem eigenen Ausdruck.  Wo kommt jetzt der Fehler? 
(Nicht getestet, es können also Syntax-Fehler noch drin sein.)

von Alexander (Gast)


Lesenswert?

Hallo!

Danke an alle, es war mein Fehler, ich habe die ganze Zeit menueintrag 
statt menu geschrieben.

Gruß und nen guten Rutsch

Alexander

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.