Arduino Mikrocontroller Tutorials - Module

OLed Display mit SSD1306 Controller (Bsp. SBC-OLED01)

Bild 0.96 OLED Display

Das 0,96 inch große OLed Modul (2,44 cm Diagonale) kann 128x64 Pixel anzeigen. Das Modul ist zweifarbig (monocrome). Blau auf schwarzem Hintergrund. Die Steuerung des Moduls übernimmt der integrierte SSD1306 Controller. Der Controller benötigt eine Spannung von 3.3V. Wenn wie hier auf dem Board ein Spannungsregler integriert ist, kann das Modul auch mit 5V betrieben werden. Die Kommunikation mit dem µC erfolgt über I2C mit der Moduladresse 3C.

Ein OLed Display benötigt wenig Strom, da eine Hintergrundbeleuchtung wie bei LCD Displays nicht notwendig ist. Ein Bildpunkt leuchtet beim OLed selbst. Im Grunde besteht das Display aus 128x64=8192 kleinen LEDs.

OLed Display Arduino Uno
GND GND
VCC 3,3V oder 5V
SCL A5
SDA A4

Ansteuerung des OLed Display über Adafruit Bibliotheken

Durch einbinden der beiden Bibliotheken Adafruit_GFX.h und Adafruit_SSD1306.h kann das Display einfach angesteuert werden.

Allgemein

display.clearDisplay()
Dieser Befehl löscht den Display-Buffer. An der Darstellung auf dem Display änder dies jedoch noch nichts.

display.display()
Mit diesem Befehl wird der Display-Speicher Inhalt an das Display übertragen und angezeigt.

display.width()display.height()

display.width() / display.height()
Mit diesen Funktionen wird die Displayhöhe oder die Displaybreite zurückgegeben.

