Forum: Mikrocontroller und Digitale Elektronik LCD Menü Struktur Navigation


von Lokus P. (derschatten)


Lesenswert?

Es gibt ja schon einige Beiträge hier die sich mit LCD Menü 
beschäftigen.
Dank dieser konnte ich mir eine ungefähre Struktur zurechtbasteln.

Jetzt wollte ich fragen wie ihr eure Menüs so designed habt.
Wie erfolgt die Auswahl?

Ich habe eine 16x2 LCD zur Verfügung.
Da es ja nun nicht Sinnvoll ist immer nur einen Eintrag anzuzeigen und 
die zweite Zeile dann leer bleibt, dachte ich mir man könnte das ganze 
mittels eines Cursors am linken Rand des Displays selektieren und mit 
einer Taste Auswählen. Das Menü scrollt dann mit dem Cursor nach oben 
oder unten mit.

Oder wie würdet ihr das gestalten?

von Ganymed (Gast)


Lesenswert?

Man kann auch einen Inkrementalen
Drehgeber nehmen. Durch Rechts-
oder Linksdehen wird das Menu herauf-
herunter gezählt.

von MagIO (Gast)


Lesenswert?

Genau so ....

oder anders ;o)

Also, das hängt ja auch von der Applikation ab. Wenn es Sinn macht auch 
während der Menü-Auswahl Status-Information auszugeben (z.B. 
Betriebsspannung .. Stromverbrauch .. irgendwelche Sensor Messwerte ... 
weiß der Geier), dann kann es natürlich auch mehr Sinn machen nur eine 
Zeile für das Menü zu benutzen und die andere für diese Informationen 
frei zu halten. Dann wiederum fände ich es persönlich schöner, wenn das 
Menü nach rechts und links scrollt. Die andere Frage ist dann, ob sich 
die Mühe auch lohnt.

von Lokus P. (derschatten)


Lesenswert?

> Genau so ....
>
> oder anders ;o)
>
> Also, das hängt ja auch von der Applikation ab. Wenn es Sinn macht auch
> während der Menü-Auswahl Status-Information auszugeben (z.B.
> Betriebsspannung .. Stromverbrauch .. irgendwelche Sensor Messwerte ...
> weiß der Geier), dann kann es natürlich auch mehr Sinn machen nur eine
> Zeile für das Menü zu benutzen und die andere für diese Informationen
> frei zu halten. Dann wiederum fände ich es persönlich schöner, wenn das
> Menü nach rechts und links scrollt. Die andere Frage ist dann, ob sich
> die Mühe auch lohnt.

Drehencoder ist für diese Zwecke oversized.
Es handelt sich grad mal um max 4 Menüeinstellungen die jeweils als 
einen Untermenüpunkt haben sollen.

Links/rechts wäre natürlich auch schön. Und in der oberen Zeile wird 
dann der Übergeordnete Menüpunkt angezeigt.

von MagIO (Gast)


Lesenswert?

Der Phantasie sind keine Grenzen gesetzt ....
man kann auch die übergeordneten Menüpunkte als Grafik am Rand 
darstellen ;o) Gibt ja schließlich 8 user defined characters.

von Lokus P. (derschatten)


Lesenswert?

