Forum: Mikrocontroller und Digitale Elektronik Menü über RS232 ausgeben


von Ralf (Gast)


Lesenswert?

Hallo,

ich mache mir grad Gedanken, wie ich über RS232 ein Menü darstellen
kann. Ich habe einige C-Beispiele für Displays gefunden, bei denen ein
struct verwendet wurde, bei dem mittels Pointer auf weitere structs
verwiesen wurde.
Die Pointer haben jeweils auf den nächsten bzw. vorhergehenden
Menü-Eintrag gezeigt, oder auf den drüber- bzw. drunterliegenden. Das
heisst, es wurde immer nur ein Eintrag angezeigt. Ich weiss nicht, ob
und wie ich dieses Schema auf mein Menü anwenden kann.

Ich möchte über die serielle Schnittstelle ein Menü ausgeben, welches
mehrere Einträge hat. Die Menü-Struktur sieht in etwa so aus:

HAUPTMENÜ
  MENU_1
    MENU_1
      usw.
    MENU_2
      usw.
    MENU_3
      usw.
  MENU_2
    MENU_1
      usw.
    MENU_2
      usw.
    MENU_3
      usw.
  MENU_3
    MENU_1
      usw.
    MENU_2
      usw.
    MENU_3
      usw.
  usw.

Also hat jedes Menü eine beliebige Anzahl von Untereinträgen, das ganze
in beliebiger Tiefe. Es soll bei Anwahl eines Eintrages entweder ein
zugehöriges Untermenü gezeigt,eine Funktion aufgerufen oder eine Ebene
zurückgesprungen werden.

Ich weiss jetzt nicht, wie ich das realisieren kann. Beim Display-Menü
ist mir der Ablauf klar, es wird ja immer nur ein Eintrag gezeigt.
Aber ich möchte ja quasi mehrere Einträge gleichzeitig darstellen und
anwählen können.

Wer kann helfen?

Ralf

von Danny (Gast)


Lesenswert?

