SSD1306

Displays gibt es ja wirklich viele. Doch dieses mal betrachten wir kein gewöhnliches Display sondern ein OLED-Display. Das winzige Display, das ich euch heute vorstellen möchte ist gerade mal 0,96′ groß und eignet sich somit sehr gut für sehr kleine Schaltungen die Informationen über eine HMI (Human Machine Interface) bereitstellen müssen / möchten. Die Platine inklusive vormontiertem OLED-Display hat die Maße von 23 x 27 mm. Angesprochen wird das Display via I2C-Bus und kann dabei auf der Rückseite über umzulötenden SMD-Widerstand von Slave-Adresse 0x78 (default) auf 0x7A geändert werden um einen eventuell vorhandenen Adressenkonflikt zu lösen. Wenn man ein klein wenig Geduld mitbringt, dass ist das Display schon für unter 5€ bei ebay zu haben. Das nachfolgende Foto zeigt das winzige Display, dass wirklich hervorragend ablesbar ist. Auf dem Foto kommt es zwar nicht so gut rüber, doch die Schrift ist weiß auf schwarzem Hintergrund (bei ebay gibt es unter anderem auch Varianten mit blauer Schrift).

Obwohl das Display so winzig ist verfügt es über eine beachtliche Auflösung von 128×64 Pixel. Dank der Ansteuerung via I2C-Schnittstelle benötigt das Display lediglich vier Anschlussleitungen. Der Betriebsspannunsgsbereich des Displays geht von 3,3V bis hoch zu zu 5V. Wer sich ein solches Display kaufen möchte findet diese am besten mit dem Suchbegriff “SSD1306” direkt bei ebay. Auf dem Foto oben seht ihr zwei Font-Größen (8 / 16 Pixel in der Höhe). Die Version mit 16 Pixeln in der Höhe ist zum Ablesen aus etwas größerer Entfernung ideal, während die kleine Minimalvariante mit 8 Pixeln in der Höhe lediglich aus unmittelbarer Nähe (etwa ab 30 cm) gut zu lesen ist.

Byteorientierung

Mit Hilfe der nachfolgenden Grafik solltet ihr die Orientierung der Bytes auf dem Display bzw. im Inneren des Speichers des Displaycontrollers etwas besser verstehen können. Somit wisst ihr genau in welcher Art und Weise Bytes in den Framebuffer geschrieben werden müssen um am Ende das gewünschte Ergebnis auf dem OLED-Display zu sehen 🙂 Die 64 Pixel in der Höhe werden hierbei auf acht Bytes aufgeteilt wovon sich jeweils das LSB oben und das MSB unten befindet. Anhand des Beispiels auf der Abbildung mit dem “A” würde das Byte ganz oben links in der Ecke also den Wert 0x7E haben. Die nächsten Bytes (in fortlaufender X-Richtung) haben dann entsprechend die Werte: 0x11, 0x11, 0x11, 0x7E, 0x00, 0x00, 0x00, 0x7F, 0x49

Bezüglich der Adressen in X und Y Richtung ist zu sagen, dass sich der Ursprung, wie in der Abbildung dargestellt, in der oberen linken Ecke befindet – Adresse (0,0). Von diesem Punkt aus werden die Koordinaten aus hochgezählt. Während sich die X-Koordinate im Bereich von 0 … 127 im gültigen Bereich befindet, reicht die Y-Koordinate lediglich von 0 … 7. Das liegt in der Page-Aufteilung des Speichers. Je acht Pixel in der Höhe sind zu einer Page zusammengefasst und über entsprechenden Byte Zugriff ansprechbar.

Nutzung der Routinen

Die Displayroutinen arbeiten mit einem lokalen Framebuffer auf dem Controller. Sämtliche Aktionen wie das Setzen eines Pixels, das Zeichnen einer Linie … werden lokal im Framebuffer durchgeführt. Mit dem Aufruf der Funktion fb_show kann der Inhalt des Framebuffers dann auf dem Display dargestellt werden. Der Famebuffer ist eindimensional aufgebaut und hat somit eine Länge von 128 x 64. Somit werden für das Display intern im Controller 8.192 Bit benötigt um den Framebuffer abzubilden.

