Raspberry Pi: OLED-Display 128×64 mit Python ansteuern (I2C)

Im Prinzip kommt ein Raspberry Pi ja ganz ohne Ein-/Ausgabe-Geräte aus – je nachdem, was man damit macht. Manchmal ist es aber schon recht praktisch, sich ein paar Informationen auf einem Display ausgeben lassen. In diesem Beitrag wollen wir ein kleines 0,96'' OLED-Display mit 128x64 Pixeln über die I2C-Schnittstelle ansteuern.

Raspberry Pi mit angeschlossenem 0,96″-OLED-Display

Inhalt

Raspberry Pi vorbereiten

Voraussetzung für alles folgende ist, dass Euer Raspberry Pi betriebsbereit ist. Wie man das Image auf eine SD-Karte bekommt und den RPi einrichtet, hatte ich hier schonmal beschrieben.

Von Haus aus ist die I2C-Schnittstelle am Raspberry Pi deaktiviert. Um diese nun einzuschalten verbinden wir uns per SSH und starten die Konfigurationsoberfläche vom Raspberry Pi:

$ sudo raspi-config

Dort gehen wir zum Punkt 5 (Interfacing Options) -> P5 (I2C) -> ENTER und bestätigen die Abfrage, ob wir I2C aktivieren wollen, mit <Ja>. Anschließend verlassen wir raspi-config.

Jetzt installieren wir noch ein paar Pakete, die wir für unser Script brauchen und starten den RPi neu:

$ sudo apt-get install python-smbus i2c-tools git python-pil
$ sudo reboot

OLED-Display anschließen

Mit ein paar Steckbrücken verbinden wir den Raspberry Pi mit dem OLED-Display. Bei meinem Display ist es egal, ob man 5V oder 3,3V nutzt. Prüft das besser bei Eurem nochmal.

Raspberry Pi: OLED-Display über I2C anschließen

Raspberry Pi: OLED-Display über I2C anschließen

Adresse ermitteln

Da I2C ein Bus-System für mehrere Teilnehme ist, haben alle auch eine Busadresse. Bei diesen kleinen Displays hat sich so etwas wie ein Standard durchgesetzt. Bei fast allen lautet die Adresse 0x3C. Das lässt sich einfach überprüfen, indem wir folgenden Befehl absetzen:

$ i2cdetect -y 1

Als Ausgabe erhalten wir dann so eine Tabelle, der wir als Adresse des einzigen Busteilnehmers 3c entnehmen können:

pi@raspberrypi:~ $ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- 3c -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

Die Adresse 0x3c ist in der von uns verwendeten Python-Bibliothek schon vorausgewählt, sodass wir der Adresse keine weitere Beachtung schenken müssen.

Python-Code

Bibliothek einbinden

Für die Ansteuerung des Displays machen wir uns eine kleine Python-Bibliothek auf Github zu Nutze. Die klonen wir und haben damit alles, was wir benötigen:

$ git clone https://github.com/BLavery/lib_oled96

Wir wechseln in das Verzeichnis lib_oled96 und legen uns dort eine neue Script-Datei an:

$ cd lib_oled96
$ touch display.py
$ chmod 777 display.py

Anschließend öffnen wir die soeben erstellte Datei in einem beliebigen Editor und fangen mit der Programmierung an:

$ nano display.py

Beispiel 1: Hallo Welt

Raspberry Pi: OLED-Display-Beispiel "Hallo Welt"

Raspberry Pi: OLED-Display-Beispiel „Hallo Welt“

#!/usr/bin/env python
# coding=utf-8

# Bibliotheken importieren
from lib_oled96 import ssd1306
from smbus import SMBus

# Display einrichten
i2cbus = SMBus(1)			# 0 = Raspberry Pi 1, 1 = Raspberry Pi > 1
oled = ssd1306(i2cbus)

# Ein paar Abkürzungen, um den Code zu entschlacken
draw = oled.canvas

# Display zum Start löschen
oled.cls()
oled.display()

# Hallo Welt
draw.text((20, 16), "Hallo", fill=1)
draw.text((60, 40), "Welt!", fill=1)

# Ausgaben auf Display schreiben
oled.display()

Der Klassiker in der Programmierung schreibt einfach ein paar Worte aufs Display. Die Zeilen 1-10 im Script liefern dabei die Grundfunktionalitäten und Zeile 13 dient lediglich dazu, den Code etwas zu verschlanken. Interessant wird es ab Zeile 16, denn hier beginnt die echte Ausgabe aufs Display. Der hier verwendete Befehl oled.cls() löscht den kompletten Inhalt und oled.display() schreibt die bisherigen Ausgaben auf das OLED-Display.

