Zum Inhalt springen

U8g2-Anleitung für OLED- und LCD-Displays mit Arduino ​

Diese Anleitung bringt ein neues U8g2-Projekt von einer leeren Lopaka-Zeichenfläche bis zu einem funktionierenden Arduino-Sketch. Lopaka erzeugt den Zeichencode; du schließt das Display an und initialisierst es, wählst die Pufferung und entscheidest, wann welcher Screen angezeigt wird.

Was ist U8g2? ​

U8g2 ist eine Grafikbibliothek für monochrome OLED- und LCD-Displays. Sie unterstützt viele Controller, Zeichenprimitive, Bitmaps und eine große Sammlung von Schriftarten. Lopaka erzeugt Code für die grafische U8g2-API, nicht für die reine Text-API U8x8.

Prüfe mit dem offiziellen Setup-Tutorial und der Konstruktorliste, ob U8g2 genau dein Display unterstützt.

Bevor du anfängst ​

Du brauchst:

  • Einen Mikrocontroller und ein monochromes Display, das U8g2 unterstützt.
  • Den Namen des Display-Controllers, die Auflösung und die Schnittstelle, zum Beispiel SSD1306, 128×64, Hardware-I2C.
  • Das Datenblatt des Displays oder die Verdrahtungsanleitung des Herstellers.
  • Ein Arduino-kompatibles Projekt, mit dem du einen einfachen Sketch kompilieren und hochladen kannst.

Achtung

Lopaka erkennt deine Hardware nicht. Zwei Module, die gleich aussehen, können unterschiedliche Controller, Adressen, Pinbelegungen oder Display-Offsets haben.

Schritt 0: U8g2 installieren und testen ​

Öffne in der Arduino IDE Tools → Manage Libraries, suche nach U8g2 und installiere die Bibliothek von olikraus. So beschreibt es auch das offizielle U8g2-Repository.

Für eine manuelle Installation in Arduino lädst du die offizielle U8g2-Arduino-Distribution herunter und fügst ihr ZIP über Sketch → Include Library → Add .ZIP Library hinzu. Andere Toolchains können dieselbe offizielle Distribution über ihre Verwaltung von Bibliotheksabhängigkeiten nutzen. Nimm bevorzugt eine veröffentlichte Version, außer du brauchst gezielt eine noch unveröffentlichte Änderung.

Bevor du Lopaka-Code hinzufügst, kompiliere eines der U8g2-Beispiele für dein Display und lade es hoch. Läuft das Beispiel, stimmen Konstruktor, Verdrahtung und Installation der Bibliothek.

Schritt 1: Display-Konstruktor wählen ​

Der Name des Konstruktors legt vier wichtige Dinge fest:

TeilBeispielBedeutung
Controller und DisplaySSD1306_128X64_NONAMEHardwarefamilie und Auflösung
PufferF, 1 oder 2Vollbild- oder Seitenpuffer
SchnittstelleHW_I2C, SW_I2C, 4W_HW_SPI usw.Bus und Implementierung
ArgumenteU8G2_R0, Reset- und Bus-PinsDrehung und Verdrahtung

Zum Beispiel:

cpp
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(
    U8G2_R0,
    U8X8_PIN_NONE
);

Das ist nur ein Beispielkonstruktor für ein 128×64-SSD1306-Display mit Hardware-I2C. Ersetze ihn durch den genauen Konstruktor und die Argumente aus der offiziellen C++-Setup-Liste.

Vollpuffer oder Seitenpuffer? ​

  • Ein Konstruktor mit _F_ hält das ganze Bild im RAM. Zeichne zwischen clearBuffer() und sendBuffer().
  • Ein Konstruktor mit _1_ oder _2_ nutzt einen kleineren Seitenpuffer. Setze die komplette Zeichenfunktion in die Bildschleife firstPage() / nextPage().

Der Vollpuffermodus ist einfacher und schneller, braucht aber mehr RAM. Bei einem 128×64-Bild mit einem Bit pro Pixel belegt allein der Pixelpuffer 1024 Byte. Der Seitenmodus braucht weniger RAM, zeichnet aber für jede Seite dasselbe Bild neu. Siehe den Leitfaden zu den Puffermodi von U8g2.

Schritt 2: Lopaka-Projekt anlegen ​

  1. Öffne lopaka.app und lege ein Projekt an.
  2. Wähle U8g2 als Plattform.
  3. Stelle Screen-Größe auf die logische Breite und Höhe des Displays ein. Für ein nicht gedrehtes 128×64-Display nimmst du 128 × 64.
  4. Behalte den schwarzen Standardhintergrund. U8g2 gibt ein Bit pro Pixel aus, Lopaka-Designs unterscheiden also nur zwischen Vordergrund und Hintergrund statt RGB-Farben.

