MenuDesigner

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche
Lcd-menu-demo.jpg

Menüsystem für monochrome GLCDs

Idee

MenuEdit.png
MenuInterpreter-demo.png
Menuedit-color-dialog.png
Menuinterpreter-pc-test-color.png

Die Idee war es, ein möglichst einfaches Menüsystem für kleinere LCDs zu haben, welches sich leicht erstellen lässt und dennoch die wichtigsten Elemente moderner Deskop GUIs zu bieten. Außerdem sollte der Flashverbrauch niedrig gehalten werden und nicht zwangsweise mit komplexeren Menüs immer größer werden. Über die Jahre kamen einige Features hinzu, so dass das System inzwischen auch 7 Segment Anzeigen und farbige LCDs unterstützt.

Features

  • Nicht an einen bestimmten LCD Controllertyp gebunden
  • Grafischer Editor für Linux und Windows
  • Benötigt 5KB Flash (bei einem ATMega8 und 16Bit Adressen)
  • Auch als PC Programm testbar
  • Sehr geringer statischer RAM Verbrauch (allerdings durchaus etwas mehr Stack)
  • Der Sourcecode steht unter der GPL, der auf der Mikrocontroller benötigte Code steht unter der Mozilla Public License 2.0.
  • Abspeichern der Menüstruktur als kompakte Bytecodes auf einem beliebigem wahlfrei lesbarem Speicher
  • Die Menüstruktur darf bis zu 16MB groß werden (24/32 Bit Adressen) oder 64KB bei 16 Bit Adressen
  • Die Navigation innerhalb des Menüs ist auf eine Bedienung mit wenigen Tasten optimiert. Alternativ kann auch eine Maus oder ein Touchscreen verwendet werden (die Liste wird hier bis auf weiteres aber nicht vollständig unterstützt).
  • Unterstützung von verschiedenen Fonts
  • Generell kann zwischen Objekten innerhalb eines Fensters mit zwei Tasten, ähnlich wie bei der TAB Taste, hin und her gewechselt werden „Fokus“. Mit einer weiteren Taste „Enter“ können dann dem Objekt zugeordnete Aktionen ausgeführt werden.
  • Objekte des Menüsystems:
    • Fenster: Enthält mehrere weitere Objekte und füllt üblicherweise den Bildschirm des LCDs komplett aus.
    • Unterfenster: Kann ebenfalls weitere Objekte enthalten, wobei nur ein Teil des Bildschirms ausgefüllt wird und in dem restlichem Teil des Bildschirms weiterhin das ursprüngliche Fenster zu sehen ist
    • Box: Dient dazu Teile des Bildschirms flächendeckend weiß oder schwarz zu füllen. Ebenfalls verwendbar für horizontale und vertikale Linien, sowie als „Löschfunktion“.
    • Button: Zeigt Text an und kann mit Aktionen belegt werden. Wahlweise mit oder ohne Umrandung einsetzbar.
    • Label: Einfaches Objekt zum Anzeigen von Text
    • GFX: Zeigt Pixelgrafiken an und unterstützt eine einfache Längenkompression. Ebenfalls mit Aktionen belegbar. Zusätzlich lässt sich sehr leicht zwischen verschiedenen Darstellungen umschalten, was sich gut für Animationen eignet.
    • Checkbox: Bietet eine Auswählbare Schaltfläche mit Text an. Mit Aktionen belegbar.
    • Groupbutton: Ähnlich wie eine Checkbox, jedoch kann immer nur ein Groupbutton innerhalb einer Gruppe aktiv sein.
    • List: Generiert eine Liste inklusive Positionsbalken an der rechten Seite. Ein Element ist auswählbar. Mit Aktionen belegbar.
    • Shortcut: Nicht sichtbar. Bietet das direkte Ausführen von Funktionen an, ohne dass erst ein Objekt einen Fokus haben muss.
    • Globaler Shortcut: Wie ein Shortcut, jedoch in jedem Fenster aktiv. Beispielsweise nützlich um aus jedem Fenster heraus zu einer Fehlermeldung springen zu können.
  • Generell lässt sich die Fokusierbarkeit aller Objekte auch deaktivieren.
  • Fokusierte Objekte können eine andere Schriftart verwenden.
  • Unter „Aktionen“ ist folgendes möglich: Den Wechsel zu einem anderem (Unter)fenster und/oder der Aufruf der Funktion menu_action mit einer individuellen Nummer als Parameter. Das bedeutet, dass der Wechsel zwischen einzelnen Fenster keinen zusätzlichen Aufwand beim Programmieren benötigt.
  • Statische Texte und Grafiken können in der Menüstruktur abgelegt werden, dynamische im RAM.
  • Kommt ohne Interrupts, Delays u.ä. aus.
  • Einfache Umschaltung zwischen verschiedenen Sprachen zur Laufzeit.
  • Eignet sich sowohl für schwarz weiß, graustufen als auch für farbige Anzeigen. Die Anzahl der Bits pro Farbkanal kann eingestellt werden und Grafiken werden gegebenenfalls automatisch passend konvertiert.
  • Als reduzierte Version auch für 7 Segment Anzeigen verwendbar.