Funktionen zum Zeichnen #include "Wire.h" #include "Adafruit_GFX.h" #include "Adafruit_SSD1306.h" Adafruit_SSD1306 display(128, 64, &Wire, -1); // 128=Breite, 64=Höhe, &Wire=I2C, -1=kein extra Reset void setup() { display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //0x3C=I2C Adresse display.fillScreen(BLACK); } void loop() { // Zeichnen display.clearDisplay(); // Displaybuffer löschen display.drawPixel(90, 55, WHITE); // (x, y, color) display.drawLine(0, 0, 128, 64, WHITE); // (x1, y1, x2, y2, color) display.drawRect(10, 20, 10, 10, WHITE); // (x, y, width, height, color) display.fillRect(30, 30, 10, 10, WHITE); // (x, y, width, height, color) display.drawRoundRect(50, 40, 20, 20, 5, WHITE); // (x, y, width, height, color) display.fillRoundRect(10, 42, 20, 20, 5, WHITE); // (x, y, width, height, color) display.drawCircle(70, 10, 10, WHITE); // (x, y, radius, color) display.fillCircle(100, 10, 10, WHITE); // (x, y, radius, color) display.drawTriangle(90, 20, 95, 40, 110, 45, WHITE); // (x1, y1, x2, y2, x3, y3, color) display.fillTriangle(120, 35, 115, 20, 110, 35, WHITE); // (x1, y1, x2, y2, x3, y3, color) display.writeFastHLine(10, 10, 50, WHITE); // (x1,y1,Länge, color) display.writeFastVLine(10, 10, 50, WHITE); // (x1,y1,Länge, color) display.display(); // Displaybuffer anzeigen }
Funktionen um Text auszugeben #include "Wire.h" #include "Adafruit_GFX.h" #include "Adafruit_SSD1306.h" Adafruit_SSD1306 display(128, 64, &Wire,-1); // 128=Breite, 64=Höhe, &Wire=I2C, -1=kein extra Reset void setup() { display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //0x3C=I2C Adresse } void loop() { display.fillScreen(BLACK); // Löscht den Display Buffer // Text ausgeben display.setTextColor(WHITE); display.setTextSize(1); // 1=Standard (S) display.setRotation(0); // 0=0°(S), 1=90°, 2=180°, 3=270° display.setCursor(23,0); // x,y display.println("OLED - Display"); display.print(display.height()); display.print(" x "); display.println(display.width()); display.println(125, BIN); display.display(); delay(1000); // Text scrollen display.startscrollright(1, 1); // (von Zeile, bis Zeile) delay(2300); display.startscrollleft(2,2); delay(5500); display.stopscroll(); // Text invertieren display.invertDisplay(true); delay(1000); display.invertDisplay(false); delay(1000); }
Funktion um eine andere Schriftart auszuwählen #include "Wire.h" #include "Adafruit_GFX.h" #include "Adafruit_SSD1306.h" // Zunächst muss die gewünschte Schriftart inkl. der gewünschten Größe eingebunden werden #include "Fonts/FreeMonoOblique18pt7b.h" /* MÖGLICHE SCHRIFTARTEN IN VERFÜGBAREN GRÖSSEN FreeMono12pt7b.h FreeSansBoldOblique12pt7b.h FreeMono18pt7b.h FreeSansBoldOblique18pt7b.h FreeMono24pt7b.h FreeSansBoldOblique24pt7b.h FreeMono9pt7b.h FreeSansBoldOblique9pt7b.h FreeMonoBold12pt7b.h FreeSansOblique12pt7b.h FreeMonoBold18pt7b.h FreeSansOblique18pt7b.h FreeMonoBold24pt7b.h FreeSansOblique24pt7b.h FreeMonoBold9pt7b.h FreeSansOblique9pt7b.h FreeMonoBoldOblique12pt7b.h FreeSerif12pt7b.h FreeMonoBoldOblique18pt7b.h FreeSerif18pt7b.h FreeMonoBoldOblique24pt7b.h FreeSerif24pt7b.h FreeMonoBoldOblique9pt7b.h FreeSerif9pt7b.h FreeMonoOblique12pt7b.h FreeSerifBold12pt7b.h FreeMonoOblique18pt7b.h FreeSerifBold18pt7b.h FreeMonoOblique24pt7b.h FreeSerifBold24pt7b.h FreeMonoOblique9pt7b.h FreeSerifBold9pt7b.h FreeSans12pt7b.h FreeSerifBoldItalic12pt7b.h FreeSans18pt7b.h FreeSerifBoldItalic18pt7b.h FreeSans24pt7b.h FreeSerifBoldItalic24pt7b.h FreeSans9pt7b.h FreeSerifBoldItalic9pt7b.h FreeSansBold12pt7b.h FreeSerifItalic12pt7b.h FreeSansBold18pt7b.h FreeSerifItalic18pt7b.h FreeSansBold24pt7b.h FreeSerifItalic24pt7b.h FreeSansBold9pt7b.h FreeSerifItalic9pt7b.h */ Adafruit_SSD1306 display(128, 64, &Wire, -1); // 128=Breite, 64=Höhe, &Wire=I2C, -1=kein extra Reset void setup() { display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //0x3C=I2C Adresse } void loop() { display.clearDisplay(); // Löscht den Display Buffer display.setTextColor(WHITE); display.setCursor(0, 50); display.setFont(&FreeMonoOblique18pt7b); // mit setFont() kann eine vorher eingebundene Schriftart ausgewählt werde display.println("Hallo"); display.display(); display.setFont(); // ohne Argument wird wieder zur Standardschriftwart gewechselt delay(1000); }

Bitmap einbinden