Ich habe sowas in der Art bei meiner Technikerarbeit mit einem
"intelligenten" Touch-Display gemacht. Das war RS232 und I2C-Fähig
und man konnte Makros im Display hinterlegen die dann vom µC abgerufen
werden könnnen. Da war so ziemlich alles mit machbar, sogar Pull-Down
Menüs. Ich habe damals das EA-Kit 128 verwendet
(http://www.lcd-module.de/deu/pdf/grafik/kit128.pdf).

von Danny (Gast)


Lesenswert?

Sorry falsches Display (sollte aber egal sein)...
--> http://www.lcd-module.de/deu/pdf/grafik/kit240-6.pdf

von Karl H. (kbuchegg)


Lesenswert?

Ich wuerde das ganze so machen:

Ich mach eine struct die einen Menüeintrag definiert.
Ein Menüeintrag besteht aus einem anzuzeigenden Text sowie
einem Funktionspointer.
Ein komplettes Menue ist dann einfach ein Array aus derartigen
Einträgen.
Die Verwaltungsroutine dazu macht das übliche: Einen Menüeintrag
auswählen und vom ausgewählten Menüeintrag den Funktionspointer
nehmen und die zugehörige Funktion aufrufen. Eine derartige
Funktion kann dann selbst wieder ein Menü aufbauen usw., usw.
Ist der Funktionspointer 0, dann wird die Funktion klarerweise
nicht aufgerufen, sondern die Verwaltungsfunktion return-ed
ganz normal.

Ach was solls.
Ungefähr so (auf einem PC unter DOS programmiert):

#include <stdio.h>

#define ELEMENTS(x)  (sizeof(x)/sizeof(*x))

typedef void (MenuFnct)( void );

struct MenuEntry
{
  char      Text[20];
  MenuFnct* Function;
};

void HandleMenu( const char* MenuTitle, struct MenuEntry* Menu,
unsigned char MenuSize )
{
  int i;
  int Auswahl;

  do {

    printf( "%s\n", MenuTitle );

    for( i = 0; i < MenuSize; ++i )
      printf( "%d: %s\n", i+1, Menu[i].Text );

    do {
      printf( "\nWahl: " );
      scanf( "%d", &Auswahl );
    } while( Auswahl < 1 || Auswahl > MenuSize );

    Auswahl--;

    if( Menu[Auswahl].Function ) {
      (*Menu[Auswahl].Function)();
      printf( "\n" );
    }

  } while( Menu[Auswahl].Function );
}

void HandleNew( void )
{
  printf( "Funktion 'Neu' ausgewählt\n" );
}

void HandleOpen( void )
{
  printf( "Funktion 'Öffnen' ausgewählt\n" );
}

void HandleSave( void )
{
  printf( "Funktion 'Speichern' ausgewählt\n" );
}

void HandleCut( void )
{
  printf( "Funktion 'Ausschneiden' ausgewählt\n" );
}

void HandleCopy( void )
{
  printf( "Funktion 'Kopieren' ausgewählt\n" );
}

void HandlePaste( void )
{
  printf( "Funktion 'Einfügen' ausgewählt\n" );
}

void HandleClose( void )
{
  printf( "Funktion 'Schjließen' ausgewählt\n" );
}

void SelectMenu( void )
{
  struct MenuEntry SelectMenu[] =
    { { "Zurück",    0 } };

  HandleMenu( "Auswählen", SelectMenu, ELEMENTS( SelectMenu ) );
}

void DateiMenu( void )
{
  struct MenuEntry FileMenu[] =
    { { "Neu",       HandleNew },
      { "Öffnen",    HandleOpen },
      { "Speichern", HandleSave },
      { "Zurück",    0 } };

  HandleMenu( "Datei", FileMenu, ELEMENTS( FileMenu ) );
}

void BearbeitenMenu( void )
{
  struct MenuEntry EditMenu[] =
    { { "Ausschneiden", HandleCut },
      { "Kopieren",     HandleCopy },
      { "Einsetzen",    HandlePaste },
      { "Zurück",    0 } };

  HandleMenu( "Bearbeiten", EditMenu, ELEMENTS( EditMenu ) );
}

void AnsichtMenu( void )
{
  struct MenuEntry ViewMenu[] =
    { { "Auswählen",    SelectMenu },
      { "Schließen",    HandleClose },
      { "Zurück",    0 } };

  HandleMenu( "Ansicht", ViewMenu, ELEMENTS( ViewMenu ) );
}

int main()
{
  struct MenuEntry MainMenu[] =
     { { "Datei",       DateiMenu },
       { "Bearbeiten",  BearbeitenMenu },
       { "Ansicht",     AnsichtMenu },
       { "Beenden",     0 } };

  HandleMenu( "Hauptmenue", MainMenu, ELEMENTS( MainMenu ) );
}

von Ralf (Gast)


Lesenswert?

Hi Karl Heinz,

ui, das ist ein ordentliches Stück Code, danke. Ich werd mir das mal zu
Gemüte führen.

Ralf

von MiGu (Gast)


Lesenswert?

Hallo Karl Heinz,

dein Code sieht sehr interessant aus. Habe ihn mal nurchgearbeitet und 
versuche ihn gerade auf einen uC zu implementieren. Folgendes habe ich 
vor:

Es soll ein zweizeiliges LCD für die Anzeige verwendet werden. In der 
ersten Zeile steht das aktuelle Menü, z.B. "Hauptmenü". In der zweiten 
Zeile soll das Untermenü stehen.

Für die Bedienung sollan Tasten am uC dienen. Eine entsprechende 
Entprellroutine für "Up", "Down" und "Enter" ist vorhanden, es wird 
jeweils ein FLAG bei Betätigung gesetzt.

Die HandleMenu-Routine soll nicht in einer do-while-Schleife laufen, 
sondern es soll wieder rausgegangen werden, um weitere Aufgaben zu 
erfüllen. Statt dessen soll das jeweilige Menü über Zeiger "gemerkt" 
werden und beim nächsten Durchlauf auf die "Enter-Taste" in das 
Untermenü gesprungen werden. Es kann ja auf dem LCD immer nur ein 
Untermenü angezeigt werden.

So wollte ich deinen Code anpassen - momentan hänge ich gerade in der 
Umsetzung der Zeiger-Problematik.

Hast du eine Idee, wie man das machen könnte? Evtl über Next-Prev-Zeiger 
der MenuEvent-Struktur?

Danke im voraus.
Michael.

von Purzel H. (hacky)


Lesenswert?

Menues macht man am besten mit Statusmaschinen. Jede Aenderung 
(up,down..) andert den Status. Das laeuft dann im mmenuhaendler auf 
einen switch statement hinaus. Gewartet wird im switch nirgends. 
Dargestellt mit einer State-event-acrion matrix.

rene

von Dirk (Gast)


Lesenswert?

Hi,

Stefan war so nett seinen Code zu posten
Beitrag "LCD - Menu"

von Dirk (Gast)


Lesenswert?

Ps.: In diesen Beispiel liegt das Menu nicht Flash des Mikrocontrollers. 
Die Menueintraege sollten lieber im Flash stehen als im RAM.

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.