Forum: Compiler & IDEs Funktionspointer im PROGMEM?


von Sebba (Gast)


Lesenswert?

Moin moin!

In C ist es ja möglich Funktionen über Pointer aufzurufen.
Ist dies auch auf einem AVR möglich? (Genauer: kann ich diese Adresse
irgendwie in den Programmspeicher ablegen?)

Mein konkretes Problem ist folgendes:
Ich habe eine Funktion die ein Menü erzeugt - nun möchte ich beim
anwählen eines Menüpunkts bestimmte Funktionen ausführen - Momentan
mach ich das indem ich ne dicke Case Abfrage zu jedem Menüpunkt
mache...
Schöner wär natürlich wenn ich ein Zeigerarray in dem Programmspeicher
ablegen könnte...

Danke schonmal

von Michael U. (Gast)


Lesenswert?

Hallo,

fehlt mir wie üblich die C-Kenntnis.

Muß aber gehen, da der AVR IJMP und ICALL kann.

in menunr ist die Nummer des Menüs (array-index)

.cseg

ldi XH,high(2*menutab)
ldi XL,low(2*menutab)
lsl menunr             ; *2 wegen Wordlänge der Adresse
add XL,menunr
clr menunr            ; um an eine 0 zu kommen...
adc XH,menunr         ; jetzt zeigt x auf die gewünschte Adresse in der
Tabelle
lpm ZH,X+             ; jetzt die Adresse nach Z
lpm ZL,X
ijmp                  ; und zur Routine springen springen
oder icall            ; wenn es als Subroutine aufgerufen werden soll

.dseg

menuetab:
  .dw  funktion1
  .dw  funktion2
  .dw  funktion3
usw.

wie das in C geht? noch keine Ahnung... ;)

Gruß aus Berlin
Micahel

von JojoS (Gast)


Lesenswert?

Zeigerarray als const geht, aber was ich bisher gesehen war das der
Compiler LDS oder LDD Befehle erzeugt, die Sprungziele also aus dem RAM
holt (das vorher mit den Konstanten initialisiert wird). Wenn die
Sprungtabelle im PROGMEM liegt wird der gleiche Code erzeugt aber die
RAM Werte nicht richtig geladen - der Sprung geht an die Adresse 0.
Hier ist ein Beispiel wie ich eine Zuordnung von Tasten zu Funktionen
realisiert habe:
1
void Btn0Click(void)
2
{
3
  PORTC &= ~_BV(0);
4
  pos=middlePos;
5
}
6
7
void Btn1Click(void)
8
{
9
  PORTC &= ~_BV(0);
10
  pos+=deltaPos;
11
}
12
13
void Btn2Click(void)
14
{
15
  PORTC |= _BV(0);
16
  pos-=deltaPos;
17
}
18
19
typedef struct
20
{
21
  short bitnr;
22
  void (*fnAction)(void);
23
} ACTION;
24
25
const ACTION ActionTab[]  =
26
{
27
  {2, Btn0Click},
28
  {3, Btn1Click},
29
  {5, Btn2Click},
30
  {0, NULL}
31
};
32
33
void CheckIO(void)
34
{
35
  ACTION* p;
36
  p=ActionTab;
37
  while(p->fnAction != NULL)
38
  {
39
    if ((PINB ^ PB_old) & PB_old & _BV(p->bitnr))
40
      p->fnAction();
41
    p++;
42
  }
43
  PB_old=PINB;
44
}

von Wolfgang (Gast)


Lesenswert?

Und wenn das Ganze ins Flash bzw. PROGMEM soll, dann kann man nicht 
direkt über den pointer lesen, sondern muß pgm_read_byte bzw. 
pgm_read_word bemühen und den Funktionspointer lokal umkopieren:

const ACTION ActionTab[] PROGMEM  =
{
  {2, Btn0Click},
  {3, Btn1Click},
  {5, Btn2Click},
  {0, NULL}
};

void CheckIO(void)
{
  const ACTION* p;
  p=ActionTab;
  void (*fp)(void);

  while(fp = (void *) pgm_read_word(&p->fnAction) != NULL)
  {
    if ((PINB ^ PB_old) & PB_old & _BV(pgm_read_byte(&p->bitnr))
      fp();
    p++;
  }
  PB_old=PINB;
}


von Peter Sager (Gast)


Lesenswert?

Wirf mal einen kleinen Blick auf folgenden Beispiel: So ergeben sich 
Function-Calls mit ICALL(Z) statt mit CALL:

__________________________________________________________

#include <avr/io.h>

void function_A(void)
{
  unsigned char i=4;
  while(i--)
  {
    asm volatile("nop");
  }
}

// get address pointer of function_A
void (*function_B)(void) = (void *)(function_A);

// define a function-pointer to a fixed FLASH address
void (*function_C)(void) = (void *)(0x0F00);  // WORD-Address !!!

int main(void)
{
  function_A();  // => CALL
  function_B();  // => ICALL(Z=function_A)
  function_C();  // => ICALL(Z=0x0F00)
  while(1);
}

__________________________________________________________

Auf diese Art kannst Du natürlich auch beliebeige Struks aufbauen. Die 
Pointer werden allerdings zur Laufzeit ins RAM-kopiert!

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.