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
Das & zeigt auf die erste Adresse von deiner Struktur "menueeintrag" und die wird solange hochgezählt bis das struct durch ist.
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
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
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
> 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).
Du musst das Ergebnis von pgm_read_word auf den passenden function pointer casten:
1 | (*(void(*)(void))pgm_read_word(&menuein...))(); |
Hallo! Danke Hc Zimmerer, aber leider meldet er dabei einen Fehler: "expected expression before 'menueintrag' " ich weiß da nicht mehr weiter...
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).
So sieht die Zeile aus (*(void(*)(void))pgm_read_word(&menueintrag[menu_aktuell].ok))();
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.)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.