Zum Inhalt springen

Lopaka Basics 05: Vom Browser zum Board ​

Ein SSD1306-OLED-Modul, verdrahtet mit GND, VCC, SCL und SDA, das das Morgen-Dashboard mit FRI 24 OCT, 07:45 und Sunny 23C zeigt

Du hast einen Screen gezeichnet, du hast den Code hochgeladen, und das Display bleibt schwarz. Das Display ist selten kaputt. Meist ist es eines von fünf Dingen, und sobald du das richtige behebst, leuchtet der Screen auf.

In dieser Episode bringst du das Morgen-Dashboard aus Episode 2 vom Browser auf ein Board: Installiere die Bibliothek in der Arduino IDE, baue den Sketch um den Code von Lopaka und prüfe, wie viel Speicher er nutzt. Dann gehst du die fünf Gründe durch, warum ein neues Display schwarz bleibt, und die Behebung für jeden.

Was du bauen wirst: einen Arduino-Sketch, der die Screens Morning und Night aus Episode 2 auf einem 128×64-SSD1306-OLED zeigt, plus eine Checkliste für einen schwarzen Screen. Was du brauchst: einen Browser, die kostenlose Arduino IDE und das Morning-Dashboard-Projekt aus Episode 2. Ein Arduino UNO und ein OLED-Modul sind optional; wir führen den Sketch im Simulator aus Episode 1 aus.

Wie das Board mit dem Screen spricht ​

Vier Drähte: Strom, Takt und Daten ​

Ein kleines OLED wie unseres braucht vier Drähte. Zwei sind Strom: VCC und GND. Die anderen zwei sind ein Bus namens I2C:

  • SCL ist der Takt. Das Board sendet einen stetigen Tick darauf.
  • SDA trägt die Daten, ein Bit pro Tick.

Der I2C-Bus zwischen einem Arduino UNO und dem OLED: Der SCL-Takt tickt über den SDA-Datenbits, die die Adresse 0x3C buchstabieren; ein Sensor bei 0x76 und eine Uhr bei 0x68 teilen sich dieselben zwei Drähte, und nur das Display antwortet auf 0x3C

Jede Nachricht beginnt mit einer Adresse ​

Andere Teile können sich dieselben zwei Drähte teilen: Ein Temperatursensor, eine Echtzeituhr und das Display können alle an SCL und SDA hängen. Also beginnt jede Nachricht mit einer Adresse, und nur das Teil mit dieser Adresse antwortet.

Die meisten dieser Displays antworten auf 0x3C. Manche antworten auf 0x3D. Auf vielen Modulen setzt ein winziger Widerstand auf der Rückseite die Adresse, neben einer Beschriftung wie „IIC ADDRESS SELECT 0x78 / 0x7A“. Diese zwei Zahlen sind dieselben Adressen verdoppelt: 0x3C × 2 = 0x78 und 0x3D × 2 = 0x7A. Behalte das für Grund 2 unten im Hinterkopf.

Die Rückseite des OLED-Moduls: Die Beschriftung IIC ADDRESS SELECT mit einem Widerstand auf der 0x78-Seite und der Notiz 0x78 = 0x3C × 2

Größere Farbscreens nutzen SPI ​

Farbscreens wie das TFT aus Episode 4 nutzen stattdessen meist SPI: mehr Drähte (MOSI, SCK, CS, DC und RST), viel schneller, und ein Auswahl-Draht, CS, statt einer Adresse.

Ein Arduino UNO neben dem Farb-TFT aus Episode 4, mit den SPI-Drähten MOSI, SCK, CS, DC und RST; mehr Drähte, viel schneller

Schritt 1: Kopiere den Code aus Lopaka ​

Öffne das Morning Dashboard aus Episode 2: ein 128×64-OLED mit der Bibliothek U8g2 und zwei Screens, Morning und Night.

Lopaka schreibt die Zeichenfunktionen, eine pro Screen: drawMorning() und drawNight(). Den Sketch um sie herum, mit Display-Einrichtung und loop(), schreibst du einmal in der Arduino IDE.

