Forum: Compiler & IDEs wie konstanten Zeiger auf Funktion aus Flash lesen?


von Niklas (Gast)


Lesenswert?

Hallo C-Profis,

ich habe folgendes Problem:
Für ein Display-Menü habe ich mir ein Struct für die einzelnen Buttons
gebaut in der Form:
typedef const struct {
  unsigned char xpos;
  unsigned char ypos;
  ...
  void (*program)();    //Zeiger auf Funktion
  ...
} but;

Nun speicher ich die Werte in einem Array aus diesen Structs in den 
Flash:
const but button[MAX_BUTTONS] PROGMEM = {{10,20,...,dimming_high,...},
                                         {...}};
"dimming high" ist nun die Funktion, auf die der Zeiger im Struct zeigt.
Verwende ich PROGMEM nicht und speicher das Array ganz normal, erreiche 
ich die Funktion folgendermaßen:
(*button[index].program)();

Meine Frage ist jetzt, wie kann ich die entsprechende Funktion starten, 
wenn mein Zeiger im Flash liegt? Ist dies überhaupt möglich?

Vielen Dank im voraus.
Gruß
Niklas

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ist offenbar ein AVR.  Du musst eine Zeigervariable im RAM anlegen
und diese mittels pgm_read_word() aus dem ROM füllen.

von Niklas (Gast)


Lesenswert?

Hallo Jörg,

entschuldige bitte, ich hatte vergessen zu erwähnen, dass es um einen 
AVR geht und ich ihn mit gcc programmiere.
Meine Zeigervariable im RAM ist bereits im Struct vorhanden:
void (*program)();

Ich weiß auch, dass ein Zeiger bei den AVRs 16bit groß ist und man ihn 
dementsprechent mit pgm_read_word() liest.
Mit einem normalen Zeiger habe ich auch kein Problem, nur kenne ich die
Syntax nicht, um einen Zeiger auf eine Funktion aus dem ROM zu lesen.
Ich habe es mit (void*)pgm_read_word((&button[i].program)());
versucht, aber AVR-Studio meldet mir:
error: called object '&button[i].program' is not a function

???
Irgendetwas mache ich also falsch. Weist du wie die Syntax richtig 
lauten müsste? Danke

Gruß
Niklas

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Du versuchst den Zeiger bereits im ROM zu dereferenzieren, d. h. die
Funktion aufzurufen.  Lass einfach mal die runden Klammern weg.

Der Typecast nach void * bringt auch nichts.

von Werner B. (Gast)


Lesenswert?

Jetzt mal so aus dem Bauch heraus...
1
void (*prog)(void) = (void(*)(void))pgm_read_word(&(button[i].program));
2
prog();
Du kannst nicht (void(*)(void))pgm_read_word(&(button[i].program))(); 
direkt aufrufen, weil pgm_read_word ein Makro ist.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ich würde es so angehen (Ungetestet, nur hingeschrieben)
1
typedef const struct {
2
  unsigned char xpos;
3
  unsigned char ypos;
4
  ...
5
  void (*program)(void);    //Zeiger auf Funktion
6
  ...
7
} but;
8
9
// Definitionen
10
11
const but button[MAX_BUTTONS] PROGMEM = {
12
  {10, 20, ..., &dimming_high, ...},
13
  {...}
14
};
15
16
void dimming_high(void)
17
{
18
}
19
20
// Aufruf
21
22
int main(void)
23
{
24
  // so ;-)
25
  void (* fptr)(void); 
26
  fptr = (void (*)) pgm_read_word((&(button[0].program));
27
  fptr();
28
29
  // oder so ;-(
30
  *((void (*)) pgm_read_word((&(button[0].program)))(); 
31
}

EDIT: Mit Werners Antwort hat sich mein ;-( erledigt ;-)

von Niklas (Gast)


Lesenswert?

Es funktioniert!!!

Ich danke euch vielmals für eure Hilfe! Ich habe mein Fehler erkannt.
Eigentlich blöde von mir zu versuchen, eine Adresse zu "starten".
Habe die Adresse der Funktion jetzt an einen neuen Funktionszeiger
übergeben, wie von euch vorgeschlagen und es funktioniert auf Anhieb.
Nochmals danke.

Gruß
Niklas

von Rolf Magnus (Gast)


Lesenswert?

> // oder so ;-(

Versuch mal, diesen Smiley mit deinem Gesicht nachzumachen, also die 
Mundwinkel hängen lassen und ein Auge zukneifen. Ist gar nicht so 
einfach ;-)

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.