Arduino Nesso N1: So einfach zeigst du eigene Bilder auf dem Display an
Du möchtest eigene Bilder auf dem Display des Arduino Nesso N1 anzeigen lassen? Perfekt â genau darum geht es in diesem Beitrag. Wir starten ganz bewusst mit der einfachsten und schnellsten Methode, bei der ein Bild direkt aus dem Flash-Speicher (PROGMEM) geladen und auf dem Display dargestellt wird. Diese Lösung kommt ohne SD-Karte, ohne Dateisystem und ohne zusĂ€tzliche Hardware aus â ideal fĂŒr kleine Projekte, MenĂŒs oder Startbildschirme.
https://youtu.be/OjLf1hFUJuc
Im spÀteren, separaten Beitrag zeige ich dir dann, wie du Bilder direkt vom internen Dateisystem des Nesso N1 laden kannst, inklusive flexibler Bildverwaltung und Slideshow-Optionen. Doch beginnen wir zunÀchst mit der Basis, die jeder sofort umsetzen kann.
Hinweis zur BildqualitÀt der Fotos
Die folgenden Fotos zeigen die ausgegebenen Bilder direkt auf dem Display des Arduino Nesso N1. Bitte beachte: Die QualitĂ€t der Aufnahmen wirkt fotografiert etwas unscharf oder mit sichtbaren Pixelstrukturen. In der RealitĂ€t sieht das Display deutlich besser aus â die Farben sind krĂ€ftiger, die SchĂ€rfe höher und die Darstellung insgesamt klarer.
Das liegt schlicht daran, dass Kameraobjektive und Displays selten perfekt harmonieren und sich MoirĂ©-Effekte oder Reflexionen einschleichen. FĂŒr die tatsĂ€chliche Darstellung solltest du dich daher auf das Live-Bild des GerĂ€ts verlassen â die Fotos dienen lediglich zur Veranschaulichung.
Was wird fĂŒr dieses Projekt benötigt?
Damit du eigene Bilder auf dem Display des Arduino Nesso N1 anzeigen kannst, brauchst du nur wenige Dinge. Das Projekt kommt komplett ohne zusĂ€tzliche Sensoren oder externe Hardware aus und eignet sich daher ideal fĂŒr Einsteiger.
FĂŒr dieses Beispiel verwende ich:
- Arduino Nesso N1*
Das HerzstĂŒck des Projekts â ein kompakter Mikrocontroller mit ESP32-C6 und integriertem 240Ă135-Pixel-Display.
- USB-C Datenkabel*
Zum Programmieren und zur Stromversorgung. Wichtig: Ein reines Ladekabel funktioniert nicht!
- Drei Bilder
FĂŒr die Demo verwende ich JPG, PNG und BMP. Du kannst aber beliebige Bilder nutzen, solange sie vorher zugeschnitten und in ein C-Array konvertiert wurden.
- Arduino IDE
Zum Schreiben und Hochladen des Programms. Empfohlen ist die aktuelle Version der IDE.
- M5Unified Bibliothek von M5Stack
Sie ĂŒbernimmt die Initialisierung des Displays, der Tasten und der ĂŒbrigen Peripherie.
Installation: Sketch â Bibliothek einbinden â Bibliotheken verwalten â âM5Unifiedâ suchen
Hinweis von mir: Die mit einem Sternchen (*) markierten Links sind Affiliate-Links. Wenn du ĂŒber diese Links einkaufst, erhalte ich eine kleine Provision, die dazu beitrĂ€gt, diesen Blog zu unterstĂŒtzen. Der Preis fĂŒr dich bleibt dabei unverĂ€ndert. Vielen Dank fĂŒr deine UnterstĂŒtzung!
Dieser minimale Aufbau reicht vollkommen aus, um Bilder im PROGMEM abzulegen, anzuzeigen und spÀter sogar per Tastendruck durchzublÀttern.
Wichtiger Hinweis zum USB-C-Datenkabel
In meinem Test hat sich gezeigt, dass nicht jedes beliebige USB-C-Kabel zuverlĂ€ssig mit dem Arduino Nesso N1 funktioniert. Besonders dĂŒnne oder Ă€ltere Kabel liefern oft nicht genug Strom oder verlieren die Datenverbindung wĂ€hrend des Flashens.
Ich musste ein hochwertiges, krĂ€ftig abgeschirmtes USB-C-Datenkabel verwenden und den Nesso N1 zusĂ€tzlich ĂŒber einen aktiven USB-Hub anschlieĂen, damit genĂŒgend Strom anliegt und die Programmierung stabil funktioniert.
Wenn der Upload bei dir hÀngen bleibt, das Board nicht erkannt wird, lohnt es sich daher zuerst, ein besseres Kabel oder einen aktiven Hub zu testen. Oft ist das schon die komplette Lösung.
Bilder fĂŒr das Arduino Nesso N1 Display vorbereiten
FĂŒr dieses Beispiel verwende ich ein Foto meines kleinen Hundes. Damit das Bild spĂ€ter sauber und pixelgenau auf das Display des Arduino Nesso N1 passt, muss es zunĂ€chst auf die richtige GröĂe gebracht werden.
1. Bild auf DisplaygröĂe zuschneiden
Das Display des Nesso N1 besitzt eine Auflösung von 240 à 135 Pixeln (Breite à Höhe im Querformat).
Daher schneide ich mein Foto zuerst in genau dieses Format zurecht:
- Breite: 240 Pixel
- Höhe: 135 Pixel
- Format: JPG
Das Zuschneiden kann mit jedem gÀngigen Bildeditor erfolgen, in meinem Fall verwende ich Paint.NET, dieses Tool ist kostenfrei und es gibt viele Plugins und Features um Bilder zu bearbeiten.
2. Bild in Array umwandeln
Damit das Bild direkt aus dem Flash-Speicher geladen werden kann, wird es in ein Byte-Array umgewandelt:
const uint8_t jpg = { ... };
DafĂŒr nutze ich das Online-Tool: https://notisrac.github.io/FileToCArray/
Es konvertiert jede Bilddatei in ein kompatibles C-Array (getestet mit JPG, PNG & BMP).
Wichtige Einstellungen im Tool:
- Treat as binary: anhaken
- Data type: unint8_t
Alle anderen Werte sind per Default gesetzt und passen.
Einstellungen fĂŒr den File to C style array converter
Nach dem Generieren erhĂ€ltst du ein fertiges StĂŒck Code, mit den Daten des Bildes in einem Array die so beginnt:
const unsigned char Mailo1_jpg = {
0xFF, 0xD8, 0xFF, 0xE0, ...
};
Diese Datei kannst du anschlieĂend direkt in dein Arduino-Projekt einbinden und auf dem Display anzeigen.
Abspeichern der generierten Daten als C-Header-Dateii oder kopieren in die Zwischenablage
Arduino Nesso N1 Bild anzeigen â jetzt gehtâs an die Programmierung
Nachdem wir unser Bild vorbereitet und mit dem Online-Tool in eine bild.h umgewandelt haben, geht es nun an die eigentliche Programmierung.
Der schwierigste Teil ist bereits erledigt: Das Bild liegt als fertiges PROGMEM-Array vor â jetzt mĂŒssen wir es nur noch im Sketch einbinden.
Damit du direkt loslegen kannst, stelle ich dir ein vollstĂ€ndiges Arduino-Beispielprojekt zum Download bereit. Lade das Projekt in die Arduino IDE, ersetze die beiliegende bild.h einfach durch deine eigene Datei â und schon kann das Bild auf dem Display des Arduino Nesso N1 angezeigt werden.
Programm zum Anzeigen eines Bildes auf dem Arduino Nesso N1 - einfach mit PROGMEMHerunterladen
- Beispielsketch herunterladen
- bild.h gegen dein eigenes Bild austauschen
- Sketch kompilieren
- Auf den Nesso N1 hochladen
- Bild erscheint direkt beim Start auf dem Display
Im nĂ€chsten Schritt schauen wir uns den Beispielcode genauer an und ich erklĂ€re dir Zeile fĂŒr Zeile, wie das Bild auf das Display gelangt.
/*******************************************************
* Arduino Nesso N1 â Bildanzeige aus PROGMEM
* ---------------------------------------------------
* Dieses Beispiel zeigt, wie ein JPG-Bild direkt aus
* dem Flash-Speicher (PROGMEM) geladen und auf dem
* Display des Arduino Nesso N1 dargestellt wird.
*
* Das Bild befindet sich in der Datei "bild.h" und
* wurde zuvor ĂŒber ein C-Array-Konvertierungstool
* (z. B. FileToCArray) erzeugt.
*
* Autor: Stefan Draeger
* Blogbeitrag:
* https://draeger-it.blog/arduino-nesso-n1-so-einfach-zeigst-du-eigene-bilder-auf-dem-display-an/
*
* Hardware:
* - Arduino Nesso N1 (ESP32-C6)
* - Integriertes 240Ă135 SPI-Display (ST7789)
*
* Benötigte Libraries:
* - M5GFX (Displaytreiber)
*
* Dieses Beispiel zeigt nur ein statisches Standbild.
* Animationen oder das Laden aus dem Dateisystem
* werden in einem separaten Beitrag behandelt.
*******************************************************/
#include
#include
#include "bild.h" // enthÀlt: const uint8_t jpg PROGMEM
M5GFX display; // Display-Objekt des Nesso N1
void setup() {
display.begin(); // Display initialisieren
display.setRotation(1);
// Dreht das Display ins Querformat
// 0 = Hochformat, 1 = Querformat, 2/3 = invertiert
display.fillScreen(TFT_BLACK);
// Hintergrund löschen, damit kein Artefakt sichtbar ist
// JPG direkt aus PROGMEM anzeigen
// Parameter:
// 1) jpg -> Byte-Array aus bild.h
// 2) sizeof(jpg) -> BildgröĂe in Bytes
// 3) X-Position -> 0
// 4) Y-Position -> 0
display.drawJpg(jpg, sizeof(jpg), 0, 0);
}
void loop() {
// Keine Aktion notwendig â das Bild bleibt stehen
}
Das Array in eine eigene Datei auszulagern hat mehrere Vorteile.
Zum einen bleibt dein eigentlicher Arduino-Sketch deutlich ĂŒbersichtlicher, weil die langen Byte-Arrays nicht mehr direkt im Code stehen. Gerade bei Bildern können diese schnell mehrere tausend Zeilen einnehmen und wĂŒrden den Programmcode unlesbar machen.
Zum anderen bietet dir dieser Ansatz maximale FlexibilitÀt:
Wenn du spĂ€ter mehrere Bilder nacheinander anzeigen möchtest â etwa fĂŒr eine Slideshow oder fĂŒr ein MenĂŒ â, musst du nicht jedes Mal den Sketch anpassen. Du legst einfach weitere Dateien wie bild2.h, bild3.h usw. an und bindest sie bei Bedarf ein. Der Code selbst bleibt schlank, klar strukturiert und leicht erweiterbar.
Wie der ESP32-C6 Bilder speichert: Flash vs. RAM einfach erklÀrt
Nachdem wir nun erfolgreich ein erstes Bild auf dem Display anzeigen können, lohnt sich ein kurzer Blick darauf, wo die Bilddaten eigentlich gespeichert werden â und warum das entscheidend fĂŒr die StabilitĂ€t deines Programms ist.
Der Arduino Nesso N1 verfĂŒgt ĂŒber 520 KB SRAM, von denen jedoch nur etwa 320 KB als âdynamischer Speicherâ fĂŒr Variablen zur VerfĂŒgung stehen. Der Rest wird vom System selbst benötigt (WiFi-Stack, Buffer, RTOS usw.).
Umso wichtiger ist es, groĂe Datenmengen â wie Bilddateien â nicht im RAM, sondern im Flash-Speicher abzulegen.
Auf dem ESP32-C6 funktioniert das ganz einfach:
- const uint8_t bild = {...};
â Array wird automatisch im Flash gespeichert (ideal fĂŒr Bilder)
- uint8_t bild = {...};
â Array landet im RAM und verbraucht dort sehr viel Speicher
Das SchlĂŒsselwort PROGMEM wird zwar unterstĂŒtzt, ist auf diesem Mikrocontroller aber nicht entscheidend.
Der eigentliche Unterschied entsteht durch const.
Ein kurzer Vergleich zeigt das deutlich:
Bild im Flash (mit const)
- Globale Variablen: 18.200 Bytes
- RAM bleibt fast komplett frei
Der Sketch verwendet 591870 Bytes (45%) des Programmspeicherplatzes. Das Maximum sind 1310720 Bytes.
Globale Variablen verwenden 18200 Bytes (5%) des dynamischen Speichers, 309480 Bytes fĂŒr lokale Variablen verbleiben. Das Maximum sind 327680 Bytes.
Bild im RAM (ohne const)
- Globale Variablen: 165.744 Bytes
- RAM fast zur HĂ€lfte belegt
Der Sketch verwendet 592642 Bytes (45%) des Programmspeicherplatzes. Das Maximum sind 1310720 Bytes.
Globale Variablen verwenden 165744 Bytes (50%) des dynamischen Speichers, 161936 Bytes fĂŒr lokale Variablen verbleiben. Das Maximum sind 327680 Bytes.
Der Unterschied ist enorm. Gerade bei mehreren Bildern wĂ€re der RAM sehr schnell erschöpft â und das Programm wĂŒrde instabil laufen oder gar nicht mehr starten.
- Bilder immer als const-Arrays definieren.
- Sie landen dann automatisch im Flash und belasten den RAM nicht.
Dieser Punkt ist wichtig, bevor wir im nÀchsten Beispiel mehrere Bilder einbinden und per Tastendruck durchblÀttern. Genau dort zeigt sich der Vorteil besonders deutlich.
Arduino Nesso N1 Bilder per Tastendruck wechseln (JPG/PNG/BMP)
Nachdem wir ein einzelnes Bild erfolgreich anzeigen konnten, wollen wir nun einen Schritt weitergehen und die Bilder aktiv steuern. DafĂŒr habe ich ein kleines Beispielprogramm geschrieben, das gleich drei verschiedene Bildformate unterstĂŒtzt:
- JPG
- PNG
- BMP (Bitmap)
Alle Bilder liegen wie zuvor in separaten Header-Dateien (bild1.h, bild2.h, bild3.h).
Mit den beiden Hardware-Tasten am Arduino Nesso N1 können wir dann ganz einfach vor- und zurĂŒckblĂ€ttern:
- KEY1 / BtnA (grĂŒne Taste) â nĂ€chstes Bild
- KEY2 / BtnB (obere Taste) â vorheriges Bild
Damit verhÀlt sich das Display wie eine kleine, interaktive Bildergalerie.
Der Vorteil: Du kannst jedes beliebige Bildformat testen und sofort sehen, wie es auf dem Display dargestellt wird.
Das Grundprinzip ist schnell erklÀrt:
- Beim Start wird das erste Bild geladen.
- In der loop()-Funktion prĂŒfen wir, ob eine der beiden Tasten gedrĂŒckt wurde.
- Je nach Tasteneingabe erhöhen oder verringern wir einen ZÀhler (counter).
- AnschlieĂend wird das passende Bild ĂŒber drawJpg(), drawPng() oder drawBmp() neu geladen.
Arduino Nesso N1 - Bildwechsel mit Tasten
Auf diese Weise bleibt das Programm sehr kompakt, aber extrem flexibel. Du kannst beliebig viele weitere Bilder ergĂ€nzen â jeweils in einer eigenen Header-Datei â und die Navigation bleibt identisch.
Programm: Anzeigen von verschiedenen Bilder auf dem Arduino Nesso N1, wechsel mit den TastenHerunterladen
Im folgenden Codeblock findest du das vollstÀndige Beispiel (die Dateien mit den Bildern oben in der ZIP-Datei zum Download) :
/**
* Titel: Arduino Nesso N1 â Bilder per Tastendruck durchblĂ€ttern
*
* Beschreibung:
* Dieses Beispiel zeigt, wie du auf dem Arduino Nesso N1 (M5Stack Nesso, ESP32-C6)
* mehrere Bilder auf dem Display anzeigen und mit den Hardware-Tasten KEY1 (BtnA)
* und KEY2 (BtnB) vor- und zurĂŒckblĂ€ttern kannst.
*
* Verwendet werden drei Bildformate:
* - JPG (bild1.h, Array: jpg)
* - PNG (bild2.h, Array: png)
* - Bitmap/BMP (bild3.h, Array: bmp)
*
* Autor: Stefan Draeger
* Blogbeitrag: https://draeger-it.blog/arduino-nesso-n1-so-einfach-zeigst-du-eigene-bilder-auf-dem-display-an/
*/
#include
#include
// Bilddaten auslagern, damit der Sketch ĂŒbersichtlich bleibt
#include "bild1.h" // Bild als JPG â Array: jpg
#include "bild2.h" // Bild als PNG â Array: png
#include "bild3.h" // Bild als Bitmap/BMP â Array: bmp
// Anzahl der verfĂŒgbaren Bilder
const int NUM_BILDER = 3;
// ZĂ€hler, welches Bild aktuell angezeigt wird (1-basiert)
int counter = 1;
void setup() {
// Konfiguration fĂŒr das M5-Framework holen
auto cfg = M5.config();
cfg.clear_display = true; // Display beim Start automatisch löschen
// Initialisiert Display, Taster, ggf. Touch, I2C-Expander usw.
M5.begin(cfg);
// Display in Landscape-Ausrichtung (quer) setzen
M5.Display.setRotation(1);
// Startbild anzeigen (JPG aus bild1.h)
M5.Display.drawJpg(jpg, sizeof(jpg), 0, 0);
}
void loop() {
// ZustÀnde von Tasten, Touch etc. aktualisieren
M5.update();
bool btnPress = false; // Merker, ob eine der Tasten gedrĂŒckt wurde
// KEY1 (Button A) gedrĂŒckt â zur nĂ€chsten Bildposition wechseln
if (M5.BtnA.wasPressed()) {
btnPress = true;
if (counter 1) {
btnPress = true;
counter--;
}
}
// Nur neu zeichnen, wenn tatsĂ€chlich eine Taste gedrĂŒckt wurde
if (btnPress) {
// Bildschirm leeren (schwarz fĂŒllen)
M5.Display.fillScreen(TFT_BLACK);
// Sicherheitshalber wieder Landscape setzen
M5.Display.setRotation(1);
// Bild je nach ZÀhlerstand auswÀhlen und anzeigen
switch (counter) {
case 1:
// JPG aus bild1.h
M5.Display.drawJpg(jpg, sizeof(jpg), 0, 0);
break;
case 2:
// PNG aus bild2.h
M5.Display.drawPng(png, sizeof(png), 0, 0);
break;
case 3:
// Bitmap/BMP aus bild3.h
M5.Display.drawBmp(bmp, sizeof(bmp), 0, 0);
break;
}
}
// Kleine Entlastung fĂŒr die CPU (optional)
delay(10);
}
Bonus: Bild mit zufÀlligem Block-Effekt einblenden
Nachdem wir nun wissen, wie sich ein Bild ganz normal auf dem Display des Arduino Nesso N1 darstellen lÀsst, wollen wir das Ganze etwas aufpeppen.
Statt das Bild direkt komplett zu zeichnen, kann man einen kleinen visuellen Effekt einbauen, der das Bild in zufĂ€lligen Segmenten erscheinen lĂ€sst â Ă€hnlich wie ein âPuzzleâ, das sich nach und nach zusammensetzt.
Arduino Nesso N1 - Reveal Effekt
Wie funktioniert der Effekt?
- Das Display wird in ein Raster aus kleinen Kacheln eingeteilt
â in unserem Beispiel 8 Spalten Ă 5 Zeilen, also insgesamt 40 Blöcke.
- Diese Kacheln werden anschlieĂend in zufĂ€lliger Reihenfolge freigegeben.
Dazu nutzen wir den bekannten Fisher-Yates-Shuffle, der alle Blöcke gleich wahrscheinlich mischt.
- FĂŒr jeden Block setzen wir eine sogenannte Clip-Region:
Das bedeutet, dass das Bild nur innerhalb dieses kleinen Rechtecks sichtbar ist.
- AnschlieĂend wird immer wieder das komplette Bild gezeichnet â
aber durch die Clip-Region erscheint jedes Mal nur der aktuelle Block.
So entsteht ein dynamischer âRevealâ-Effekt, bei dem das Bild nach und nach sichtbar wird â jedes Mal anders, weil die Reihenfolge zufĂ€llig bestimmt wird.
Der vollstÀndige Beispielcode sieht so aus:
/************************************************************
* Titel: Arduino Nesso N1 â Bild mit zufĂ€lligem Block-Effekt einblenden
* ----------------------------------------------------------
* Beschreibung:
* Dieses Beispiel zeigt, wie ein Bild auf dem Arduino Nesso N1
* (ESP32-C6) nicht einfach komplett angezeigt wird, sondern
* in zufÀlligen kleinen Blocksegmenten erscheint.
*
* DafĂŒr wird das Display in ein Raster aus Kacheln (Tiles)
* unterteilt. Jede dieser Kacheln wird per Clip-Region einzeln
* freigegeben und das Bild abschnittsweise gezeichnet.