OLED I²C 128×64 MONOCHROME LIBRARY

English version.

Ich habe mir vor einiger Zeit einen 0,96 Zoll Display zugelegt, welcher mit dem BUS-System I²C arbeitet. Der kleine Display hat nicht mehr als 10€ gekostet, was ihn sehr attraktiv für schnelle Hacks und kleinere Projekte macht.

Display_Real_Image

Der Aufbau

Der Display hat 4 Pins, welche auch eindeutig gekennzeichnet sein sollten, und wie folgt mit dem Arduino UNO verbunden werden.

  • SDA ⇒ A4
  • SCL ⇒ A5
  • VCC ⇒ 5V
  • GND ⇒ Ground

A4 und A5 dienen am Arduino UNO hier als BUS-Schnittstelle und können daher auch nicht mehr für andere Zwecke belegt werden. Viele Displays arbeiten auch oder nur mit 3,3V als Versorgungsspannung, dies sollte man unbedingt vorher überprüfen. Je nach Arduino und verwendeten Prozessor liegen die Kommunikationspins an unterschiedlichen Stellen. Dies kann man auf der Arduino Homepage für jedes Board nachlesen.

How it works

Der Display wird, wie bereits kurz erwähnt, mit dem Arduino via I2C verbunden. Damit das Arduino dies auch „verstehen“ kann, benötigt man die Library „Wire.h“, welche mit der IDE mit installiert wird. Ein großer Pluspunkt an dieser Verbindung ist, dass die Kommunikation für mehrere Geräte funktioniert, darauf wird hier jedoch nicht weiter eingegangen. Der Vorteil ist, dass nur 2 Pins am Arduino für den Display benötigt werden. Dies spart Platz für andere Komponenten!

Um den Display nutzen zu können, muss man ihm bestimmte Daten senden. Dies erfolgt über die Wire-Library.

Wire.beginTransmission(Device_Address);
Wire.write(Register_Address);
Wire.write(Data);
Wire.endTransmission();

Die hierbei verwendeten Parameter sind die Geräteadresse, die Registeradresse und der Datenblock. Die Geräteadresse lautet bei meinem Display 0x3C, diese kann jedoch von Display zu Display verscheiden sein. Hierfür muss man nur im Datenblatt des Gerätes nachschlagen. Die Registeradresse unterteil sich hier in zwei Teile, den Command Mode 0x80 und den Data Mode 0x40. Hier wird angegeben, ob nun ein Befehl oder ein Datenblock folgt. Der dritte Term beinhaltet den Befehl oder die Daten. Die Liste an Befehlen und sendbaren Daten findet man ebenfalls im Datenblatt, oder im Internet.

Der Display ist in 128 Spalten und 8 Zeilen mit jeweils 8 Pixeln als Block unterteilt. Diese Blöcke nennt man auch Pages. Die Pixel in einem solchen Block werden durch eine 8-stellige Binärzahl gesteuert. Übergeben muss man diese jedoch als HEX-Nummer.

Um beispielsweise den Pixel in der oberen linken Ecke zu schalten, muss man folgenden Satz an Befehlen senden:

Wire.beginTransmission(0x3C);  // Display Adresse
Wire.write(0x40);              // Data Mode - es folgen Daten
Wire.write(0x01);              // 0x01 = 00000001
Wire.endTransmission();        // Beenden der Übertragung

Um zum nächsten Block zu gelangen muss man lediglich einen neuen Satz an Befehlen senden, der Display erhöht den Zähler bei jedem Empfangen von Daten selbst. Je nachdem, welcher Modus am Ende der Zeile aktiv ist, setzt der Display folgende Aktion:

  • Horizontal Addressing: Der Zähler springt zum ersten Block in der nächsten Zeile.
  • Page Addressing: Der Zähler springt zum ersten Block in der momentanen Zeile.

Display_Shematic

Anhand der Grafik oben kann man erkennen, wie die Pages aufgebaut sind. Die langen, vertikalen Balken symbolisieren jeweils eine Page. Die grün eingefärbte Page ist jene, welche in dem Beispiel oben beschrieben wurde. Hier wurde nur der erste Pixel (der oberste Pixel) angesprochen. Nach diesem Befehl wird der Zähler erhöht, und die Page rechts neben der grünen ist an der Reihe.

Der Code

Wie immer liegt der Programmcode auf GitHub.

