Forum: Mikrocontroller und Digitale Elektronik Funktions Pointer


von Manfred W. (Gast)


Lesenswert?

Wenn ich eine Funktion über einen Pointer aufrufe.

zb. über eine Menüstruktur.

Wird dann diese Funktion nur 1 mal ausgeführt oder läuft die sollange 
von vorne los wie ich mich in diesem Menü befinde?

von Tauwetter (Gast)


Lesenswert?

Die Frage ist etwas undurchsichtig. Die Funktion läuft solange, bis sie 
wieder verlassen wird, egal auf welche Weise sie aufgerufen wird.

von Manuel (Gast)


Lesenswert?

Mit Funktionspointern hat das ganze aber nix zu tun :-)

von Lokus P. (derschatten)


Lesenswert?

Indirekt.
Aber zu meinem Problem:

Ich hab mir eine Menüstrucktur gebastelt:
1
// LCD-Menüeinträge definieren
2
// ===========================
3
const char menu_000[] PROGMEM = " Multifunktions ";  //
4
const char menu_001[] PROGMEM = "ArcadeController";  //
5
6
const char menu_002[] PROGMEM = "** HAUPTMENUE **";  // 0
7
8
const char menu_100[] PROGMEM = "Tastenzuordnung>";  // 1
9
const char menu_101[] PROGMEM = "[X        ]    1";  // 2
10
const char menu_102[] PROGMEM = "[XX       ]    2";  // 3
11
const char menu_103[] PROGMEM = "[XXX      ]    3";  // 4
12
const char menu_104[] PROGMEM = "[XXXX     ]    4";  // 5
13
const char menu_105[] PROGMEM = "[XXXXX    ]    5";  // 6
14
const char menu_106[] PROGMEM = "[XXXXXX   ]    6";  // 7
15
const char menu_107[] PROGMEM = "[XXXXXXX  ]    7";  // 8
16
const char menu_108[] PROGMEM = "[XXXXXXXX ]    8";  // 9
17
const char menu_109[] PROGMEM = "[XXXXXXXXX]    9";  // 10
18
19
const char menu_200[] PROGMEM = "<Dauerfeuer    >";  // 11
20
const char menu_201[] PROGMEM = "[         ]    0";  // 12
21
const char menu_202[] PROGMEM = "[X        ]    1";  // 13
22
const char menu_203[] PROGMEM = "[XX       ]    2";  // 14
23
const char menu_204[] PROGMEM = "[XXX      ]    3";  // 15
24
const char menu_205[] PROGMEM = "[XXXX     ]    4";  // 16
25
const char menu_206[] PROGMEM = "[XXXXX    ]    5";  // 17
26
const char menu_207[] PROGMEM = "[XXXXXX   ]    6";  // 18
27
const char menu_208[] PROGMEM = "[XXXXXXX  ]    7";  // 19
28
const char menu_209[] PROGMEM = "[XXXXXXXX ]    8";  // 20
29
const char menu_210[] PROGMEM = "[XXXXXXXXX]    9";  // 21
30
31
const char menu_300[] PROGMEM = "<System        >";  // 22
32
const char menu_301[] PROGMEM = "LCD            >";  // 23
33
const char menu_302[] PROGMEM = "<LED-Test       ";  // 24
34
35
const char menu_400[] PROGMEM = "<Speichern     >";  // 25
36
37
const char menu_500[] PROGMEM = "<Beenden        ";  // 26
38
39
40
typedef struct def_menustruktur
41
{
42
  const char *text;
43
  unsigned char next;
44
  unsigned char previous;
45
  unsigned char sub;
46
  unsigned char up;
47
  void (*f_pointer) (unsigned char wert);
48
}menustruktur;
49
50
void tastenzuordnung(unsigned char wert);
51
void dauerfeuer(unsigned char wert);
52
void lcd(unsigned char wert);
53
void led(unsigned char wert);
54
void speichern(unsigned char wert);
55
void beenden(unsigned char wert);
56
57
// Tabelle von Zeigern auf die Texte erstellen
58
// ===========================================
59
menustruktur menu[] PROGMEM = 
60
{
61
  {menu_002, 0, 0, 0, 0, NULL},
62
  {menu_100, 11, 1, 2, 1, NULL},
63
    {menu_101, 3, 2, 1, 1, tastenzuordnung(1)}, 
64
    {menu_102, 4, 2, 1, 1, tastenzuordnung(2)}, 
65
    {menu_103, 5, 3, 1, 1, tastenzuordnung(3)}, 
66
    {menu_104, 6, 4, 1, 1, tastenzuordnung(4)}, 
67
    {menu_105, 7, 5, 1, 1, tastenzuordnung(5)}, 
68
    {menu_106, 8, 6, 1, 1, tastenzuordnung(6)}, 
69
    {menu_107, 9, 7, 1, 1, tastenzuordnung(7)}, 
70
    {menu_108, 10, 8, 1, 1, tastenzuordnung(8)}, 
71
    {menu_109, 10, 9, 1, 1, tastenzuordnung(9)}, 
72
  {menu_200, 22, 1, 12, 11, NULL}, 
73
    {menu_201, 13, 12, 11, 11, dauerfeuer(0)}, 
74
    {menu_202, 14, 12, 11, 11, dauerfeuer(1)}, 
75
    {menu_203, 15, 13, 11, 11, dauerfeuer(2)}, 
76
    {menu_204, 16, 14, 11, 11, dauerfeuer(3)}, 
77
    {menu_205, 17, 15, 11, 11, dauerfeuer(4)}, 
78
    {menu_206, 18, 16, 11, 11, dauerfeuer(5)}, 
79
    {menu_207, 19, 17, 11, 11, dauerfeuer(6)}, 
80
    {menu_208, 20, 18, 11, 11, dauerfeuer(7)}, 
81
    {menu_209, 21, 19, 11, 11, dauerfeuer(8)}, 
82
    {menu_210, 22, 20, 11, 11, dauerfeuer(9)}, 
83
  {menu_300, 25, 11, 23, 22, NULL}, 
84
    {menu_301, 24, 23, 22, 22, lcd(1)}, 
85
    {menu_302, 24, 23, 22, 22, led(1)}, 
86
  {menu_400, 26, 22, 25, 25, speichern(1)}, 
87
  {menu_500, 26, 25, 26, 26, beenden(1)} 
88
};