Klicke im Tab Morning des Code-Panels auf Kopieren, wechsle dann zum Tab Night und kopiere den auch. Kopieren nimmt den Code des offenen Tabs. Der generierte Code ist derselbe wie in Episode 2.

Das Morning Dashboard in Lopaka mit den Screens Morning und Night auf der Zeichenfläche; das Code-Panel zeigt den Morning-Tab mit der drawMorning-Funktion, dem Kopieren-Button und eingeschaltetem Als PROGMEM deklarieren

Schritt 2: Installiere U8g2 ​

Öffne in der Arduino IDE den Bibliotheksmanager (das Bücher-Icon links), suche nach U8g2 und klicke bei der U8g2-Bibliothek von oliver auf INSTALLIEREN. Die Episode nutzte Version 2.36.19.

Schritt 3: Wähle das Board ​

Klicke oben auf Board auswählen, wähle Anderes Board und Port auswählen, tippe uno und wähle Arduino UNO. Ohne angeschlossenes Board kann die IDE den Sketch trotzdem kompilieren; du brauchst den Port nur zum Hochladen.

Schritt 4: Baue den Sketch ​

Ein neuer Sketch hat bereits setup() und loop(). Füge den Code von Lopaka oben ein und füge dann drei Zeilen hinzu: Binde die Bibliothek ein, erstelle das Display und starte es in setup(). Lösche in loop() den Puffer, zeichne und sende den Puffer an den Screen:

cpp
#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);

// Paste the Lopaka code here: drawMorning() and drawNight()

void setup() {
  // put your setup code here, to run once:
  u8g2.begin();
}

void loop() {
  // put your main code here, to run repeatedly:
  u8g2.clearBuffer();
  if (millis() / 3000 % 2) drawNight(); else drawMorning();
  u8g2.sendBuffer();
}

setup() läuft einmal, wenn das Board startet. loop() läuft wieder und wieder. Die if-Zeile zeigt jeden Screen drei Sekunden lang, wie in Episode 2, und die Reihenfolge Löschen, Zeichnen, Senden ist der Frame-Puffer aus Episode 1.

Die IDE mit dem fertigen Sketch: das Ende von drawNight, dann setup mit u8g2.begin() und loop mit clearBuffer, der millis-Zeile und sendBuffer

Die Konstruktorzeile beschreibt dein Display ​

Die lange Zeile unter dem #include ist der Konstruktor. Er beschreibt dein Display, und jeder Teil seines Namens bedeutet etwas:

  • SSD1306: der Controller-Chip auf dem Modul.
  • 128X64: die Größe in Pixeln.
  • NONAME: ein generisches Modul, keine bestimmte Marke.
  • F: der Puffer-Modus. F ist ein voller Frame-Puffer, 1.024 Bytes RAM. 1 zeichnet den Screen in Pages und braucht nur 128 Bytes.
  • HW_I2C: die Verdrahtung, Hardware-I2C an den SDA- und SCL-Pins des Boards.

U8G2_R0 bedeutet keine Rotation, und U8X8_PIN_NONE sagt, dass kein Reset-Pin verdrahtet ist. Die U8g2-Bibliothek hat einen Konstruktor für jede Kombination aus Chip, Größe, Puffer und Verdrahtung. Wähle den falschen, und der Screen bleibt schwarz.

Der Konstruktor U8G2_SSD1306_128X64_NONAME_F_HW_I2C, in Karten aufgeteilt: Controller-Chip, Größe, F für einen vollen Puffer von 1 KB und Hardware-I2C; eine Zeile ist dein Display, und eine falsche Zeile bedeutet einen schwarzen Screen

Schritt 5: Verifiziere und führe aus ​

Verifizieren ​

Klicke oben links auf Verifizieren, das Häkchen. Die IDE kompiliert den Sketch und meldet:

Sketch uses 15394 bytes (47%) of program storage space. Maximum is 32256 bytes.
Global variables use 1600 bytes (78%) of dynamic memory, leaving 448 bytes for local variables. Maximum is 2048 bytes.

Der Sketch braucht weniger als die Hälfte des Flash und mehr als drei Viertel des RAM. Der Frame-Puffer allein sind 1.024 der 2.048 Bytes des UNO; alles andere braucht 576. Behalte diese 78 % im Auge: Sie kommen in Grund 5 zurück.