Um die Library nutzen zu können, muss diese zuerst in das Bibliothekenverzeichnis der IDE kopiert werden. Zusätzlich benötigt man auch noch die Wire-Library, welche sich bereits im Verzeichnis für Bibliotheken befinden sollte.

Nun steht die OLED_I2C_128x64_Monochrome zur Verfügung. Um nicht immer diesen langen Namen schreiben zu müssen, wird die Klasse als Display erstellt, und das Objekt als lcd.

Das folgende Script soll zeigen, wie man die Library benutzt.

#include "OLED_I2C_128x64_Monochrome.h"
#include "OLED_I2C_128x64_Monochrome_Font.h"
#include <Wire.h>

void setup()
{
     lcd.initialize();
     lcd.printString("----------------", 0, 0);
     lcd.printString("THIS IS A STRING", 3, 0);
     lcd.printString("----------------", 6, 0);
}

void loop()
{
    // Nothing to do here.
}

Display_String_Image

Manche Displays, so auch meiner, benötigen 7.5V für das OLED Panel. Aus diesem Grund muss der interner Hochsetzer aktiviert werden, welcher die 5V der Versorgung umwandelt. Hierfür muss man die beiden folgenden Daten senden:

sendCommand(0x8d);
sendCommand(0x14);

In der Library ist dieser Fall bereits berücksichtigt. Wer einen Display nutzt, welcher diesen Command nicht benötigt, der muss lediglich die Zeile 9 im *.cpp File auskommentieren, oder löschen.

#define USE_REGULATOR

Um das Thema Horizontal Addressing nochmal geanuer zu erklären, habe ich hier eine kleine Aufgabe parat gestellt. Die Pages sollen reihenweise ausgemalt werden, wobei sie am Zeilenende die Zeile wechseln. Hierfür muss man den Display auf den Horizontal Mode umschalten.

Nachdem der Display ausgemalt wurde, also die letzte Page in der letzten Zeile angesprochen wurde, kehrt der Zähler wieder auf Page 0 und Zeile 0 zurück.

Danach wird der Display wieder schwarz ausgemalt – selbes Prinzip, es wird nur ein anderer Datenwert gesendet.

#include "OLED_I2C_128x64_Monochrome.h"
#include "OLED_I2C_128x64_Monochrome_Font.h"
#include <Wire.h>

void setup()
{
    lcd.initialize();
    lcd.setHorizontalMode();
}

void loop()
{
    for (byte Y = 0; Y < 8; Y++)
    {
        for (byte X = 0; X < 128; X++) 
        {
            Wire.beginTransmission(0x3C); // Display Adresse
            Wire.write(0x40);             // Data Mode
            Wire.write(0xff);             // 0x99 = 11111111
            Wire.endTransmission();       // Beenden der Übertragung
            delay(10);
        }
    }
    for (byte Y = 0; Y < 8; Y++)
    {
        for (byte X = 0; X < 128; X++) 
        {
            Wire.beginTransmission(0x3C); 
            Wire.write(0x40);             
            Wire.write(0x00);             // 0x00 = 00000000
            Wire.endTransmission();
            delay(10);
        }
    }
}

Display_Gif_small

Ich hoffe damit habe ich alle Fragen ausgeräumt, wer dennoch welche hat -> Comment Section!

Advertisements