Ich hab mir jetzt mal etwas gebastelt:
1
#define MENU_SIZE    (sizeof(menu_text) / sizeof(*menu_text))
2
3
// LCD-Menüeinträge definieren
4
// ===========================
5
const char Menu_0[] PROGMEM = "** Hauptmenu ** 1\n";
6
const char Menu_1[] PROGMEM = "Tastenzuordnung ";
7
const char Menu_2[] PROGMEM = "Dauerfeuer      ";
8
const char Menu_3[] PROGMEM = "Konfiguration   ";
9
const char Menu_4[] PROGMEM = "Speichern       ";
10
const char Menu_5[] PROGMEM = "Beenden         ";
11
12
13
// Tabelle von Zeigern auf die Texte erstellen
14
// ===========================================
15
const char *menu_text[] PROGMEM =
16
{
17
  Menu_0,
18
  Menu_1,
19
  Menu_2,
20
  Menu_3,
21
  Menu_4,
22
  Menu_5
23
};
24
25
volatile uint8_t MenuOnScreen = 1;
26
volatile uint8_t menu_index = 1;
27
28
int main(void)
29
{
30
  init();                            // Einschaltsequenz starten
31
  sei();                            // Interrupts aktivieren
32
33
  while(1)
34
  {
35
36
    if(get_key_short(1<<KEY0) && Summe == 0)        // kurzer Tastendruck (PinB.6)
37
    {
38
      MenuOnScreen = 1 - MenuOnScreen;            // LCD-Hauptmenü anzeigen
39
      lcd_clrscr();
40
      lcd_puts ((const char*) pgm_read_word(&menu_text[0]));
41
    }      
42
      
43
    if(MenuOnScreen)
44
    {
45
      if(get_key_short(1<<KEY0))              // kurzer Tastendruck (PinB.6)
46
      {
47
        if(menu_index < MENU_SIZE - 2)
48
        menu_index++;
49
      }
50
51
      if(get_key_short(1<<KEY1))              // kurzer Tastendruck (PinB.7)
52
      {
53
        if(menu_index > 1)
54
        menu_index--;
55
      }
56
57
      if(get_key_long(1<<KEY0))              // langer Tastendruck (PinB.6)
58
      {
59
        eeprom_write_byte(00, nKonfig);          // Wert in EEPROM speichern
60
      }
61
62
      lcd_puts ((const char*) pgm_read_word(&menu_text[menu_index]));
63
64
    }
65
    else
66
    {
67
68
....

(noch nicht getestet obs funktioniert)

jetzt hätte ich mir vorgestellt am Anfang bzw. Ende des Textes einen < 
oder > anzuzeigen wenn das Menü noch weiter geht.

Soll ich das am besten gleich in die Textvariable schreiben oder als 
zusätzliche String zum Text anfügen?

Wie mach ich das am besten?

von Lokus P. (derschatten)


Lesenswert?

ich hänge hier:
1
lcd_puts_P (menu_text[menu_index]);

Invalid initializer

Was stimmt da nicht?
Laut Anleitung müßte der Befehl die Werte aus dem Speicher auslesen 
können

von Chris M. (shortie)


Lesenswert?

weil der Code eine nette Menüfunktion implementiert hat habe ich den mir 
als Bookmark vor längerer Zeit mal gespeichert. Allerdings bislang nicht 
getestet, aber vielleicht ist er für dich hilfreich.

http://www.paddy-ol.de/index.php?option=com_content&task=view&id=27&Itemid=1

von Patrick W. (paddy)


Lesenswert?

@Chris M.

Danke, den Link hätte ich jetzt auch gepostet, denn das ist meine eigene 
Homepage. Freut mich, dass auch jemand das Zeugs liest was ich auf die 
Homepage stelle.

Der Code ist nicht besonders optimiert, aber zumindest lauffähig. Für 
Diskussion und Verbesserung bin ich immer offen, auch wenn ich aktuell 
wenig Zeit habe für die Atmels wegen den Klausuren.

Gruß Paddy

von 2ZeilenLCD (Gast)


Lesenswert?

Hallo Manfred,

genau so ein Menü habe ich auch auf einem 2x16 Display von DOGM 
aufgesetzt.

Per Drehencoder wird vertikal durch das Menü gesteuert.
Mit OK wechselt man in den Menü Punkt als geht eine Ebene tiefer.
Mit BACK kann man in der Menü Hierachie wieder eine Ebene aufsteigen.
Mittels LEFT und RIGHT kann innerhalb eines Eingabescreens (z.b. 
Frequenz Eingabe für PWM) die Dezimalstelle ausgewählt werden, ansonsten 
kann auch hier der Wert per Drehencoder inkrementiert / dekrementiert 
werden...

Eigentlich hätte man auf LEFT / RIGHT auch verzichten können...
auch die OK Taste ist unnötig, weil der Drehencoder selbst auch als 
Taster dient... bzw. dieser hat bei Druck eine Tasterleitung zum uC...

Ahja, ein Video zu dem Menü findest du hier:
http://www.youtube.com/watch?v=GhUI7uQmt_c

Ich muss allerdings zugeben, dass ich hier leider nichts kommentiert 
habe und die Qualtität auch nicht so der Hit ist, aber zumindest das 
Prinzip wird klar ;-)

Kurz zu dem was ich da auf dem Video mache (vermutlich erkennt man es 
nicht):

1. Zunächst navigiere ich durchs Menü, wähle PWM1 und stelle dort eine 
Frequenz von 900 Hz ein.

2. Ich wähle einen RECORD Modus, bei dem ich am Analog Eingang eine 
Spannung sample... ich drehe zur Stimulation des Analogeingang ein paar 
mal wirklich an einem Poti ;-)

3. Danach spiele ich die aufgenommene Sequenz am Analogausgang wieder 
ab... am Oszi sieht man dann den Verlauf, den ich zuvor per Stimulation 
aufgenommen habe...

4. Ich wechsle in den Menüpunkt System --> Beleuchtung und verstelle die 
Display Helligkeit ;-) Kleine Spielerei, die Helligkeit ist per PWM 
geregelt (und einer KSQ)... hier wird eigentlich nur der Tastgrad von 0% 
- 100 % verändert...

