www.mikrocontroller.net

Forum: Compiler & IDEs Funktionspointer im PROGMEM?


Autor: Sebba (Gast)
Datum:

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

Autor: Michael U. (Gast)
Datum:

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

Autor: JojoS (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
void Btn0Click(void)
{
  PORTC &= ~_BV(0);
  pos=middlePos;
}

void Btn1Click(void)
{
  PORTC &= ~_BV(0);
  pos+=deltaPos;
}

void Btn2Click(void)
{
  PORTC |= _BV(0);
  pos-=deltaPos;
}

typedef struct
{
  short bitnr;
  void (*fnAction)(void);
} ACTION;

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

void CheckIO(void)
{
  ACTION* p;
  p=ActionTab;
  while(p->fnAction != NULL)
  {
    if ((PINB ^ PB_old) & PB_old & _BV(p->bitnr))
      p->fnAction();
    p++;
  }
  PB_old=PINB;
}


Autor: Wolfgang (Gast)
Datum:

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


Autor: Peter Sager (Gast)
Datum:

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

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.