22 Gedanken zu “OLED I²C 128×64 MONOCHROME LIBRARY

  1. Es ist schon mehr als verwirrend, dass die Beispiele scheinbar Strings übergeben, aber mit diesen kann man nicht arbeiten.
    Welcher Datentyp für TEXTE ist erforderlich ?

    Gefällt mir

    1. Dazu muss ich kurz fragen, was du genau mit Texten meinst?
      Vom Datentyp her ist’s ein Char-Array. Wenn du auf das Problem anspielst, dass du zB vom seriellen Monitor direkt keine Textausgabe realisieren kannst, dann liegt’s daran, dass du vorerst den String in ein Char-Array wandeln musst, das du dann weiter parsen kannst.

      Im *.cpp File ( https://github.com/deloarts/OLED_I2C_128x64_Monochrome_Library/blob/master/OLED_I2C_128x64_Monochrome.cpp#L78 ) kannst du dirs genauer ansehen.

      Gefällt mir

  2. Hallo, wie kann man denn die Schrift anpassen, dass sie größer wird. Ich nehme an ich muss in der OLED_I2C_128x64_Monochrome_Font.h die Änderungen vornehmen, weiß aber leider nicht was eich eintragen muss. Kannst du mir da einen Tipp geben?

    Gruß Bert

    Gefällt mir

    1. Du hast es schon richtig erkannt, die Schrift ist im …_Font.h hinterlegt. Dort ist eine Zeile jeweils ein ASCII-Symbol, beginnend von DEC32, endend bei DEC127 (die Tabelle findest du hier: http://www.asciitable.com/ , hier siehst du auch gleich, welche Symbole überhaupt darstellbar sind).

      Die Schriftgröße nimmt derzeit 8×8 Pixel ein, das erkennst du am Aufbau der Zeilen in der …_Font.h. Willst du also ein Zeichen darstellen, so wird der korrespondierende ASCII-Eintrag genommen und Schrittweise auf dem Display dargstellt. Die Vorgehensweise findest du im *.cpp-File in der Funktion Display::printChar().

      Der Grund warum die Schriftart genau 8 Pixel hoch ist, ist dass der Display von sich aus in Zeilen der Höhe 8 Pixel arbeitet. Ich habe mir also einiges an Aufwand erspart die Schrift zu erstellen, weil man ansonsten zum darstellen eines Zeichens mehrfach Zeilen wechseln müsste.

      Wenn du die Größe der Schrift also ändern willst, dann kannst du das wie folgt tun:

      Erstelle zuerst eine neue Font (ASCII-Reihenfolge beachten) und lade sie in die …_Font.h. Wie du einzelne Pixel am Display darstellst habe ich im Eintrag beschrieben. Dabei kannst du grundsätzlich jede Größe wählen (10×10, 12×14, etc).

      Danach musst die *.cpp bearbeiten, am besten du fängst bei Display::setCursor() and und arbeitest dich weiter nach vorne. Allerdings musst du auf das pageAdressing achten (wie sich der Display am Zeilenende verhält).

      Ich denke du hast dir einen etwas einfacheren Weg erhofft, aber leider ist das Ändern der Schriftgröße ein Haufen Arbeit, ich hoffe trotzdem ich habe dir helfen können, wenn du noch Fragen hast, dann helfe ich dir gerne weiter.

      MFG

      Gefällt mir

      1. Hey, danke für die schnelle Antwort!
        Ok, dann muss ich mich mal in Ruhe damit auseinander setzen. Ich würde mich in Arduino Dingen, in der Mittelkasse einordnen. Ich muss eigentlich lediglich eine Zweistellige Zahl, möglichst groß Darstellen.
        Im Notfall schiele ich mal in die Adafruit Library und schau mal wie die das gemacht haben. Bei denen ist halt mein Problem, dass da der Arduino gleich voll ist (Ram) und ich dann für meinen Code kaum Platz habe. Da sieht das mit deiner Library um Welten besser auch 😀

        Gruß Bert

        Gefällt mir

        1. Wenn es nur um Zahlen geht, dann kannst du diese auch als NxM größes Bitmap erstellen (suche nach Bitmap to Hex Converter). Und dann wirfst du die Zahl einfach per drawBitmap-Funktion an die richtige Stelle. Wenn es um keine schnellen Wechsel der Zahlen geht, dann sollte das sehr gut funktionieren, ohne viel RAM zu verbrauchen.

          Gefällt mir

    1. Hier kommt es darauf an, von welchem Hersteller dein Display ist.
      Wenn du eines von Heltec hast, dann muss man schon recht konkret suchen, da diese Displays weder eine Seriennummer, noch eine Typennummer oder Ähnliches haben, dafür gibt es unterschiedliche Ausführungen (4 Pins, 6 Pins, mit/ohne Spannungsregler, 3.3V, 5V …).

      Für den Chip habe ich dir das Datenblatt unter folgenden Link bereitgestellt: http://www.deloarts.bplaced.net/sites/de/libraries/oled_display/datasheet_SSD1780.pdf

      Und für das OLED-Panel hier (das ist nicht ganz so interessant):
      http://www.deloarts.bplaced.net/sites/de/libraries/oled_display/datasheet_panel.pdf

      Ich hoffe du hast den selben Chip wie ich, dann kannst du das Datenblatt nutzen – aber wenn meine lib funktioniert, dann sollte dem so sein.

      Gefällt mir

  3. Vielen Dank!

    Du hast mit dieser kurzen Beschreibung und der Bib mehr für mich getan als diese ganzen „Tutorials“ die am Ende eh nicht funktionieren!

    +1 Internets for you

    Gefällt mir

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s