Einschränkungen

  • Die LCD Auflösung ist auf 4096x4096 begrenzt
  • Listen funktionieren mit Touchdisplays bisher nur eingeschränkt
  • Objekte haben ihren festen Platz auf dem Bildschirm, ein Verschieben zur Laufzeit ist nicht möglich.
  • Animationen sind nur schwer zu realisieren
  • Es lassen sich maximal 16 verschiedene Groupbuttons je Gruppe verwenden. Es sind maximal 16 verschiedene Gruppen möglich
  • Die Anzahl der unterschiedlichen Checkboxen ist auf 256 begrenzt
  • Die Anzahl der unterschiedlichen Listen ist auf 256 begrenzt und die Zeilenzahl auf ~10000
  • Die Anzahl der unterschiedlichen Indexe von Multi-Grafiken ist auf 256 begrenzt und jede Multi-Grafik unterstützt maximal 65536 verschiedene darstellbare Bitmaps.

Die Limits sind sicher hoch genug, dass es für fast alle Anwendungsfälle reichen müsste.

Funktionsweise

Menuinterpreter-schema.png

Die Funktionen für die Grafikausgabe und dem Zugriff auf die Menüstruktur muss selbst geschrieben werden. Dies ermöglicht eine Anpassung an eigene Displays und beliebige Speicher.

Bei der Grafikausgabe, wird vor jedem Neuzeichnen einmal menu_screen_clear aufgerufen. Die Funktion ist deswegen nicht als einzelne menu_screen_set Aufrufe integriert, weil es oftmals einfach schnellere Methoden zum Löschen eines Bildschirms gibt, als jeden Pixel einzeln zu setzen.

Die menu_screen_set Funktion setzt beim Neuzeichnen alle Pixel, wobei bei übereinander liegenden Objekten der gleiche Pixel mehrfach gesetzt werden kann. Es muss darauf geachtet werden, dass bei dem Funktionsaufruf die Bildschirmgröße noch nicht beachtet wird. Zum Schluss eines Neuzeichnens, wird einmalig menu_screen_flush() aufgerufen. Dann sollte der zuvor durch menu_screen_set gesetzte Inhalt wirklich auf das LCD geschrieben werden. Zwar kann auch stattdessen menu_screen_set direkt jeden Pixel auf dem LCD setzten, dann wird jedoch eventuell der Bildaufbau sichtbar und beim mehrfachen setzen des gleichen Pixels kann dies unnötig lange dauern.

menu_byte_get muss dem Interpreter die Daten der Menüstruktur liefern. Die Implementierung kann aus einem simplen Arrayzugriff oder aber aus einer komplexen Leseroutine für externe EEPROMs oder MMC bestehen. Generell sollte jedoch Speicher mit langer Latenz vermieden werden. Ist die Menüstruktur fehlerhaft, kann es zu Leseversuchen außerhalb der Größe der Menüstruktur kommen, ansonsten sollte dies nicht vorkommen.