viele Grüße

von Lokus P. (derschatten)


Lesenswert?

Grüß dich!

Über dieses Video bin ich vor einigen Tagen gestolpert.
Sieht sehr professionell aus das ganze.

Das mit dem Encoder ist eine feine Sache, aber wie gesagt für meine 
Zwecke etwas unpraktisch.

Im Prinzip reichen mir 2 Tasten.

Wird eine der tasten länger gedrückt gelangt man ins Menü. Wo man dann 
mittels links/rechts durch die Menüpunkte navigiert.
Oder dort wird mit einem längerem Tastendruck ins Untermenü gewechselt 
wo ebenfalls wieder links/rechts - langer tastendruck die Option gewählt 
wird.

Über "Beenden" kommt man dann wieder aus dem Menü.

Ich freunde mich gerade mit den LCD Funktionen von Volker Oth's an: 
http://homepage.hispeed.ch/peterfleury/group__pfleury__lcd.html#gd7760569f1a160fca1a29af711cab47b

Ich hänge momentan nur bei der lcd_puts_p Funktion.

Wenn ich hier mit Variablen arbeiten möchte funktioniert das nicht so 
richtig:
1
lcd_puts_p (menu_text[menu_index]);

AVR Studio zeigt mir zwar keinen Fehler, allerdings bekomme ich nur 
kryptische Zeichen am Display.

von spess53 (Gast)


Lesenswert?

Hi

>Ich hänge momentan nur bei der lcd_puts_p Funktion.

Kann lcd_puts_p Text aus dem Flash ausgeben?

MfG Spess

von Lokus P. (derschatten)


Lesenswert?

spess53 schrieb:
> Hi
>
>>Ich hänge momentan nur bei der lcd_puts_p Funktion.
>
> Kann lcd_puts_p Text aus dem Flash ausgeben?
>
> MfG Spess

Ja, genau dafür ist er gemacht:
1
void lcd_puts_p  (  const char *  progmem_s   )   
2
 
3
   Display string from program memory without auto linefeed. 
4
5
6
Parameters:
7
 s  string from program memory be be displayed  
8
9
Returns:
10
none 
11
See also:
12
lcd_puts_P