Die Größe der Lopaka-Zeichenfläche legt die Designfläche und das Koordinatensystem fest; sie wählt keinen U8g2-Konstruktor und konfiguriert nicht das physische Display.

Schritt 3: Screen gestalten ​

Platziere im Editor Text, Bilder und Zeichenprimitive. Die Position (0, 0) ist die linke obere Ecke der Zeichenfläche. Benenne Ebenen vor dem Export um: Aus den Namen werden Kommentare, Bildbezeichner, Animations-Header und optionale Variablennamen.

U8g2-Projekte in Lopaka erzeugen Folgendes:

Lopaka-EbeneArduino-U8g2-Ausgabe
LiniedrawLine()
RechteckdrawFrame() / drawBox()
Abgerundetes RechteckdrawRFrame() / drawRBox()
EllipsedrawEllipse() / drawFilledEllipse()
DreieckdrawTriangle(); im U8g2-Inspektor von Lopaka immer gefüllt
PolygonEine Hilfsfunktion aus geschlossenen drawLine()-Aufrufen; nur Umriss
TextsetFont() plus drawStr() oder drawUTF8()
Malebene, Icon oder importiertes BildEin monochromes XBM-Array plus drawXBM() oder drawXBMP()
AnimationFrame-Daten bzw. Header plus Hilfsfunktionen zur Frame-Auswahl und zum Zeichnen

Vordergrund, Hintergrund und Invertierung ​

Das U8g2-Projekt ist monochrom, deshalb zeigt der Inspektor keine RGB-Farbauswahl. Normale Ebenen setzen Pixel; Ebenen mit Invertiert (XOR) nutzen die U8g2-Zeichenfarbe 2 (XOR). Lopaka erzeugt außerdem transparente Schrift- und Bitmap-Modi, damit leere Pixel in Text und Bildern darunterliegende Ebenen nicht löschen.

U8g2 weist darauf hin, dass nicht jede Primitive XOR unterstützt, auch die Ellipsen-Funktionen nicht. Prüfe invertierte Formen auf dem echten Display; siehe setDrawColor.

Position und Text-Grundlinie ​

Formkoordinaten nutzen die üblichen U8g2-Ursprünge. Text richtet sich nach der Grundlinie der Schriftart, nicht nach der Oberkante der sichtbaren Buchstaben. Ein Schriftartwechsel kann daher die sichtbare vertikale Ausrichtung verändern, auch wenn die Textebene an derselben Position bleibt.

Text lässt sich um 0°, 90°, 180° oder 270° drehen. Lopaka erzeugt bei Bedarf setFontDirection(). Details zu den Koordinaten findest du in der U8g2-API-Referenz.

Schritt 4: Generierten Code konfigurieren ​

Öffne die Code-Einstellungen und wähle Arduino (Cpp) für einen Arduino-Sketch. U8g2 bietet außerdem die Syntax ESP-IDF (C) für Projekte, die bereits die C-Schnittstelle von U8g2 nutzen; das ist weder eine vollständige ESP-IDF-Anwendung noch eine Hardware-Portierung.

EinstellungWas sie bei U8g2 ändert
Wrapper-FunktionPackt den aktiven Screen in void draw{ScreenName}(void)
Als PROGMEM deklarierenNutzt U8X8_PROGMEM und drawXBMP() für Arduino-Bitmap-Deklarationen
Schriftarten einbindenBindet heruntergeladene Header eigener Schriftarten ein; integrierte U8g2-Schriftarten brauchen keinen Header
Bilder deklarierenErzeugt die Bitmap-Arrays für Mal- und Bildebenen
Bilddateien einbindenErzeugt #include "image_<Name>_bits.h" statt der Inline-Bitmap-Arrays
Animations-HilfsfunktionenBindet heruntergeladene Animations-Header ein und erzeugt Hilfsfunktionen für Timing und Zeichnen
Variablen deklarierenErzeugt Deklarationen für Ebeneneigenschaften, die als Variablen markiert sind
Kommentare, EbenentitelFügt der statischen Ausgabe Kommentare mit den Ebenennamen hinzu
Display leeren/füllenBeginnt den Zeichenblock mit u8g2.clearBuffer() (Arduino) oder u8g2_ClearBuffer() (ESP-IDF); siehe Hinweis unten

Lass unter Arduino alle Optionen außer Display leeren/füllen aktiviert.

Display leeren/füllen unter Arduino