In meiner Funktion möchte ich nun gerne eine Variabel übergeben die in 
der Tabelle definiert ist:
1
void tastenzuordnung(unsigned char wert)
2
{
3
  nKonfig = pgm_read_word(&menu[menu_index].wert);
4
}

Nur, da passt was nicht.

von Heiko (Gast)


Lesenswert?

Tipp 1:
=======
1
menustruktur menu[] PROGMEM = 
2
{
3
  {menu_002, 0, 0, 0, 0, NULL},
4
  {menu_100, 11, 1, 2, 1, NULL},
5
    {menu_101, 3, 2, 1, 1, tastenzuordnung(1)}, 
6
    {menu_102, 4, 2, 1, 1, tastenzuordnung(2)},

tastenzuordnung(1) <- geht so nicht
An diese Stelle in der Struktur darf nur der Funktionspointer, also nur 
die Adresse der Funktion gespeichert werden. Bei dem Aufruf des Fkt-Ptrs 
kannst du dann ein Argument angeben.

Tipp 2
======
Statt
1
void tastenzuordnung(unsigned char wert);
kannst du doch direkt den Pointer auf den aktuellen Menueintrag 
übergeben. Somit wirst du auch gleich die globale Variable menu_index 
los.

von Rolf Magnus (Gast)


Lesenswert?

> Nur, da passt was nicht.

Das ist zwar richtig, aber was verleitet dich zu dieser Annahme?
1
> nKonfig = pgm_read_word(&menu[menu_index].wert);

menu_struktur hat kein Element names wert, also kannst du auch nicht 
darauf zugreifen. Mir ist nicht klar, was du eigentlich machen willst.

von Karl H. (kbuchegg)


Lesenswert?

Da du sowieso nur 5 Funktionalitäten hast, die eine überschaubare Menge 
darstellen, lass Funktionspointer sein und mach es konventionell mit 
Funktions Codes, die in der Menüstruktur enthalten sind.
1
#define NO_ACTION          0
2
#define EXIT_ACTION        1
3
#define DEF_KEY_ACTION     2
4
#define DEF_REPEAT_ACTION  3
5
#define LCD_ACTION         4
6
#define LED_ACTION         5
7
#define SAVE_ACTION        6
8
9
typedef struct def_menustruktur
10
{
11
  const char *text;
12
13
  unsigned char next;
14
  unsigned char previous;
15
  unsigned char sub;
16
  unsigned char up;
17
18
  unsigned char ActionCode;
19
  unsigned char ActionArgument;
20
}menustruktur;

Braucht weniger Speicher und ist auch einfacher zu handhaben
1
menustruktur menu[] PROGMEM = 
2
{
3
  {menu_002, 0, 0, 0, 0, NO_ACTION, 0 },
4
  {menu_100, 11, 1, 2, 1, NO_ACTION, 0 },
5
    {menu_101, 3, 2, 1, 1, DEF_KEY_ACTION, 1 }, 
6
    {menu_102, 4, 2, 1, 1, DEF_KEY_ACTION, 2 },
7
...

von Lokus P. (derschatten)


Lesenswert?

Heiko schrieb:
> tastenzuordnung(1) <- geht so nicht
> An diese Stelle in der Struktur darf nur der Funktionspointer, also nur
> die Adresse der Funktion gespeichert werden. Bei dem Aufruf des Fkt-Ptrs
> kannst du dann ein Argument angeben.
>

Ich weiß nicht wie ich dann jedem Menüpunkt eine Variable zuweisen soll.

> Statt
>
1
void tastenzuordnung(unsigned char wert);
> kannst du doch direkt den Pointer auf den aktuellen Menueintrag
> übergeben. Somit wirst du auch gleich die globale Variable menu_index
> los.

Kannst du mir genauer erklären wie du das meinst.

> Braucht weniger Speicher und ist auch einfacher zu handhabenmenustruktur
> menu[] PROGMEM =
> {
>   {menu_002, 0, 0, 0, 0, NO_ACTION, 0 },
>   {menu_100, 11, 1, 2, 1, NO_ACTION, 0 },
>     {menu_101, 3, 2, 1, 1, DEF_KEY_ACTION, 1 },
>     {menu_102, 4, 2, 1, 1, DEF_KEY_ACTION, 2 },
> ...

Wie sieht denn dann die dazugehörige Funktion aus die ich für jeden 
menüpuinkt aufrufen möchte?

von Klaus W. (mfgkw)


Lesenswert?

Wenn ich richtig verstanden habe, was du vorhast, dann folgendes:
1
menustruktur menu[] PROGMEM = 
2
{
3
  {menu_002, 0, 0, 0, 0, NULL },
4
  {menu_100, 11, 1, 2, 1, NULL },
5
    {menu_101, 3, 2, 1, 1, tastenzuordnung(1)}, 
6
    {menu_102, 4, 2, 1, 1, tastenzuordnung(2)}, 
7
...
Ich vermute, du willst hier hinterlegen, daß später mal
tastenzuordnung(1) etc. aufgerufen wird.

Geht nicht wie Heiko scho sagte, weil so wie es hier steht
beim Initialisieren bereits die Funktion aufgerufen wird,
und nicht später beim Zugriff auf das Feld.

Besser:
In der struct noch ein Element vorsehen für das Argument.
Erst beim Aufruf dann Funktionszeiger und dieses Argument
zusammenbringen:
1
typedef struct def_menustruktur
2
{
3
  const char *text;
4
  unsigned char next;
5
  unsigned char previous;
6
  unsigned char sub;
7
  unsigned char up;
8
  void (*f_pointer) (unsigned char wert);
9
  char     argument;
10
}menustruktur;
11
12
void tastenzuordnung(unsigned char wert);
13
void dauerfeuer(unsigned char wert);
14
void lcd(unsigned char wert);
15
void led(unsigned char wert);
16
void speichern(unsigned char wert);
17
void beenden(unsigned char wert);
18
19
// Tabelle von Zeigern auf die Texte erstellen
20
// ===========================================
21
menustruktur menu[] PROGMEM = 
22
{
23
  { menu_002, 0, 0, 0, 0, NULL, 0 },
24
  { menu_100, 11, 1, 2, 1, NULL, 0 },
25
  { menu_101, 3, 2, 1, 1, tastenzuordnung, 1 }, 
26
  { menu_102, 4, 2, 1, 1, tastenzuordnung, 2 }, 
27
...
28
29
// Aufruf:
30
  menu[menu_index].f_pointer( menu[menu_index].argument );

von Heiko (Gast)


Lesenswert?

f_pointer zeigt auf tastenzuordnung -> Rekursion wenn ich mich nicht 
irre.

Manfred:
Das Argument wert ist der Index des Menueintrages oder?

Wenn nein -> muss ich wohl nochmal überlegen...

Wenn ja:
Wer ruft den tastenzuordnung auf? in dieser Fkt ist der Index bekannt, 
also kannst du direkt einen Ptr auf den Menueintrag dem f_pointer 
übergeben und in diesem dann das von Klaus vorgeschlagene Feld argument 
auswerten.

von Heiko (Gast)


Lesenswert?

Klaus du hast doch grad editiert, oder? :)

von Karl H. (kbuchegg)


Lesenswert?

Manfred W. schrieb:

>> Braucht weniger Speicher und ist auch einfacher zu handhabenmenustruktur
>> menu[] PROGMEM =
>> {
>>   {menu_002, 0, 0, 0, 0, NO_ACTION, 0 },
>>   {menu_100, 11, 1, 2, 1, NO_ACTION, 0 },
>>     {menu_101, 3, 2, 1, 1, DEF_KEY_ACTION, 1 },
>>     {menu_102, 4, 2, 1, 1, DEF_KEY_ACTION, 2 },
>> ...
>
> Wie sieht denn dann die dazugehörige Funktion aus die ich für jeden
> menüpuinkt aufrufen möchte?

Der springende Punkt ist, dass das Menü dann gar nicht mehr automatisch 
irgendeine Funktion aufruft. In der Funktion, die das Menü abarbeiten, 
steht dann
1
....
2
3
   if( menu[menu_index].ActionCode == DEF_KEY_ACTION )
4
     nKeys = menu[menu_index].ActionArgument;
5
6
   else if( menu[menu_index].ActionCode == .... )

Natürlich nicht so, sondern noch unter Berücksichtigung, dass das Menü 
im Flash liegt.

Du machst schon wieder einen Kardinalfehler nach dem anderen. 
Programmiere erst mal ein konventionelles Menü und achte darauf, dass du 
die Flashzugriffe richtig machst, ehe du dich an Funktionspointern 
versuchst.

von Klaus W. (mfgkw)


Lesenswert?

Heiko schrieb:
> Klaus du hast doch grad editiert, oder? :)

Ja, sorry, da war noch einiges falsch.
Ich hatte zu schnell abgeschickt :-(

von Klaus W. (mfgkw)


Lesenswert?

Karl heinz Buchegger schrieb:
> Du machst schon wieder einen Kardinalfehler nach dem anderen.
> Programmiere erst mal ein konventionelles Menü und achte darauf, dass du
> die Flashzugriffe richtig machst, ehe du dich an Funktionspointern
> versuchst.

Und zusätzlich:
Mit Techniken wie Funktionszeigern wird man auf einem PC
wesentlich einfacher warm.
Wenn man dann weiß, was man anrichtet, macht es erst auf
einem MC Sinn.

von Lokus P. (derschatten)


Lesenswert?

> Du machst schon wieder einen Kardinalfehler nach dem anderen.
> Programmiere erst mal ein konventionelles Menü und achte darauf, dass du
> die Flashzugriffe richtig machst, ehe du dich an Funktionspointern
> versuchst.

Habs jetzt verstanden wie es abläuft.

Das menü ist ja schon komplett aufgebaut.
Mußte es jetzt nur anhand der Funktionstabelle anpassen.

Dabei hab ich ejtzt das problem das mein Untermenü bei Tastendruck nicht 
mehr weitergesprungen wird:
1
    if(MenuOnScreen)
2
    {  
3
      if(get_key_short(1<<KEY0))              // kurzer Tastendruck (PinB.6)
4
      {
5
        sub_menu_index = pgm_read_word(&menu[menu_index].next);
6
      }
7
8
      if(get_key_short(1<<KEY1))              // kurzer Tastendruck (PinB.7)
9
      {
10
        sub_menu_index = pgm_read_word(&menu[menu_index].previous);
11
      }
12
13
      if(get_key_long(1<<KEY1))              // langer Tastendruck (PinB.6)
14
      {
15
        menu_index = pgm_read_word(&menu[menu_index].text);
16
        sub_menu_index = pgm_read_word(&menu[menu_index].sub);
17
      }
18
19
      lcd_gotoxy(0,0);
20
      lcd_puts_p(pgm_read_word(&menu[menu_index].text));
21
      lcd_gotoxy(0,1);
22
      lcd_puts_p(pgm_read_word(&menu[sub_menu_index].text));
23
24
      if(menu[menu_index].ActionCode == DEF_KEY_ACTION)
25
        nKonfig = menu[menu_index].ActionArgument;
26
      else if(menu[menu_index].ActionCode == DEF_REPEAT_ACTION)
27
        nFire = menu[menu_index].ActionArgument;
28
      else if(menu[menu_index].ActionCode == SAVE_ACTION)
29
        eeprom_write_byte(00, nKonfig);
30
      else if(menu[menu_index].ActionCode == EXIT_ACTION)
31
        MenuOnScreen = 0;
32
    }
33
    else
34
...

Bei Taste KEY0 springt er mir nicht ins nächste Menü. sondern auf

const char menu_002[] PROGMEM = "** HAUPTMENUE **";  // 0

Warum?

von Karl H. (kbuchegg)


Lesenswert?

Weil du dich wieder mal mit viel zu vielen Variablen selbst ausgetrickst 
hast.

Wo wird menu_index verändert.
Was passier bei einem kurzen Druck auf KEY_0?
Was bedeutet das für menu_index?
Was heisst das dann daher folgerichtig für das nächste angezeigte Menü?

Wie spielt das hier:
>   {menu_002, 0, 0, 0, 0, NO_ACTION, 0 },
dann mit hinein?

Wie stellst du dir vor, dass da jemals irgendein anderer Menüpunkt 
'aktiviert' werden soll, wenn alle weiterführenden Indexeinträge aus 
diesem Menüpunkt heraus wieder beim Indexeintrag 0 landen?

Auch:
Das hinschreiben des Menütextes bzw. Ausführen der Aktion ist ja wohl 
nur dann notwendig, wenn eine Taste gedrückt wurde. Es macht keinen 
Sinn, das jedesmal, bei jedem Durchlauf durch die Schleife, 
durchzuführen.


> Warum?

Weil du dich noch immer mit Komplexität übernimmst, die du nicht 
beherrscht.

von Karl H. (kbuchegg)


Lesenswert?

Noch was:
Bau das alles zunächst ohne Flash auf. Also: komplettes Menü im 
Speicher. Dann hast du eine Chance, dass dir der Compiler den einen oder 
anderen Fehler findet. Und dann passiert dir sowas

        menu_index = pgm_read_word(&menu[menu_index].text);

nicht. Hier, mit dem Umweg über das Flash kann sich der Compiler nicht 
'wehren'. Er muss das so akzeptieren.
Aber so ...

        menu_index = menu[menu_index].text;

... hätte er dich längst angepflaumt, dass da etwas nicht stimmt.

Und wie immer: vorher ein Konzept zurechtlegen.
Wie soll die Menüführung prinzipiell funktionieren? Was bedeutet das für 
die Variablen? Was ist daher der Inhalt jeder Variablen? Und ruhig auch 
einmal auf dem Papier ein einfaches Menü skizzieren, inklusive 
Variablen, und durchspielen was bei einem Tastendruck zu geschehen hat. 
Welche Variable bekommt welchen Wert? Warum bekommt sie ihn? etc.

von Lokus P. (derschatten)


Lesenswert?

Karl heinz Buchegger schrieb:
> Das hinschreiben des Menütextes bzw. Ausführen der Aktion ist ja wohl
>
> nur dann notwendig, wenn eine Taste gedrückt wurde. Es macht keinen
>
> Sinn, das jedesmal, bei jedem Durchlauf durch die Schleife,
>
> durchzuführen.

da geb ich dir recht.
Jedoch weiß ich nicht wie ich sonst Zentral die Anzeige aktuallisieren 
soll.
Bei jedem Tastendruck das Display neu schreiben?
1
    if(MenuOnScreen)
2
    {  
3
      if(get_key_short(1<<KEY0))              // kurzer Tastendruck (PinB.6)
4
      {
5
        sub_menu_index = pgm_read_word(&menu[menu_index].next);
6
7
        lcd_gotoxy(0,1);
8
        lcd_puts_p(pgm_read_word(&menu[sub_menu_index].text));
9
      }
10
11
      if(get_key_short(1<<KEY1))              // kurzer Tastendruck (PinB.7)
12
      {
13
        sub_menu_index = pgm_read_word(&menu[menu_index].previous);
14
15
        lcd_gotoxy(0,1);
16
        lcd_puts_p(pgm_read_word(&menu[sub_menu_index].text));
17
      }
18
19
      if(get_key_long(1<<KEY1))              // langer Tastendruck (PinB.6)
20
      {
21
        menu_index = pgm_read_word(&menu[menu_index].text);
22
        sub_menu_index = pgm_read_word(&menu[menu_index].sub);
23
24
        lcd_gotoxy(0,0);
25
        lcd_puts_p(pgm_read_word(&menu[menu_index].text));
26
        lcd_gotoxy(0,1);
27
        lcd_puts_p(pgm_read_word(&menu[sub_menu_index].text));
28
29
        if(menu[menu_index].ActionCode == DEF_KEY_ACTION)
30
          nKonfig = menu[menu_index].ActionArgument;
31
        else if(menu[menu_index].ActionCode == DEF_REPEAT_ACTION)
32
          nFire = menu[menu_index].ActionArgument;
33
        else if(menu[menu_index].ActionCode == SAVE_ACTION)
34
          eeprom_write_byte(00, nKonfig);
35
        else if(menu[menu_index].ActionCode == EXIT_ACTION)
36
          MenuOnScreen = 0;
37
      }
38
    }
39
    else

Mal abgesehen von den Fehlern die ich dadurch erhalte:

../main.c:306: warning: passing argument 1 of 'lcd_puts_p' makes pointer 
from integer without a cast

von Karl H. (kbuchegg)


Lesenswert?

Manfred W. schrieb:

> da geb ich dir recht.
> Jedoch weiß ich nicht wie ich sonst Zentral die Anzeige aktuallisieren
> soll.
> Bei jedem Tastendruck das Display neu schreiben?

zb indem dar eigentliche LCD-Update in eine Funktion ausgelagert wird, 
die dann, wenn ein Neubeschreiben notwendig ist, ganz einfach aufgerufen 
wird.
So hat man die Logik des Update an nur einer Stelle gesammelt und kann 
sie trotzdem überall einfach benutzen.

>         lcd_puts_p(pgm_read_word(&menu[sub_menu_index].text));

>
> ../main.c:306: warning: passing argument 1 of 'lcd_puts_p' makes pointer
> from integer without a cast

Was will lcd_puts_p haben?
Was liefert pgm_read_word?

> Mal abgesehen von den Fehlern die ich dadurch erhalte:

Und nein. Den Fehler hast du nicht durch die Umstellerei erhalten. Der 
war vorher auch schon da.


Nochmal: Realisiere das erst mal alles, ohne dass du Dinge ins Flash 
verlagerst. Erst dann, wenn alles funktioniert, fängst du an, Teile ins 
Flash auszulagern.

Du führst einen 2-Fronten-Krieg und es mangelt an Erfahrung, wie man so 
etwas meistern kann.
Daher: immer schön eins nach dem anderen. Mach dir nicht selbst das 
Leben unnötig schwer. Zuerst soll das Menüsystem laufen und dann 
kümmerst du dich um die Verschiebung der Daten ins Flash und die dazu 
notwendigen Anpassarbeiten im Code.

Du hast einen Mega8 und genug SRAM, dass die paar Texte und die 
Menüstruktur da reinpassen werden. Und wenn nicht: Dann speck während 
der Entwicklung das Menü ab. Hauptsache du hast erst mal alles im SRAM 
und kannst dich auf die Programmierung der Menü-Auswertung konzentrieren 
und musst nicht zusätzlich auch noch Flashzugriffe gleichzeitig richtig 
stellen.

von Lokus P. (derschatten)


Lesenswert?

OK, ich habe die Flashroutine nun komplett entfernt.
Beim compilieren wird auch keinen Fehler mehr angezeigt.
Einen Teil der Menüanzeige habe ich in einer Funktion ausgelagert. (Ob 
es so Sinnvoll ist weiß ich jetzt noch nicht)

Was mir jetzt noch Sorgen macht sind 2 Sachen:

1.) Ich möchte gerne den eingestellten Wert (zb. der Tastenzuordnung) 
beim verlassen des Menüs erhalten haben.
Darumd achte ich mir schreibe ich diesen in die Variable nKonfig.
1
        if(menu[menu_index].ActionCode == DEF_KEY_ACTION)
2
          nKonfig = menu[menu_index].ActionArgument;
3
        else if(menu[menu_index].ActionCode == DEF_REPEAT_ACTION)
4
          nFire = menu[menu_index].ActionArgument;
5
        else if(menu[menu_index].ActionCode == SAVE_ACTION)
6
        {
7
          eeprom_write_byte(00, nKonfig);
8
          lcd_update();
9
        }
10
        else if(menu[menu_index].ActionCode == EXIT_ACTION)
11
          lcd_update();
Nur leider tut es das nicht. Ich erhalte immer 1.
Ich komm nicht dahinter.
Ein Denkanstoss wäre toll.

2.) Ich habe das Menü jetzt wieder so umstrukturiert das
1
const char menu_002[] = "** HAUPTMENUE **";  //
nun kein Teil der Menüstruktur mehr ist:
1
menustruktur menu[] = 
2
{
3
  {menu_100, 10, 0, 1, 0, NO_ACTION, 0},
4
    {menu_101, 2, 1, 0, 0, DEF_KEY_ACTION, 1},
5
    {menu_102, 3, 1, 0, 0, DEF_KEY_ACTION, 2},
6
    {menu_103, 4, 2, 0, 0, DEF_KEY_ACTION, 3},
7
    {menu_104, 5, 3, 0, 0, DEF_KEY_ACTION, 4},
8
    {menu_105, 6, 4, 0, 0, DEF_KEY_ACTION, 5},
9
    {menu_106, 7, 5, 0, 0, DEF_KEY_ACTION, 6},
10
    {menu_107, 8, 6, 0, 0, DEF_KEY_ACTION, 7},
11
    {menu_108, 9, 7, 0, 0, DEF_KEY_ACTION, 8},
12
    {menu_109, 9, 8, 0, 0, DEF_KEY_ACTION, 9},
13
  {menu_200, 21, 0, 11, 10, NO_ACTION, 0},
14
    {menu_201, 12, 11, 10, 10, DEF_REPEAT_ACTION, 0},
15
    {menu_202, 13, 11, 10, 10, DEF_REPEAT_ACTION, 1},
16
    {menu_203, 14, 12, 10, 10, DEF_REPEAT_ACTION, 2},
17
    {menu_204, 15, 13, 10, 10, DEF_REPEAT_ACTION, 3},
18
    {menu_205, 16, 14, 10, 10, DEF_REPEAT_ACTION, 4},
19
    {menu_206, 17, 15, 10, 10, DEF_REPEAT_ACTION, 5},
20
    {menu_207, 18, 16, 10, 10, DEF_REPEAT_ACTION, 6},
21
    {menu_208, 19, 17, 10, 10, DEF_REPEAT_ACTION, 7},
22
    {menu_209, 20, 18, 10, 10, DEF_REPEAT_ACTION, 8},
23
    {menu_210, 21, 19, 10, 10, DEF_REPEAT_ACTION, 9},
24
  {menu_300, 24, 10, 22, 21, NO_ACTION, 0},
25
    {menu_301, 23, 22, 21, 21, LCD_ACTION, 1},
26
    {menu_302, 23, 22, 21, 21, LED_ACTION, 1},
27
  {menu_400, 25, 21, 24, 24, SAVE_ACTION, 1},
28
  {menu_500, 25, 24, 25, 25, EXIT_ACTION, 1}
29
};
Da dies ja nur angezeigt werden soll, wenn ich im Hauptmenü bin.
Da ist jedoch leider jetzt das Problem.
Wie bekomme ich beim Rücksprung ins Hauptmenü diesen Text wieder in die 
obere Spalte?
Ist diese vielleicht doch besser in der Struktur aufgehoben um darauf 
zuzugreifen?

von Lokus P. (derschatten)


Lesenswert?

eine andere Frage:
Beim bedienen der Taster passiert es das das Display dünkler wird.
Jeh mehr Taster ich bediene umso dünkler wird es.

Ich habe das ganze jetzt mal mit einem gelöschten AVR probiert. Da tritt 
dieses Verhalten nicht auf.
Am AVR hängt auch sonst nichts außer dem Display einem Taster und 2 
taster zur Menünavigation drann.
Das Verhalten tritt nur beim Drücken des einzelnen Tasters auf.
Das hier irgendwas zuviel Strom zieht kann ich mir also nicht 
vorstellen.
Das Display ist mit 5mA angegeben.
Die Versorgung erfolgt Wahlweise über den USB-Port oder mittels 3 AA 
Batterien.

Also nehme ich fast an das die Software schuld sein müßte.

Kann es sein das der TimerInterrupt oder die Schleifen dieses Verhalten 
hervorrufen?

Code im Anhang.

von Lokus P. (derschatten)


Angehängte Dateien:

Lesenswert?

Code

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ich sehe nirgends die Stelle an der nKonfig wieder aus dem EEPROM 
ausgelesen wird und den Wert 1 von der Definition überschreibt.

Die "exotische" Schreibweise 00 z.B. eeprom_write_byte(00, nKonfig); 
wird bei anderen Werten deinem Programm irgendwann das Genick brechen.

> Beim bedienen der Taster passiert es das das Display dünkler wird.
> Jeh mehr Taster ich bediene umso dünkler wird es.

Was wird dunkler, die Zeichen auf dem Display (eher Softwareproblem) 
oder die Hintergrundbeleuchtung (eher Hardwareproblem)? Wie sind die 
Taster und das Display in Hardware verschaltet?

von Lokus P. (derschatten)


Lesenswert?

Stefan B. schrieb:
> Ich sehe nirgends die Stelle an der nKonfig wieder aus dem EEPROM
> ausgelesen wird und den Wert 1 von der Definition überschreibt.
>
Das ist richtig. Die Funktion wird momentan noch nicht genutzt. Mir ging 
es vorerst darum die Speicherfunktion zu implementieren.

> Die "exotische" Schreibweise 00 z.B. eeprom_write_byte(00, nKonfig);
> wird bei anderen Werten deinem Programm irgendwann das Genick brechen.
>
Hm, was ist denn daran falsch? Der Wert der ins EEPROM gespeichert 
werden soll liegt zwischen 1 und 9. Und der soll an die erste Stelle 
gespeichert werden.

>> Beim bedienen der Taster passiert es das das Display dünkler wird.
>> Jeh mehr Taster ich bediene umso dünkler wird es.
>
> Was wird dunkler, die Zeichen auf dem Display (eher Softwareproblem)
> oder die Hintergrundbeleuchtung (eher Hardwareproblem)? Wie sind die
> Taster und das Display in Hardware verschaltet?

Die Zeichen auf dem Display. Hab ich schon fast vermutet. Ich tippe mal 
auf den Timer. Aber wie find ich das Problem nur? Der AVR läuft mit 
8MHz. Kann das eventuell auch eine Auswirkung haben?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Also ist dein Problem nicht das Schreiben ins EEPROM sondern die 
Zuweisung an nKonfig im Programm z.B. hier?
          nKonfig = menu[menu_index].ActionArgument;

Irgendwann landest du mit den führenden Nullen bei Oktalzahlen.

Die Zeichen, hmm,

das kann einem schlechter werdenden Verhältnis von Löschen/Schreiben 
hängen. Das Programm hält sich quasi länger in Bereichen auf, wo das LCD 
gelöscht ist als in Bereichen in denen Zeichen ausgegeben sind. 
Versuchsweise LCD Löschen auskommentieren und die (ja, verstümmelte) 
Ausgabe betrachten.

Oder deine Kontrastspannung am LCD ist weniger stabil als du denkst. 
Nachmessen mit Multimeter

von Lokus P. (derschatten)


Angehängte Dateien:

Lesenswert?

Stefan B. schrieb:
> Also ist dein Problem nicht das Schreiben ins EEPROM sondern die
> Zuweisung an nKonfig im Programm z.B. hier?
>           nKonfig = menu[menu_index].ActionArgument;
>
Ja

> Die Zeichen, hmm,
>
> das kann einem schlechter werdenden Verhältnis von Löschen/Schreiben
> hängen. Das Programm hält sich quasi länger in Bereichen auf, wo das LCD
> gelöscht ist als in Bereichen in denen Zeichen ausgegeben sind.
> Versuchsweise LCD Löschen auskommentieren und die (ja, verstümmelte)
> Ausgabe betrachten.
>
Das Display wird eigentlich nur 1 mal gelöscht und das ist vor der 
While-Schleife.
Danach wird das Display immer nur überschrieben.
Was ich noch beobachtet habe. Das dunkelwerden verhält sich 
unterschiedlich. Je nachdem ob das Hauptmenü ausgewählt wurde und man 
dort navigieren kann oder nur die Wilkommensschrift angezeigt wird.
Im Hauptmenü wird es fast komplett dunkel.

> Oder deine Kontrastspannung am LCD ist weniger stabil als du denkst.
> Nachmessen mit Multimeter
Die Spannung bricht beim Drücken der Taste etwas zusammen. Je mehr 
Taster gedrückt werden umso mehr.

Was ich noch vergessen hatte war, die LCD Ausgänge als Ausgang zu 
definieren. Aber das hatte keine Auswirkung auf das Display.

Was nun?
Die Schaltng mal im Anhang.

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.