Zunächst muss man ein geeignetes schwarzweiß (monocrome) Bild in der passenden Größe (max 128px x 64px) auswählen bzw. auf die passende Größe konvertieren (Bsp. https://iconarchive.com/ ). Anschließend sucht man im Netz nach einem Online Converter (Suchbegriff: "Image to C++ Byte Array") und erzeugt aus dem hochgeladenen Bild ein Array mit den Bildpunkten und kopiert dies in seinen Arduino Sketch.

Das Erzeugen einer animierten Grafik aus einer *.gif Datei funktioniert ähnlich. Zunächst benötigt man ein Online Tool um die einzelnen Gif-Bilder zu separieren (Suchbegriff: "split GIF intro frames") Anschließend muss man mit jedem einzelnen Bild ein Array erzeugen und im Sketch dann nacheinander anzeigen.

Programmcode zum Anzeigen eines Bitmaps #include "Wire.h" #include "Adafruit_GFX.h" #include "Adafruit_SSD1306.h" Adafruit_SSD1306 display(128, 64, &Wire, -1); // Breite, Höhe, ... void setup() { display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // 0x3C=I2C Adresse } // (Horizontal) byte array of bitmap of 48 x 48 px. Die 'drawBitmap()-Methode holt das Bild aus dem Programmspeicher. Daher muss es auch da ablegt sein (mit PROGMEM). const byte PROGMEM bild[] = { 0x00, 0x60, 0x00, 0x00, 0x6, 0x0, 0x3, 0xfc, 0x0, 0x0, 0x3f, 0xc0, 0xc, 0x3, 0x0, 0x0, 0xc0, 0x30, 0x18, 0x1, 0x80, 0x1, 0x80, 0x18, 0x30, 0x0, 0xc0, 0x3, 0x0, 0xc, 0x60, 0x0, 0x40, 0x2, 0x0, 0x6, 0x40, 0x3, 0xc0, 0x3, 0xc0, 0x2, 0x40, 0xe, 0x0, 0x0, 0x70, 0x2, 0xc0, 0x18, 0x0, 0x0, 0x18, 0x3, 0xc0, 0x60, 0x3, 0xc0, 0x6, 0x3, 0xc0,0xf0, 0x3f, 0xfc, 0xf, 0x3, 0xc1, 0x91, 0xc0, 0x7, 0x9, 0x83,0x43, 0xf, 0x0, 0x0, 0xd0, 0xc2, 0x46, 0xc, 0x0, 0x0, 0x30, 0x62, 0x64, 0x18, 0x0, 0x0, 0x18, 0x26, 0x38, 0x30, 0x0, 0x0, 0xc, 0x3c, 0x18, 0x60, 0x0, 0x0, 0x6, 0x18, 0x0, 0x40, 0x0, 0x0, 0x2, 0x0, 0x0, 0x80, 0x0, 0x0, 0x41, 0x0, 0x1, 0x80, 0x0, 0x0, 0x81, 0x0, 0x1, 0x0, 0x0, 0x1, 0x0, 0x80, 0x1, 0x0, 0x0, 0x2, 0x0, 0x80, 0x2, 0x0, 0x20, 0x4, 0x0, 0xc0, 0x2, 0x0, 0x10, 0x8, 0x0, 0x40, 0x2, 0x0, 0x8, 0x10, 0x0, 0x40, 0x2, 0x0, 0x4, 0x20, 0x0, 0x40, 0x6, 0x0, 0x2, 0x40, 0x0, 0x40, 0x6, 0x0, 0x1, 0x80, 0x0, 0x60, 0x6, 0x0, 0x0, 0x0, 0x0, 0x60, 0x6, 0x0, 0x0, 0x0, 0x0, 0x40, 0x2, 0x0, 0x0, 0x0, 0x0, 0x40, 0x2, 0x0, 0x0, 0x0, 0x0, 0x40, 0x2, 0x0, 0x0, 0x0, 0x0, 0x40, 0x2, 0x0, 0x0, 0x0, 0x0, 0xc0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x0, 0x80, 0x1, 0x80, 0x0, 0x0, 0x1, 0x0, 0x0, 0x80, 0x0, 0x0, 0x1, 0x0, 0x0, 0x40, 0x0, 0x0, 0x2, 0x0, 0x0, 0x60, 0x0, 0x0, 0x6, 0x0, 0x0, 0x70, 0x0, 0x0, 0xe, 0x0, 0x0, 0xd8, 0x0, 0x0, 0x1b, 0x0, 0x1, 0x8c, 0x0, 0x0, 0x31, 0x0, 0x1, 0x3, 0x0, 0x0, 0xc0, 0x80, 0x2, 0x1, 0xc0, 0x7, 0x0, 0xc0, 0x6, 0x0, 0x3f, 0xfc, 0x0, 0x60, 0x4, 0x0, 0x3, 0xc0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; void loop() { // Einzelnes Bild anzeigen display.clearDisplay(); display.drawBitmap(40, 0, bild, 48, 48, WHITE); // (x, y, image array, image width, image height, color). display.display(); delay(500); display.clearDisplay(); display.display(); delay(500); }

Ansteuern des OLed Displays ohne Bibliothek

Bei diesem Programmcode wird lediglich die Bibliothek für die I2C Übertragung verwendet. Die I2C Adresse des Displays ist 0x3C.Die Befehle in der Länge eines Bytes zur Einstellung des Displays werden in ein "Befehls Register" mit der Adresse B01000000 geschrieben. Die Befehle im setup() zur Grundeinstellung wurden dem Datenblatt des SSD1306 Display Drivers entnommen.

Position der Speicheradressen beim OLed Display

Die Anzeigedaten, also die einzelnen Pixel bzw. LEDs, werden in das Datenregister geschrieben und von dort im RAM des Displays gespeichert. Nach jedem Schreibvorgang wird der Pointer zur RAM Speicheradresse um eins erhöht (inkrementiert). Die ersten übertragenen 8 bit Anzeigedaten werden oben links im Display vertikal dargestellt. Das nächste Byte wird durch den automatisch hochgezählten Pointer vertikal in Spalte 2 dargestellt. Nach 128 Schreibvorgängen ist die erste Reihe mit 8 Zeilen und 128 Spalten vollständig beschrieben.

Da die Höhe des Displays 64 Pixel sind müssen 8 Reihen mit je 8 Pixel Höhe (1Byte) beschrieben werden. Am Ende der ersten Zeile muss der Adress-Pointer auf die Zeile 2 umgestellt werden. Dies funktioniert nicht automatisch sondern über einen Befehl an das Befehlsregister. Anschließend wird die zweite Zeile mit 8 Pixel Höhe von links nach rechts beschrieben. Zeilenblock 3-8 funktionieren dann genauso.

#include "Wire.h" #define I2C_ADRESSE 0x3C #define BEFEHLS_REGISTER B10000000 #define DATEN_REGISTER B01000000 void setup() { Wire.begin(); // am I2C Bus als Master teilnehmen sendBefehl(B10101111); // Set Display ON (OFF B10101110) sendBefehl(B10100110); // Set Normalmodus (Inversmodus B10100111) sendBefehl(B00100000); // Set Memory Addressing Mode sendBefehl(B00000010); // ... auf Pageweise sendBefehl(B10001101); // Charge Pump sendBefehl(B00010100); // ... Enable clearAll(); } void loop() { setCursor(0,0); sendDaten(B11111111); sendDaten(B00000000); sendDaten(B11111111); sendDaten(B10100101); sendDaten(B10100101); sendDaten(B10100101); sendDaten(B11111111); sendDaten(B00000000); sendDaten(B11111111); setCursor(0, 7); sendDaten(B11111111); sendDaten(B00000000); sendDaten(B11111111); sendDaten(B10100101); sendDaten(B10100101); sendDaten(B10100101); sendDaten(B11111111); sendDaten(B00000000); sendDaten(B11111111); while (true); }
Funktionen void sendDaten(byte datenReihe) { Wire.beginTransmission(I2C_ADRESSE); Wire.write(DATEN_REGISTER); Wire.write(datenReihe); Wire.endTransmission(); } void sendBefehl(byte befehl) { Wire.beginTransmission(I2C_ADRESSE); Wire.write(BEFEHLS_REGISTER); Wire.write(befehl); Wire.endTransmission(); } void setCursor(byte X, byte Y) { sendBefehl(0x00 + (X & 0x0F)); // Spalten Adresse (lower nibble) B0000llll sendBefehl(0x10 + (X >> 4)); // Spalten Adresse (higher nibble) B0001hhhh sendBefehl(0xB0 + Y); // Page Adresse (0-7) B10110ppp } / * Bsp. X=50 (B00110010), Y=2 (B00000010) * X & 0x0F = B00110010 & B00001111 = B00000010 … sendBefehl(B00000010) * X >> 4 = B00000011 … sendBefehl(B00010011) * … B10110010 */ void clearAll() { for (byte page = 0; page < 8; page++) { setCursor(0, page); for (byte spalte = 0; spalte < 128; spalte++) sendDaten(B00000000); } setCursor(0, 0); }