In der Arduino-Vorlage ist Display leeren/füllen standardmäßig aus. Schaltest du es ein, beginnt draw{ScreenName}() mit u8g2.clearBuffer() und löscht damit alles, was dein Sketch vor dem Aufruf in den Puffer gezeichnet hat. Lass es aus, wenn dein loop() den Puffer schon leert oder vorher anderen Inhalt zeichnet. Bei aktivierten Animations-Hilfsfunktionen entfällt der Aufruf, weil die firstPage()/nextPage()-Schleife der Animation jede Seite ohnehin leert. Die ESP-IDF-Vorlage hat die Option standardmäßig eingeschaltet.

Schritt 5: Schriftarten und Bilder exportieren ​

Integrierte Schriftarten ​

Lopaka kennt die Liste der in U8g2 integrierten Schriftarten und passt den generierten Code an die gewählte Schriftart an. Ist eine Schriftart in U8g2 integriert, schreibt Lopaka direkt ihr Bibliothekssymbol in den Code und erzeugt keinen separaten Schriftart-Header zum Herunterladen. Zum Beispiel:

cpp
u8g2.setFont(u8g2_font_6x10_tr);

Steht eine Schriftart nicht auf der Liste der integrierten, behandelt Lopaka sie als eigene Schriftart, erzeugt genau ein passendes Header-Include und listet diesen Header unter Code-Einstellungen → Schriftarten zum Herunterladen auf.

Die Größen integrierter Schriftarten sind fest; wähle eine andere Schriftart, um Text größer oder kleiner zu machen. In der offiziellen U8g2-Schriftartenliste siehst du, welche Zeichen eine Schriftart enthält.

Eigene Schriftarten ​

U8g2-Projekte akzeptieren BDF-Schriftarten und können TTF, OTF oder WOFF über den Schriftart-Assistenten von Lopaka in fester Größe importieren. In Code-Einstellungen → Schriftarten:

  1. Lade jede aufgeführte eigene .h-Datei herunter.
  2. Lege die Header neben deinen Sketch oder den generierten Quellcode.
  3. Lass Schriftarten einbinden aktiviert, damit die generierten #include "Font_Name.h"-Zeilen erhalten bleiben.

Nur verwendete Glyphen rendern erzeugt einen kleineren Header, der nur die Zeichen enthält, die passende Textebenen gerade verwenden. Ist ein Textwert eine Laufzeitvariable, exportiert Lopaka die komplette eigene Schriftart, weil es künftige Zeichen nicht vorhersagen kann.

Bilder und Animationen ​

Statische Bilder werden in 1-Bit-XBM-Daten umgewandelt und können direkt im kopierten Quellcode deklariert werden. Mit aktiviertem Als PROGMEM deklarieren nutzt Lopaka U8X8_PROGMEM und drawXBMP(), passend zu den PROGMEM-Bitmap-Hinweisen von U8g2.

Code-Einstellungen → Bilder listet jedes Bild als image_<Name>_bits.h auf, mit genau den XBM-Bytes, die der Zeichenaufruf erhält. Aktiviere Bilddateien einbinden, um statt des Arrays #include "image_<Name>_bits.h" zu erzeugen und die Pixel im heruntergeladenen Header zu behalten.

Auch Animationen sind monochrom. Lade jede unter Animationen aufgeführte .h-Datei herunter, lege sie zum Sketch und behalte das generierte Include und den Hilfscode. Die Arduino-Hilfsfunktion wählt die Frames mit millis(). Du bist weiterhin dafür verantwortlich, die Update-Hilfsfunktion aufzurufen und den kompletten Screen in der richtigen Pufferschleife neu zu zeichnen.

Achtung

Die Animationsausgabe kann Startcode für setup() und loop() enthalten. Übernimm deren Includes, das Frame-Update und die Zeichen-Hilfsfunktionen in deinen Sketch und nutze dann das Aktualisierungsmuster für Vollpuffer oder Seitenpuffer aus dieser Anleitung. Behalte kein zweites setup() oder loop().

Schritt 6: Code kopieren und einbinden ​

Lege einen Screen namens Main an, füge eine Textebene und einen Rahmen hinzu und klicke im Code-Bereich von Lopaka auf Kopieren. Eine typische generierte Zeichenfunktion sieht so aus:

cpp
void drawMain(void) {
    u8g2.setFontMode(1);
    u8g2.setBitmapMode(1);

    u8g2.setFont(u8g2_font_6x10_tr);
    u8g2.drawStr(8, 18, "Hello!");
    u8g2.drawFrame(0, 0, 128, 64);
}

Dein Code enthält den Namen deines Screens und deine eigenen Ebenen, Schriftarten und Koordinaten.