Die Verifizieren-Ausgabe: 15394 Bytes (47 %) Flash und 1600 Bytes (78 %) dynamischer Speicher, und ein Balken der 2.048 Bytes RAM des UNO, bei dem der 1.024-Byte-Frame-Puffer die Hälfte einnimmt

Hochladen oder im Simulator ausführen ​

Wähle mit angeschlossenem Board seinen Port im selben Dialog Board auswählen und klicke auf Hochladen, den Pfeil neben Verifizieren.

Kein Board? Öffne das Simulatorprojekt aus Episode 1: ein Arduino UNO mit einem SSD1306-Display, verdrahtet GND mit GND, VCC mit 5V, SDA mit A4 und SCL mit A5, und die U8g2-Bibliothek. Füge den Sketch ein und drücke Play. Das Display zeigt den Morning-Screen und wechselt jede drei Sekunden zu Night.

Der Simulator, der den Sketch ausführt: ein Arduino UNO, verdrahtet mit dem OLED mit SDA zu A4 und SCL zu A5, und das Display zeigt 07:45 und Sunny 23C

Fünf Gründe, warum ein Screen schwarz bleibt ​

Die Prüfungen gehen von außen nach innen: Drähte, Adresse, Chip, Code und Speicher. Bei jedem brechen wir die funktionierende Einrichtung im Simulator, sehen den Screen schwarz werden und beheben es.

1. Die Drähte ​

An einem UNO geht SDA zu A4 und SCL zu A5. Vertausche sie, und das Board spricht mit niemandem: Der Screen bleibt schwarz.

Prüfe auch Strom und Masse. Andere Boards nutzen andere Pins: Auf den meisten ESP32-Boards ist SDA Pin 21 und SCL Pin 22.

Grund 1, Drähte: Die SDA- und SCL-Drähte bei A4 und A5 vertauscht, als vertauscht beschriftet, mit niemandem sprechend, und das OLED bleibt schwarz

2. Die Adresse ​

Die meisten Module antworten auf 0x3C, manche auf 0x3D. U8g2 spricht mit 0x3C, wenn du ihm nichts anderes sagst. Wenn das Modul auf 0x3D gesetzt ist, antwortet nichts, und der Screen bleibt schwarz.

Um herauszufinden, welches du hast, führe einen I2C-Scanner-Sketch aus. Er fragt jede Adresse auf dem Bus und druckt die, die antworten:

cpp
#include <Wire.h>

void setup() {
  Wire.begin();
  Serial.begin(9600);
  Serial.println("Scanning I2C...");
  for (byte a = 1; a < 127; a++) {
    Wire.beginTransmission(a);
    if (Wire.endTransmission() == 0) {
      Serial.print("Found a device at 0x");
      Serial.println(a, HEX);
    }
  }
  Serial.println("Done.");
}

void loop() {}

Lade ihn hoch und öffne den Seriellen Monitor mit 9600 Baud.

Grund 2, Adresse: Der I2C-Scanner-Sketch läuft, mit Found a device at 0x3D im Seriellen Monitor

Setze dann die Adresse in deinem Dashboard-Sketch, vor begin():

cpp
void setup() {
  u8g2.setI2CAddress(0x3D * 2);
  u8g2.begin();
}

U8g2 will die Adresse verdoppelt, also wird aus 0x3D 0x3D * 2, 0x7A: dieselbe Zahl, die auf der Rückseite des Moduls gedruckt ist.

Die Behebung in setup: u8g2.setI2CAddress(0x3D * 2) vor u8g2.begin(), U8g2 will sie verdoppelt: 0x7A, und das OLED zeigt das Dashboard wieder

3. Der Chip ​

Zwei Module können genau gleich aussehen und unterschiedliche Controller nutzen. Die meisten kleinen 0,96-Zoll-Screens nutzen den SSD1306. Viele 1,3-Zoll-Modelle nutzen den SH1106. Führe SSD1306-Code auf einem SH1106 aus, und du bekommst einen leeren Screen oder einen Rauschstreifen am Rand.

