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
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).
Sorry falsches Display (sollte aber egal sein)... --> http://www.lcd-module.de/deu/pdf/grafik/kit240-6.pdf
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 ) ); }
Hi Karl Heinz, ui, das ist ein ordentliches Stück Code, danke. Ich werd mir das mal zu Gemüte führen. Ralf
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.
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.