Minimaler Sketch mit Vollpuffer ​

Nutze dieses Muster nur mit einem _F_-Konstruktor:

cpp
#include <Arduino.h>
#include <Wire.h>
#include <U8g2lib.h>

// Hardware-specific: replace with the constructor for your display.
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(
    U8G2_R0,
    U8X8_PIN_NONE
);

// Paste Lopaka asset declarations, custom-font includes, helpers,
// and the generated drawMain() function here.
void drawMain(void) {
    u8g2.setFontMode(1);
    u8g2.setBitmapMode(1);
    u8g2.setFont(u8g2_font_6x10_tr);
    u8g2.drawStr(8, 18, "Hello!");
    u8g2.drawFrame(0, 0, 128, 64);
}

void setup(void) {
    u8g2.begin();
}

void loop(void) {
    u8g2.clearBuffer();
    drawMain();
    u8g2.sendBuffer();
}

Alternative mit Seitenpuffer ​

Nutze dieses Bildschleifen-Muster mit einem _1_- oder _2_-Konstruktor:

cpp
void loop(void) {
    u8g2.firstPage();
    do {
        drawMain();
    } while (u8g2.nextPage());
}

Ändere im Seitenmodus keinen UI-Zustand innerhalb von drawMain(). U8g2 ruft die Funktion für ein einziges Bild mehrmals auf, und jeder Durchlauf muss dasselbe Bild zeichnen. Aktualisiere Sensorwerte, Navigationszustand und Auswahl des Animations-Frames vor firstPage().

Schritt 7: Laufzeitdaten und weitere Screens hinzufügen ​

Um einen Wert dynamisch zu machen, wähle seine Eigenschaft im Inspektor aus, aktiviere den Variablenschalter und lass Variablen deklarieren aktiviert. Lopaka ersetzt dann das Literal durch eine benannte Deklaration auf Basis des Ebenennamens. Deine Anwendung kann diesen Wert vor dem nächsten Neuzeichnen aktualisieren.

Jeder Lopaka-Screen wird separat exportiert, und sein Titel wird zum Namen der Zeichenfunktion. Kopiere die Funktion jedes Screens ins Projekt, führe gemeinsame Includes und Assets zusammen, damit sie nur einmal deklariert sind, und entscheide dann, welche Funktion aufgerufen wird:

cpp
enum Screen { MAIN, DETAILS };
Screen currentScreen = MAIN;

void drawCurrentScreen(void) {
    if (currentScreen == MAIN) {
        drawMain();
    } else {
        drawDetails();
    }
}

Lopaka erzeugt keine Navigation zwischen Screens, keine Tastenbehandlung, keine Menüs, kein Auslesen von Sensoren und keinen Anwendungszustand.

Was Lopaka übernimmt und was du übernimmst ​

Lopaka übernimmtDu übernimmst
Pixel-Layout und Reihenfolge der EbenenVerdrahtung, Spannung und Pinbelegung des Displays
U8g2-Zeichenaufrufe für unterstützte EbenenDen genauen Konstruktor für Controller, Schnittstelle und Puffer
Verweise auf integrierte SchriftartenInstallation von U8g2 und der Board-Toolchain
Umwandlung eigener Schriftarten und Header zum DownloadDie eigenen Header beim Quellcode behalten
1-Bit-Bitmap-DeklarationenRAM-/Flash-Budget und Wahl des Puffers
Optionale Variablen und Animations-Hilfsfunktionenbegin(), Aktualisierungsschleife, Timing und Anwendungszustand
Eine benannte Zeichenfunktion pro exportiertem ScreenEingaben, Navigation, Sensoren und den Zeitpunkt des Neuzeichnens

Kompilieren, hochladen und iterieren ​

  1. Kompiliere vor dem Hochladen. Behebe zuerst jeden fehlenden Header und jedes fehlende Symbol.
  2. Lade hoch und vergleiche das physische Display mit der Lopaka-Zeichenfläche.
  3. Passe Konstruktor, Drehung, Größe der Zeichenfläche oder Ebenenpositionen nach Bedarf an.
  4. Wenn sich das Design ändert, ersetze den kompletten generierten Abschnitt, statt einzelne generierte Aufrufe an mehreren Stellen zu bearbeiten.

Halte Hardware- und Anwendungscode außerhalb des generierten Abschnitts, damit ein neuer Export ihn nicht überschreibt:

cpp
// BEGIN LOPAKA GENERATED CODE
// Replace this entire block after exporting again.
// END LOPAKA GENERATED CODE

Fehlerbehebung ​