Alle Display-Informationen werden solange gesammelt, bis sie mit dem Befehl oled.display() auf das Display übertragen werden.

Auf den Zeilen 20 und 21 wird dann die eigentliche Textausgabe erzeugt. Die Syntax lautet draw.text((<x>, <y>), <Inhalt>, [<Schriftart>], [<Formatierung>]). Die Angaben <x>, <y> stehen hier für die Koordinaten auf dem Display, bezogen auf die obere linke Ecke. Das Wort „Hallo“ wird also 20 Pixel nach rechts und 16 Pixel nach unten verschoben. Das Wort „Welt“ dann demzufolge um 60 Pixel nach rechts und 40 Pixel nach unten. Zeile 24 erzeugt wieder die Anzeige auf dem Display.

Den Code kopieren wir einfach in den Editor, speichern und schließen diesen (Strg+X) und führen das Script aus:

$ ./display.py

Beispiel 2: Schriften formatieren

Raspberry Pi: OLED-Display-Beispiel "Hallo Welt" mit formatierter Schrift

Raspberry Pi: OLED-Display-Beispiel „Hallo Welt“ mit formatierter Schrift

#!/usr/bin/env python
# coding=utf-8

# Bibliotheken importieren
from lib_oled96 import ssd1306
from smbus import SMBus
from PIL import ImageFont

# Display einrichten
i2cbus = SMBus(1)			# 0 = Raspberry Pi 1, 1 = Raspberry Pi > 1
oled = ssd1306(i2cbus)

# Ein paar Abkürzungen, um den Code zu entschlacken
draw = oled.canvas

# Schriftarten festlegen
FreeSans12 = ImageFont.truetype('FreeSans.ttf', 12)
FreeSans20 = ImageFont.truetype('FreeSans.ttf', 20)

# Display zum Start löschen
oled.cls()
oled.display()

# Hallo Welt
draw.text((20, 16), "Hallo", font=FreeSans12, fill=1)
draw.text((60, 40), "Welt!", font=FreeSans20, fill=1)

# Ausgaben auf Display schreiben
oled.display()

Wir gehen einen Schritt weiter und formatieren die ausgegebene Schrift. Dazu erweitern wir unser Script um Elemente der Bibliothek PIL (Zeile 7), legen die Schriftarten fest (Zeilen 17 und 18) und wenden sie als Formatierung auf den Text an (Zeilen 25 und 26).

Beispiel 3: Formen zeichnen

Raspberry Pi: OLED-Display-Beispiel mit Formen

Raspberry Pi: OLED-Display-Beispiel mit Formen

#!/usr/bin/env python
# coding=utf-8

# Bibliotheken importieren
from lib_oled96 import ssd1306
from smbus import SMBus

# Display einrichten
i2cbus = SMBus(1)			# 0 = Raspberry Pi 1, 1 = Raspberry Pi > 1
oled = ssd1306(i2cbus)

# Ein paar Abkürzungen, um den Code zu entschlacken
draw = oled.canvas

# Display zum Start löschen
oled.cls()
oled.display()

# Formen zeichnen
draw.line((4, 2, 20, oled.height-1), fill=1)					# diagonale Linie
draw.rectangle((22, 2, 30, oled.height-1), outline=1, fill=0)	# Rechteck
draw.rectangle((32, 2, 40, oled.height-1), outline=0, fill=1)	# Rechteck, ausgefüllt
draw.ellipse((42, 2, 60, oled.height-1), outline=1, fill=0)		# Ellipse
draw.line((76, 2, 76, 63), fill=1)								# vertikale Linie
draw.arc((62, 2, 90, 63), -90, 90, fill=1)						# Bogen
draw.polygon([(92, 63), (110, 63), (101, 2)], outline=1, fill=0) # Polygon (Dreieck)

# Ausgaben auf Display schreiben
oled.display()

Für das Zeichnen von Formen haben wir bereits alles an Bord, was benötigt wird. Zur Verfügung stehen verschiedene Grundformen. In nachfolgender Auflistung stehen x1 , y1 für die Startkoordinaten und x2, y2 für die Endkoordinaten:

  • Linien: draw.line((x1, y1, x2, y2), fill=1)
  • Rechteck (nur Rahmen): draw.rectangle((x1, y1, x2, y2), outline=1, fill=0)
  • Rechteck (ausgefüllt): draw.rectangle((x1, y1, x2, y2), outline=1, fill=1)
  • Ellipse: draw.ellipse((x1, y1, x2, y2), outline=1, fill=0)
  • Polygon: draw.polygon([(x1, y1), (x2, y2), (x3, y3)], outline=1, fill=0)
    Die Eckpunkte werden als Array angegeben. (x1, y1) erste Ecke, (x2, y2) zweite Ecke, (x3, y3) dritte Ecke, …
  • Bogen: draw.arc((x1, y1, x2, y2), α1, α2, fill=1)
    α1, α2 stehen für den Startwinkel und den Endwinkel, gerechnet im Uhrzeigersinn, begonnen bei 3:00 Uhr. Der Platzbedarf eines Bogens ist der selbe, wie der einer Ellipse, jedoch wird nur der angegebene Winkel gezeichnet.

