mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Frage zu Pointern - Menu


Autor: Alexander (Gast)
Datum:

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

Autor: Nils S. (kruemeltee) Benutzerseite
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

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

Autor: Alexander (Gast)
Datum:

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

Autor: Alexander (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann mir das keiner erklären?

Autor: Nils S. (kruemeltee) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat dir das keiner erklärt?

Autor: Alexander (Gast)
Datum:

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

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht 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:
const menueintrag menu [] PROGMEM = {
/*000*/ {"Modus aendern",-1, 1,16, 8,nop,menu_OK,nop, nop},
...
};
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
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).

Autor: Alexander (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Einer ne idee zu der Sache mir den Funktionspointern?

Autor: Hc Zimmerer (mizch)
Datum:

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

Autor: Alexander (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

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

"expected expression before 'menueintrag' "

ich weiß da nicht mehr weiter...

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bist Du mit den Klammern durcheinander gekommen?  Zitat aus einem 
lauffähigen Programm für AVR ... Momentchen noch ... hier, das ist sie:
 (*(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).

Autor: Alexander (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So sieht die Zeile aus

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

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht 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:
{
   void (*f)(void);
   f =(void*)pgm_read_word(&menueintrag[menu_aktuell].ok);
   f();
}
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.)

Autor: Alexander (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

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

Gruß und nen guten Rutsch

Alexander

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.