Mit
1
lcd_puts_p (menu_text[0])
haut das auch wunderbar hin. Nur mit den Variablen nicht.

von Lokus P. (derschatten)


Lesenswert?

hab noch was herausgefunden:
Selbst so funtkioniert es nicht:
1
lcd_puts_p (menu_index);

Fehler:
../main.c:251: warning: passing argument 1 of 'lcd_puts' makes pointer 
from integer without a cast

Wenn ich das ganze ohne PROGMEM und mit dem "lcd_puts" mache gehts.

Seltsam...

von lcdmenue (Gast)


Lesenswert?

dann schnell eine lcd_puts_P  per copy und paste erstellen
die lcd_puts  kopieren umbenennen
in diese _P den eintrag pgm_read_byte ( ... )  an die richtige stelle 
setzen ... und trallala es geht


für LCDs  lassen sich prima strukturen machen
1
struct
2
{
3
 unsigned char level;
4
 char * text;
5
 void (*f_pointer)(void); // funktion die aufgerufen werden soll
6
}t_menu;
7
8
9
const char Menu_0[] PROGMEM = "** Hauptmenu ** 1\n";
10
const char Menu_1[] PROGMEM = "Tastenzuordnung ";
11
const char Menu_2[] PROGMEM = "Dauerfeuer      ";
12
const char Menu_3[] PROGMEM = "Konfiguration   ";
13
const char Menu_4[] PROGMEM = "Speichern       ";
14
const char Menu_5[] PROGMEM = "Beenden         ";
15
16
17
t_menu menu[] PROGMEM = {
18
{0 , Menu_0 , NULL }
19
  {1 , Menu_1 , funktion_für_naechste_ebene}, 
20
     {2 , Menu_1_unterpunkt1 , funktion_für_naechste_ebene}
21
        {3 , Menu_1_unterunterpunkt1 , foo }
22
        {3 , Menu_1_unterunterpunkt2 , foo}
23
     {2 , Menu_0_unterpunkt2 , NULL }
24
  {1 , Menu_2 , funktion_für_naechste_ebene},
25
     {2 , Menu_2_unterpunkt1 , foo}
26
     {2 , Menu_2_unterpunkt2 , foo}
27
  {1 , Menu_3 , foo },
28
  {1 , Menu_4 , foo },
29
  {1 , Menu_5 , foo }
30
}

da in dem menüarray nur pointer auf texte sind kann man da auch mit 
mehreren sprachen arbeiten
wer funktionen mit übergabewert will
baut sich die sturctur etwas um

void (*f_pointer) ( unsigned char wert);

von Lokus P. (derschatten)


Lesenswert?

Hi,

die lcd_puts_p sieht so aus:
1
/*************************************************************************
2
Display string from program memory without auto linefeed 
3
Input:     string from program memory be be displayed                                        
4
Returns:   none
5
*************************************************************************/
6
void lcd_puts_p(const char *progmem_s)
7
/* print string from program memory on lcd (no auto linefeed) */
8
{
9
    register char c;
10
11
    while ( (c = pgm_read_byte(progmem_s++)) ) {
12
        lcd_putc(c);
13
    }
14
15
}/* lcd_puts_p */

sollte doch eigentlich passen oder?

lcd_puts sieht dagegen so aus:
1
void lcd_puts(const char *s)
2
/* print string on lcd (no auto linefeed) */
3
{
4
    register char c;
5
6
    while ( (c = *s++) ) {
7
        lcd_putc(c);
8
    }
9
10
}/* lcd_puts */

Wird bei deiner Struktur die Funtion für das entsprechende Menü sofort 
ausgeführt wenn es angewählt wird? Oder wie ist das angedacht?

von Lokus P. (derschatten)


Lesenswert?

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

Bräuchte mal hilfe.

../main.c:137: warning: initialization discards qualifiers from pointer 
target type
../main.c:137: warning: initialization makes pointer from integer 
without a cast

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.