Das Display bleibt leer ​

  • Lade zuerst ein offizielles U8g2-Beispiel mit demselben Konstruktor hoch. Bleibt auch das leer, prüfe Stromversorgung, Masse, Verdrahtung, Controller, Reset-Pin und Schnittstelle.
  • Stelle sicher, dass u8g2.begin() genau einmal ausgeführt wird.
  • Stelle sicher, dass bei _F_ zwischen clearBuffer() / sendBuffer() gezeichnet wird bzw. bei _1_ und _2_ innerhalb der kompletten firstPage() / nextPage()-Schleife.
  • Scanne bei I2C den Bus und vergleiche das Ergebnis mit der Dokumentation des Moduls. Wenn du setI2CAddress() aufrufst, erwartet U8g2 die mit zwei multiplizierte Adresse, und der Aufruf muss vor begin() stehen; siehe die offizielle Referenz.

Das Bild ist verschoben, abgeschnitten, gespiegelt oder gedreht ​

Prüfe, ob die Lopaka-Zeichenfläche der logischen Displaygröße des Konstruktors entspricht. Wähle die genaue Controller- bzw. Display-Variante: Bei manchen Modulen ist der Controller-RAM breiter als das sichtbare Panel. Nutze U8G2_R0 bis U8G2_R3 im Konstruktor für die Drehung des Displays und halte die Abmessungen in Lopaka passend zu dieser Ausrichtung.

Farben oder überlappende Formen wirken invertiert ​

U8g2 gibt ein Bit pro Pixel aus, keine Graustufen und kein RGB. Deaktiviere Invertiert (XOR) an der Ebene, wenn XOR nicht beabsichtigt war. Nicht jede U8g2-Primitive unterstützt XOR, prüfe invertierte Ellipsen deshalb auf der Hardware.

Eine Schriftart oder ein Symbol ist nicht definiert ​

  • Namen integrierter Schriftarten müssen in der installierten U8g2-Version existieren und die verwendeten Glyphen enthalten.
  • Lade bei einer eigenen Schriftart ihre .h herunter, lege sie neben den Quellcode und lass Schriftarten einbinden aktiviert.
  • Wenn Zeichen leer bleiben, deaktiviere Nur verwendete Glyphen rendern und exportiere die eigene Schriftart erneut, besonders wenn sich Text zur Laufzeit ändert.

Dem Sketch geht der Speicher aus ​

Probiere einen _1_- oder _2_-Konstruktor mit Seitenpuffer, kleinere Bilder, weniger Animations-Frames oder eigene Schriftarten, die nur die benötigten Glyphen enthalten. Integrierte Schriftarten und Assets belegen Flash; der vollständige Display-Puffer belegt RAM.

Bilder wirken grob oder vertauscht ​

U8g2-Bilder haben ein Bit pro Pixel, deshalb kommt es auf Größe, Zuschnitt, Kontrast, Schwellenwert und Dithering an. Öffne den Bild-Assistenten von Lopaka erneut und prüfe die Vorschau in der endgültigen Pixelgröße. Halte Als PROGMEM deklarieren passend zur generierten Deklaration und zum drawXBMP()-Aufruf.

Der Seitenmodus flackert oder zeigt nur einen Teil des Screens ​

Rufe die komplette Zeichenfunktion innerhalb der do / while-Bildschleife auf. Zeichne keine Ebenen vor firstPage(), ändere keine Werte zwischen den Seiten und rufe nicht nur firstPage() ohne nextPage() auf.

FAQ ​

Konfiguriert Lopaka mein SSD1306- oder SH1106-Display? ​

Nein. Lopaka erzeugt Zeichencode. Den passenden Konstruktor, Bus, die Pins, Adresse, Drehung, den Puffermodus und die Initialisierung wählst du selbst.

Kann ich stattdessen U8x8 verwenden? ​

Nicht mit der U8g2-Ausgabe von Lopaka. U8x8 ist eine eigene, rein zeichenbasierte API und unterstützt die Grafikprimitive nicht, die Lopaka erzeugt.

Kann Lopaka farbigen U8g2-Code erzeugen? ​

Nein. Die U8g2-Plattform in Lopaka ist monochrom. Wähle für ein RGB-Display eine Farbplattform wie TFT_eSPI oder ArduinoGFX.

Ist der ESP-IDF-(C)-Export ein vollständiges Firmware-Projekt? ​

Nein. Er erzeugt Zeichencode für die C-Schnittstelle und Assets. Dein ESP-IDF-Projekt muss die U8g2-Struktur, die GPIO- und Bus-Callbacks, die Task-Schleife, die Initialisierung und die Plattformanbindung selbst konfigurieren.

Wo erfahre ich mehr? ​