menu_action wird immer dann aufgerufen, wenn ein Objekt mit einer Aktion belegt wurde. Das Ändern der Auswahl in einer Liste wird ebenfalls automatisch eine eigene Aktion zugewiesen. Als Parameter wird eine eindeutige 16Bit Nummer übergeben. Im MenüDesigner wird einer Aktion ein Name gegeben. Alle Namen werden automatisch durchnummeriert und eine Header Datei generiert, welche die Zuordnung Nummer - Aktion Name ermöglicht. Als Rückgabe kann angegeben werde ob die Aktion ein Neuzeichnen des Bildschirms erfordert. Dies ist sinnvoll wenn kein Bildschirmwechsel erfolgt, aber sich auf dem aktuellem etwas geändert hat, z. B. ein anderer Text gesetzt wurde.

Indexnummern für Dynamische Texte und Grafiken, die Eigenschaften von Radiogroups und Checkboxen werden auf eine ähnliche Weise automatisch generiert und sind dann unter dem eingestellten Namen in den Arrays auffindbar.

Dynamische Texte müssen generell wie in C Nullterminiert (\0) sein und haben keine Längenbeschränkung. Der Inhalt einer Liste ist ein langer Text, wobei \n eine neue Zeile markiert. Grafiken werden gelesen, bis der letzte Pixel der fest eingestellten Größe gesetzt ist.

menu_redraw sollte immer dann aufgerufen werden, wenn sich dynamische Texte/Grafiken geändert haben und einmal zu Beginn des Programms.

menu_keypress ist die generelle Eingabemöglichkeit des Menüs. Je nach eingestellten Key werden die entsprechenden Aktionen ausgeführt. Beispielsweise „Fokus aufs nächste Objekt setzen“. Der Parameter darf einen Wert von 1 bis 255 haben.

Ab Version 1.4 kann zusätzlich zu der Funktion menu_keypress der Aufruf menu_mouse verwendet werden. Dieser besitzt als weitere Parameter die Bildschirmkoordinaten. Der Key Parameter wird auf das Objekt angewendet, welches sich an den entsprechenden Bildschirmkoordinaten befindet. Der aktuelle Fokus wird ignoriert und nicht geändert.

Ab Version 1.5 gibt es optional die Möglichkeit mehrere Sprachen zu unterstützen. Hierzu kann für jede Sprache im Editor ein eigener Text hinterlegt werden und dann mit der Funktion menu_language_set eine anzuzeigende Sprache ausgewählt werden. Maximal sind 255 verschiedene Sprachen möglich.

Ab Version 1.6 lässt sich für GFX Objekte 'Multi-image' auswählen. In diesem Fall wird das ausgewählte Bitmap vertikal in mehrere Bilder zerlegt. Über die Variable menu_gfxindexstate[] lässt sich dann einstellen, welches angezeigt werden soll. Ist der Index größer als die Anzahl der Bilder, wird der Wert beim nächsten Zeichnen auf 0 gestellt, so dass sich mit einem periodischem Hochzählen und Neuzeichnen ohne Bereichsüberprüfung leicht endlos laufende Animationen realisieren lassen.

In der Version 1.7 sind zusätzlich zu den seit Beginn vorhandenen 5x7 Pixel Schriftarten noch besonders kompakte 5x5 Pixel Schriftarten hinzugekommen. Des Weiteren wird jetzt noch etwas kompakterer Code generiert, wenn Objekttypen nicht verwendet werden.

Ab Version 2.0 werden farbige Anzeigen unterstützt. Der Bytecode ist noch etwas kompakter geworden (und damit leider nicht mehr zu den vorherigen Versionen kompatibel). Der 8x16 Font wurde neu gestaltet und die Lizenz für den auf der Seite des Mikrocontroller benötigten Code erlaubt eine Nutzung zusammen mit Closed Source.

Weiterentwicklung

Falls es Interesse an weiteren Features gibt, bin ich - je nach Funktion - gerne bereit diese zu Implementieren. Schreibt am besten ins Forum.

Download

Beitrag in der Codesammlung

Fertige .hex Datei zum Testen auf einem ATMega8

Der aktuelle Code bei Sourceforge