Menü

Wechseln zu: Navigation, Suche

Diese Seite beschreibt das Menüprojekt von Clemens Helfmeier. Es dient der einfachen Umsetzung von Menüstrukturen und Bedienungsführung in Mikrocontrollern mit LC-Display.

by Clemens Helfmeier

Last update: 2010-06-10 (initial page)

Überblick

Das Menüprojekt ist eine Bibliothek einiger Funktionen, die es ermöglichen auf einfache Weise eine Bedienführung in einem AVR zu implementieren. Die Bibliothek ist sehr allgemein gehalten und kann leicht auch auf andere Architekturen portiert werden.

Verwendung

Man packe das menu-Verzeichnis in sein Projektverzeichnis

Makefile anpassen

Die folgenden Dateien müssen zusätzlich kompiliert und gelinkt werden (zu den Objects hinzufügen): menu/menu.c menu/menu_input.c menu/menu_output.c menu/menu_utils.c

Bibliothek konfigurieren

Die Bibliothek wird mit der Datei 'menu_conf.h' konfiguriert. Hierin müssen folgende Sachen festgelegt werden (siehe auch 'example/menu_conf.h'):

/** The MAIN_MAIN macro can be used to handle other 
 * tasks in the program. Gets executed in a loop.
 */
void main_main( void );
#define MAIN_MAIN()             do { main_main(); } while (0)

/** The MENU_GET_ACTION macro should return nonzero if
 * there is an action detected.
 * It should put ai to the action detected.
 */
#define MENU_GET_ACTION( ai )   ai = 2

/** number of different actions (numbered from 0 to max)
 * possible (e.g. number of push buttons)
 */
#define MENU_ACTION_COUNT       5

In der Datei 'processor.h' muss noch die Funktionalität die der Prozessor/das Betriebssystem falls vorhanden, zur Verfügung stellt korrigiert werden: Dazu gehören in erster Linie die atomaren Bit-Setz- und Bit-Löschbefehle sowie die Unterbringung der Variablen im richtigen Speicher (STATIC_CONST*). Am einfachsten ist es, wenn man sich die 'processor.h' aus dem example-Ordner kopiert.

Bibliothek verwenden

Nachdem die Voraussetzungen aus den beiden vorigen Kapiteln erfolgreich erfüllt wurden, kann die Bibliothek verwendet werden:

Man definiert seine Menüstruktur im Flash z.B. durch:

/* declare a menu structure:
 we have three screens, sroot 
 we need prototypes since the reference each other
 */
extern STATIC_CONST_DECL menu_screen_t sroot;
extern STATIC_CONST_DECL menu_screen_t screen1;
extern STATIC_CONST_DECL menu_screen_t screen2;

/* root screen */
STATIC_CONST_DECL char s_sroot[] = "Root Menu";
STATIC_CONST_DECL menu_screen_t sroot = {
    .lines = 2,
    .actions = {
        { .type = MENU_ACTION_SCREEN_DESCEND, .content.screen = &screen1, },
        { .type = MENU_ACTION_SCREEN_RETURN },
    },
    .items = {
        { .type = MENU_ITEM_PSTRING, .content.pstring = s_sroot, .pos_x = 4, .pos_y = 1, },
        { .type = MENU_ITEM_TERMINATOR, },
    },
};
/* screen 1 */
STATIC_CONST_DECL char s_screen1[] = "Screen One";
STATIC_CONST_DECL menu_screen_t screen1 = {
    .lines = 4,
    .actions = {
        { .type = MENU_ACTION_SCREEN_SWITCH, .content.screen = &screen2, },
        { .type = MENU_ACTION_SCREEN_RETURN },
        { .type = MENU_ACTION_SCREEN_SCROLL_DOWN },
        { .type = MENU_ACTION_SCREEN_SCROLL_UP },
    },
    .items = {
        { .type = MENU_ITEM_PSTRING, .content.pstring = s_screen1, .pos_x = 0, .pos_y = 0, },
        { .type = MENU_ITEM_CSTRING, .content.cstring = "L1" , .pos_x = 0, .pos_y = 1, },
        { .type = MENU_ITEM_CSTRING, .content.cstring = "L2" , .pos_x = 0, .pos_y = 2, },
        { .type = MENU_ITEM_CSTRING, .content.cstring = "L3" , .pos_x = 0, .pos_y = 3, },
        { .type = MENU_ITEM_TERMINATOR, },
    },
};

/* screen 2 */
STATIC_CONST_DECL char s_screen2[] = "Screen Two";
STATIC_CONST_DECL menu_screen_t screen2 = {
    .lines = 2,
    .actions = {
        { .type = MENU_ACTION_SCREEN_SWITCH, .content.screen = &screen1, },
        { .type = MENU_ACTION_SCREEN_RETURN },
    },
    .items = {
        { .type = MENU_ITEM_PSTRING, .content.pstring = s_screen1, .pos_x = 0, .pos_y = 0, },
        { .type = MENU_ITEM_CSTRING, .content.cstring = "max4" , .pos_x = 15, .pos_y = 1, },
        { .type = MENU_ITEM_TERMINATOR, },
    },
};

Hat man in seiner Menüstruktur grundlegende Tastenbelegungen, so kann man auch leicht diese komplexen Strukturen durch Makros erzeugen und sich somit viel Schreibarbeit sparen.

Diese Menüstruktur kann nun aufgerufen werden:

menu_main( &sroot );

Möchte man, dass das Menü nicht verlassen werden kann, so gibt man sicherheitshalber eine Endlosschleife:

while (1) menu_main( &s_root );

Der Prozessor startet dann das Menü und durch Interaktion des Benutzers mit der Eingangsroutine kann er durch das Menü browsen.

Download

Die Menübibliothek hat noch kein eigenes SVN-Repository. Die Dateien können im Repository vom Autopiloten gefunden werden. Dort gibt es im Ordner "terminal" auch ein Beispiel der Verwendung.

Hier ist der Download der Menü-Dateien Menü-Tarball

Die processor.h Datei findet man hier: processor.h

Ein Beispiel für eine Menüconfigurationsdatei gibt es hier: menu_conf.h

Interna

Es gibt 3 Dateien:

'menu.c': hierin ist der Kern der Bibliothek, die Funktion, die das Handling übernimmt.
'menu_input.c': in dieser Datei sind die Teile der Bibliothek enthalten, die mit der Eingabe des Benutzers korrespondieren.
'menu_output.c': diese Datei enthält die Ausgaberoutinen für das Display.
'menu_utils.c': einige nicht zuordnungsbare Funktionen sind hierin enthalten.

Im Quellcode der Applikation muss nun noch die folgenden Dateien liegen:

'menu_conf.h': hier wird die Bibliothek konfiguriert
'processor.h': Diese Datei enthält die Eigenheiten des Prozessors und ggf. Compilers.

Das Menü wird nun über die Ausgaberoutine in 'menu_output.c' angezeigt. Danach wird solange das MENU_MAIN Makro aufgerufen, bis eine Eingabe in 'menu_input.c' erkannt wurde.

Das Menü ist in seiner Struktur (Baumstruktur) im Flash abgelegt. Hierzu werden die Strukturen aus 'menu.h' verwendet und gefüllt. Im Quellcode von 'menu.h' wird recht gut erläutert, wie das funktioniert. Für ein Beispiel, siehe die Dateien im Verzeichnis 'example'. Auch eine vollständige Konfigurationsdatei und Prozessordatei liegen dort.