Ürbrigens: mit oled.height und oled.width kann man über die gesamte Bildschirmbreite zeichnen.

Beispiel 4: Bilddateien

Raspberry Pi: OLED-Display-Beispiel Bilddatei anzeigen

Raspberry Pi: OLED-Display-Beispiel Bilddatei anzeigen

#!/usr/bin/env python
# coding=utf-8
 
# Bibliotheken importieren
from lib_oled96 import ssd1306
from smbus import SMBus
from PIL import Image
 
# Display einrichten
i2cbus = SMBus(1)            # 0 = Raspberry Pi 1, 1 = Raspberry Pi > 1
oled = ssd1306(i2cbus)
 
# Ein paar Abkürzungen, um den Code zu entschlacken
draw = oled.canvas
 
# Display zum Start löschen
oled.cls()
oled.display()
 
# Bilddatei ausgeben
draw.bitmap((32, 0), Image.open('pi_logo.png'), fill=1)
 
# Ausgaben auf Display schreiben
oled.display()

Um ein Bild anzeigen zu können, wird wieder die PIL-Bibliothek benötigt. Die Funktionsweise ist sonst wieder die vorher. Angegeben werden müssen die Koordinaten, Pfad zur Bilddatei und Formatierung.

Beispiel 5: Bild invertieren

Raspberry Pi: OLED-Display-Beispiel Bild invertieren

Raspberry Pi: OLED-Display-Beispiel Bild invertieren

#!/usr/bin/env python
# coding=utf-8
 
# Bibliotheken importieren
from lib_oled96 import ssd1306
from smbus import SMBus
from PIL import Image
 
# Display einrichten
i2cbus = SMBus(1)            # 0 = Raspberry Pi 1, 1 = Raspberry Pi > 1
oled = ssd1306(i2cbus)
 
# Ein paar Abkürzungen, um den Code zu entschlacken
draw = oled.canvas
 
# Display zum Start löschen
oled.cls()
oled.display()
 
# Bilddatei ausgeben
draw.rectangle((32, 0, 95, 63), outline=1, fill=1)
draw.bitmap((32, 0), Image.open('pi_logo.png'), fill=0)
 
# Ausgaben auf Display schreiben
oled.display()

Um ein Bild zu invertieren zeichnen wir im Hintergrund ein gefülltes Rechteck und stellen fill beim Bild auf 0.

Sonstiges

Im Prinzip haben wir nun alles, was wir benötigen, um unser Display mit Leben zu befüllen. Wer weitere Inspiration benötigt schaut sich einfach mal die Beispiele an, die mit dem Git-Repository kamen.

Ein Hinweis zu den Bildern: Mein Display ist nicht defekt und meine Kamera auch nicht. In Wirklichkeit macht das Display eine wundervolle Farbe, die durch die Bildwiederholungen einfach schwer flimmerfrei einzufangen ist.

Sebastian