Die Behebung ist der Chipname im Konstruktor:

cpp
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);

Grund 3, Chip: Ein 0,96-Zoll-SSD1306-Modul mit sauberem Bild neben einem 1,3-Zoll-SH1106-Modul, das SSD1306-Code ausführt, mit einem Rauschstreifen am rechten Rand

4. Der Code ​

U8g2 zeichnet in einen Puffer im Speicher, und nur sendBuffer() bewegt das Bild auf den Screen. Vergiss diese Zeile oder vergiss u8g2.begin() in setup(), und der Screen bleibt dunkel. Der Sketch kompiliert trotzdem ohne Fehler, also prüfe diese Zeilen zuerst:

cpp
u8g2.begin();          // in setup()
u8g2.clearBuffer();    // in loop()
drawMorning();
u8g2.sendBuffer();

Grund 4, Code: Der Frame ist in den RAM-Frame-Puffer gezeichnet, aber mit durchgestrichenem begin und sendBuffer erreicht er den Screen nie, der schwarz bleibt; Fertig kompiliert, kein Fehler

5. Der Speicher ​

Erinnerst du dich an diese 78 %? Ein UNO hat 2.048 Bytes RAM, und der Frame-Puffer nimmt die Hälfte.

Lopaka hält Bilder mit PROGMEM im Flash: Der Schalter Als PROGMEM deklarieren neben dem Code ist standardmäßig an, und die Arrays bekommen U8X8_PROGMEM. Schalte ihn aus, und die Bilder wandern ins RAM. Der Mond allein sind 48 × 48 / 8 = 288 Bytes, und die vier Bilder des Dashboards brauchen 416. Jetzt nutzt der Sketch 2.016 Bytes, 98 % des RAM, mit 32 Bytes übrig für alles, was das Programm während des Laufens tut. Er kompiliert trotzdem, aber der Screen fällt auseinander: Im Simulator verschwindet der Text und die Bilder brechen.

Grund 5, Speicher: Das RAM des UNO bei 98 %, Frame-Puffer 1.024, alles andere 576 und Bilder 416, für 2.016 Bytes; die Verifizieren-Ausgabe meldet 2016 Bytes (98 %) und das OLED zeigt ein kaputtes Dashboard

Lasse PROGMEM an. Wenn dir trotzdem das RAM ausgeht, wechsle in den Page-Modus: Lege eine 1 statt des F in den Konstruktor, und der Puffer schrumpft von 1.024 Bytes auf 128.

cpp
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);

Im Page-Modus zeichnet die Bibliothek den Screen in acht Streifen, einer nach dem anderen, also ändert sich auch loop(). Statt clearBuffer() und sendBuffer() geht das Zeichnen in eine firstPage()- / nextPage()-Schleife:

cpp
void loop() {
  u8g2.firstPage();
  do {
    if (millis() / 3000 % 2) drawNight(); else drawMorning();
  } while (u8g2.nextPage());
}

Mit Page-Modus nutzt dasselbe Dashboard 704 Bytes, 34 % des RAM.

Page-Modus: Das RAM des UNO bei 34 %; die Konstruktoren U8G2_SSD1306_128X64_NONAME_F_HW_I2C für einen vollen Puffer und U8G2_SSD1306_128X64_NONAME_1_HW_I2C für Page-Modus, Puffer 1.024 zu 128 Bytes

Zusammenfassung ​

  1. Lopaka zeichnet den Screen, die IDE baut den Sketch darum: Installiere U8g2, wähle das Board, füge die Zeichenfunktionen ein und füge Include, Konstruktor, begin() und die Löschen-Zeichnen-Senden-Schleife hinzu.
  2. Eine Konstruktorzeile beschreibt dein Display: Chip, Größe, Puffer und Verdrahtung.
  3. Schwarzer Screen? Prüfe fünf Dinge: die Drähte, die Adresse, den Chip, den Code und den Speicher.

Nächste Episode: Screens & Menüs. Mehr als ein Screen, mit Menüs und einem Button. Lies Episode 6 oder schaue sie auf YouTube.

Bereit, es zu versuchen? Öffne Lopaka und bringe deinen Screen auf ein echtes Board.