void main (void)
{    
    initPIC();
    initI2C();
    lcd_init();

    /*Shut OFF the LCD-Backlight*/
    LATCbits.LC2 = 1;

    /*Etwas Text in den Framebuffer schreiben*/
    fb_draw_string_big(44,0,"OLED");
    fb_draw_string_big(0,2,"Typ:  SSD1306");
    fb_draw_string_big(0,4,"Size: 128x64");
    fb_draw_string(15,7,"http://pic-projekte.de/");

    /*Den Framebuffer zur Anzeige bringen*/
    fb_show();
    
    /*Endlosschleife*/
    while(1)
    {
    }
}

Darstellung von Bitmaps

Jetzt möchte ich euch noch zeigen, wie einfach es sein kann eine Grafik / ein Bitmap auf dem OLED-Display zu zeichnen. Zunächst schauen wir uns die folgenden Fotos an auf denen je ein Bitmap auf dem Display dargestellt wurde. Auf dem ersten Foto ist neben dem Logo meiner Webseite zusätzlich der Schriftzug “OLED Display” und “SSD1306” zu sehen. Das zweite Foto zeigt das Logo von WordPress zentriert über die gesamte Höhe von 64 Pixeln des Displays. Und wir schauen uns jetzt an, wie einfach es ist ein beliebiges Bild zu erstellen und im Anschluss auf dem Display darzustellen.

Ich möchte an dieser Stelle lediglich eine sehr einfache Methode zur Implementierung der Bitmap-Funktionalität vorstellen. Diese Vorgehensweise ist keinesfalls Speicheroptimiert. Aber das ist auch gar nicht gewollt. Ich möchte vielmehr in einfachen Schritten zeigen, wie man innerhalb weniger Minute eine Grafik / ein Bild auf das OLED-Display zaubern kann:

Bitmap vorbereiten

Zunächst einmal sucht ihr euch ein Bitmap aus, dass ihr auf dem Display anzeigen möchtet. Dieses sollte idealerweise die Maße 128 x 64 Pixel (Breite x Höhe) oder kleiner haben. Ich habe zum Schreiben dieser Anleitung das folgende Bild benutzt:



Wenn ihr ein Bild habt, dass kleiner als 128 x 64 Pixel ist, solltet ihr es mit Paint so erweitern (nicht einfach skalieren, da dann die Schärfe leidet), dass ihr entsprechend auf 128 x 64 Pixel kommt. Wenn das Bitmap entsprechend vorbereitet ist, müssen wir dieses irgendwie in C-Code umwandeln. Der User Rüder S. aus dem Mikrocontroller.net Forum hat hierzu ein kleines  Tool geschrieben, was genau das bewerkstelligt. Einfach downloaden und starten. Über den Button Bild laden... importiert ihr nun eure Bitmap-Datei und klickt auf Code erstellen, siehe:

Den generierten Source-Code könnt ihr dann Copy Clpbrd mit in die Zwischenablage kopieren. Da wir hier lediglich eine Quick & Dirty Variante betrachten entfernen wir noch die ersten beiden Bytes aus dem Array (siehe am Beispiel 0x80 und 0x40) sowie das PROGMEM. Diese beiden Bytes geben die Größe des Arrays an (0x80 = 128 und 0x40 = 64). Wir möchten diese Infos nicht nutzen sondern gehen stattdessen immer davon aus, dass das Bild das gesamte Display füllen wird. Wenn die beiden Bytes (sowie das PROGMEM) entfernt wurden, kann das Ergebnis in eurer Programm kopiert werden (z.B. in eine neue Header-Datei bmp.h).

Bitmap darstellen

Wir haben nun ein Bitmap in C-Code umgewandelt, im Anschluss (für uns aktuell) überflüssige Größeninfos entfernt und den Code entsprechend in unser Programm eingefügt (siehe bmp.h). Nun können wir die Funktion fb_show_bmp() nutzen um das Bitmap auf dem Display darzustellen, siehe:

fb_show_bmp(bmp_running_men);

Nun solltet ihr das Bitmap auf dem Display sehen, wie auch in den beiden Beispielfotos (siehe weiter oben) 🙂

Download

Da die Routinen für das Display wirklich nicht kompliziert sind, möchte ich auf eine detaillierte Analyse verzichten und lediglich den Download anbieten. Die Routinen sind mit dem für den XC8-Compiler von Microchip in C geschrieben. Der Abstraktionsgrad der Sprache C macht die Routinen jedoch sehr einfach portierbar und somit für viele Plattformen nutzbar. Der Download beinhaltet neben den Routinen auch einen dazugehörigen Font sowie ein Minimalbeispiel zur Anwendung der Routinen. Bitte lade dir die Routinen von meinem  GitHub-Repository herunter.

8 Responses

Leave a Comment