27 Comments

  1. Antworten Bernhard

    Hm, bei dieser Verkabelung liegt an SCL/SDA 5V an – das ist eigentlich zu viel für den Pi, der verträgt nur 3.3V. Gut, solange die Oled-Bibliothek nur auf den I2C-Bus schreibt, sollte das kein Problem sein

    Funktioniert das Display auch, wenn VCC an Pin 1 (3.3V) hängt?

  2. Antworten Lars

    Vielen Dank für das tolle Tutorial, das hat mir sehr geholfen.
    Ist die I2C Adresse des Displays fest oder kann man die auch einstellen um mehrere Displays an einem Bus zu betreiben?

    • Antworten Sebastian

      Ich meine die wäre fest eingestellt, kann jedoch durch Umlöten eines Widerstandes verändert werden.
      Sicher bin ich mir jedoch nicht, kann auch gut sein, dass ich das gerade verwechsle. Ich kann das derzeit leider nicht prüfen, weil mein Display fest verbaut ist.

  3. Antworten Ben

    Hallo Sebastian,

    erst einmal vielen Dank für die ausführliche und auch für einen Laien verständliche Anleitung.
    Leider will mein OLED Display einfach nicht angesteuert werden.
    Es klappt alles problemlos, bis ich dein erstes Beispiel oder das erste Beispiel aus dem lib_oled96-Ordner aufrufen will.
    Dann bekomme ich immer die folgende Fehlermeldung:

    Traceback (most recent call last):
      File "/home/pi/Desktop/lib_oled96/example1-oled96-rpi.py", line 20, in 
        oled.display()
      File "/home/pi/Desktop/lib_oled96/lib_oled96.py", line 85, in display
        const.PAGEADDR,   0x00, self.pages-1)  # Page start/end address
      File "/home/pi/Desktop/lib_oled96/lib_oled96.py", line 63, in _command
        self.bus.write_i2c_block_data(self.addr, self.cmd_mode, list(cmd))
    OSError: [Errno 121] Remote I/O error
    

    Wenn ich diese Fehlermeldung in Google eingebe, bekomme ich zwar Ergebnisse, diese sind aber durchweg in Englisch und behandeln Probleme, die ich nicht auf mein Problem ummünzen kann, um eine Lösung zu finden. Hab mir jetzt den letzten Nachmittag und die halbe Nacht um die Ohren geschlagen, um das irgendwie zu lösen (inklusive komplett neues aufsetzen des Raspberry Pi Zero W). Alle pins sind exakt wie bei dir verkabelt, alle Bibliotheken installiert, wie es hier in der Anleitung steht usw.

    Hast du eine Idee, wie ich den fehler beheben kann? Ist es vielleicht irgendeine „Kleinigkeit“, die ich übersehen habe?

    Vielen Dank im Voraus!

    • Antworten Sebastian

      Hi,
      Diesen Fall hatte ich noch nicht. Was man so im Internet findet besagt eigentlich meistens, dass man die Anschlüsse überprüfen soll, vielleicht auch mal nachmessen, ob das Display auch richtig mit Spannung versorgt wird.
      Hast du geprüft, ob die Adresse deines Displays die gleiche ist, wie bei meinem? Sonst musst du die im Script anpassen.

      • Antworten Ben

        Hallo,
        erstmal danke für die Antwort.
        Ich habe eben noch mal alles überpfrüft. Verkabelt ist alles exakt gleich und auch der i2c-Bus ist ist wie in der Anleitung auf 0x3c.
        Auch die Spannungsversorgung hab ich eben nochmal durchgemessen, es liegen 5,03V an (auch VV an 5V und GND an GND ist richtig)

    • Antworten Sebastian

      Hi,
      ja das geht. Probiere es mal mit oled._command(const.SETCONTRAST, 0xFF), wobei der Wert hinter dem Komma 0…255 in hexadezimaler Schreibweise sein darf.
      Getestet habe ich das mit dieser Bibliothek jedoch noch nicht, sondern nur in der Perl-Variante, die ich in einem anderen Beitrag beschrieben habe.

  4. Antworten Linus

    Hallo Sebastian!!
    Ich bin einer der jungen Bastler.
    Ich habe mir jetzt ein oled-Display gekauft und wollte es sofort ausprobieren.
    Hab es mit meinem Raspberry Pi 3 B+ verbunden, nur das VCC-Kabel auf Pin Nummer 1 gesteckt.
    Schon beim ersten Projekt werden auf meinem Display nur blaue und schwarze Punkte angezeigt 🙁
    Was soll ich tun? Bin nochmal deinen Text durchgegangen, habe aber keinen Fehler gefunden.
    Liegt es vielleicht an der (warscheinlich) neueren Raspian-Version?
    LG
    Linus

    • Antworten Sebastian

      Hi Linus,
      Ich kann dir nicht ganz folgen. Wenn du nur Pin 1 anschließt, wie soll das dann überhaupt funktionieren?
      Ansonsten ist mir sowas bisher auch noch nicht untergekommen, sodass ich das aus der Ferne nicht beurteilen kann. Man kann jedoch nicht 100% ausschließen, dass nicht auch ein neues Display kaputt sein könnte.

      • Antworten Linus

        Danke für deine Rückmeldung Sebastian.
        Ich habe die Kontakte des OLED-Displays wie auf der Zeichnung angeschlossen, nur den VCC-Kontakt nicht an Pin 4 (5V), sondern an Pin 1 (3,3V) angeschlossen.

  5. Antworten K0NRAD

    Super Anleitung!
    Ich habe ein Problem mit einem 128×32 OLED Display.
    Nachdem ich alles verkabelt habe erscheint beim Aufruf von i2cdetect -y 1 die Tabelle komplett ausgefüllt mit Hex Werten, vertausche ich SCL und SCA dann baut sich die Tabelle langsam auf, zeigt aber keine Adresse an.
    Ich dachte zuerst an ein defektes Modul, hab aber weitere drei mit dem gleichen Ergebnis ausprobiert.
    Hast du eine Idee woran das liegen könnte?

  6. Antworten Zarhan

    Vielen Dank für den Beitrag.
    bei mir funktioniert die Anzeige sehr gut. Allerdings bleibt der Display an, wenn ich den Pi herunterfahre. Die andere Schwierigkeit ist, dass der Display startet nicht automatisch nach dem Neustart. Ich habe es mit crontab @reboot versucht. Es klappt nicht. Wenn IHR bitte ein Tipp für mich habt? Vielen Dank im Vorraus,

    • Antworten Sebastian

      Das ist normal. Das Display zeigt den letzten Inhalt solange an, bis du diesen löschst oder die Spannung wegnimmst.

  7. Antworten Rainer

    Hallo Sebastian,
    Sehr gut beschrieben.
    Ich habe aber ein Problem mit der Anzeige. Wenn ich die verschiedenen Codes ausprobiere bekomme ich nur am untersten Rand ein wenig von dem Bild zu sehen, der größte Teil der Anzeige ist eine Sammlung von zufälligen Pxeln meist in weiß.Woran kann das denn liegen?
    Ist die library irgendwie anzupassen?
    Mir kommt es so vor, alls müsste die Anzeige viel weiter nach oben geschoben werden…
    Grüße und bleib gesund
    Rainer

    • Antworten Sebastian

      Hi Rainer,
      die Bibliothek muss natürlich nicht angepasst werden, sondern funktioniert so, wie sie ist. Möglicherweise hat dein Display jedoch einen anderen Chipsatz als den SSD1306, um den es hier geht.

      • Antworten Linus

        Das Problem hatte ich auch, Ich hab mir jetzt auch ein neues Display mit passendem Controller gekauft und jetzt funktioniert es einwandfrei. Vielen Dank für das tolle Tutorial!
        Viele Grüße
        Linus

  8. Antworten Äd

    Hallo Sebastian,
    ja, wirklich ganz tolle Arbeit. Super gut erklärt.
    Ich habe mich an Deiner Installationsanleitung der Lib lib_oled96 gehalten.
    Nun habe ich eine Anfängerfrage: die Beispiele funzen wunderbar, solange ich sie im Originalverzeichnis /home/pi/lib_oled96 lasse.
    Aber meine eigenen Programme sind ja in einem anderen Verzeichnis (z.B. pi/Dokumente/MyPythons3)
    Allein wenn ich die Datei in mein Verzeichnis kopiere und sonst nichts ändere bekomme ich diese Fehlermeldungen:
    Traceback (most recent call last):
    File „/home/pi/Dokumente/MyPythons3/myDisplay.py“, line 5, in
    from lib_oled96 import ssd1306
    File „/usr/lib/python3/dist-packages/thonny/backend.py“, line 305, in _custom_import
    module = self._original_import(*args, **kw)
    ImportError: No module named ‚lib_oled96‘

    Was mache ich falsch, dass in meinem Verzeichnis die Libs nicht gefunden werden?
    Ich arbeite mit dem mit der Thonny-IDE.

    /Äd

  9. Antworten Der Gubi

    Hallo Sebastian,

    echt richtig toll deine Anleitung und deine Beispiele.
    In Meinem Fall wollt ich gerne aktuelle Stats , zu CPU, IP, MEM-Auslastung usw. darstellen welche sich jede sekunde aktualisieren.
    Nur leider bin ich CODE-seitig nicht in der Lage das abzubilden.

    Wäre es möglich das Du hierzu noch ein Beispiel posten könntest? Würde mir wahnsinnig helfen. Danke Dir.

  10. Pingback: Display am Raspberry Pi | wer bastelt mit?

  11. Pingback: Rpi3B SSD1306 OLED I2C Interface Problem [SOLVED] – Wanted Solution

  12. Antworten Jochen

    Super Anleitung. Ich brauche allerdings den SCL für eine andere Anwendung. Kann ich das Display auch mit GPIO 0 und 1 betreiben. Sind ja auch IC“. Hab ein bisschen rumprobiert und bekomme das Display mit der Adresse 20 angezeigt. Allerdings weiß ich ab hier nicht weiter. Angezeigt bekomme ich nichts.

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht.

WordPress Cookie Hinweis von Real Cookie Banner