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.
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.
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
#!/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.
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
#!/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
#!/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
#!/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
#!/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.
- Proxmox: „Failed to connect to Server“ mit Safari auf MacOS - 28. Januar 2023
- Loxone: Benachrichtigung per Telegram - 15. Januar 2022
- Telegram: Nachrichten per Bot von der Heimautomation aufs Handy - 2. Januar 2022
Pingback: Display am Raspberry Pi | wer bastelt mit?
Pingback: Rpi3B SSD1306 OLED I2C Interface Problem [SOLVED] – Wanted Solution