Ziele des Projekts
- Verwendung zweier SPI-Geräte: SD-Kartenleser und TFT-Display mit 160×128 Pixeln
- auf der SD-Karte vorhandenen Dateien auf dem TFT-Display anzeigen
Info
Sowohl das TFT-Display als auch der SD-Kartenleser verwenden den SPI-Bus. Jedes Gerät benötigt aber eigene Datenleitungen. Der ESP32-Wroom verfügt über zwei SPI-Bussysteme, die gleichzeitig nutzbar sind.

VSPI (Standard: Hardware SPI-Bus rot markiert)
23 -> COPI (MOSI)
19 -> CIPO (MISO)
18 -> CLK
5 -> CS
HSPI (Software SPI-Bus gelb markiert)
13 -> COPI (MOSI)
12 -> CIPO (MISO)
14 -> CLK
15 -> CS
Beispiel: Verzeichnis lesen und auf einem TFT mit 160×128 Pixeln anzeigen
Das TFT-Display verwendet HSPI, der SD-Kartenleser wird über VSPI angesteuert.
Die Reihenfolge der Pins kann unterschiedlich sein. Achte auf die Beschriftung der Pins der beiden Bauteile.
Der Schaltplan
Der Schaltplan ist sehr komplex, daher wird er für die das TFT-Display und den SD-Kartenleser getrennt dargestellt.
SD-Kartenleser

Reihenfolge der Pins (VSPI):
schwarz -> GND
rot -> 5V
pink -> 19 CIPO (MISO)
blau -> 23 COPI (MOSI)
braun -> 18 SCK
weiß -> 5 CS
TFT-Display

Reihenfolge der Pins (HSPI):
schwarz -> GND
rot -> 5V
gelb -> 4 RST
grün -> 2 DC
weiß -> 15 HSPI-CS
blau -> 13 HSPI-COPI (HSPI-MOSI)
braun -> 14 HSPI-SCK
Benötigte Bibliotheken


Das Programm
Die Pins (HSPI) für das TFT-Display müssen definiert werden, die Pins für den SD-Kartenleser entsprechen der Standardkonfiguration VSPI und müssen nicht deklariert werden.
Für den SD-Kartenleser sind einige Parameter erforderlich:
- der Typ der SD-Karte (3)
- die Geschwindigkeit (SD_SCK_MHZ)
- der Datenpin (CSPin)
#include "SdFat.h"
#include "Adafruit_ST7735.h"
// TFT HSPI
#define TFT_CS 15
#define TFT_RST 4
#define TFT_DC 2
#define TFT_CLK 14
#define TFT_MOSI 13
/*
SD-Kartenleser VSPI Standard-Pins
CLK 18
MOSI 23
MISO 19
CS 5
*/
// Objekt tft der Bibliothek Adafruit_ST7735 erstellen
// es werden keine Standardpins verwendet -> alle HSPI-Pins müssen übergeben werden
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST);
// Objekt SD der Bibliothek SdFat erstellen
SdFat SD;
// Farben
#define SCHWARZ 0x0000
#define WEISS 0xFFFF
#define BLAU 0x001F
// 3 = FAT32
#define SD_FAT_TYPE 3
// SPI-Geschwindigkeit
#define SPI_SPEED SD_SCK_MHZ(4)
// der SD-Kartenleser verwendet die Standard-SPI-Pins VSPI)
// sie müssen nicht definiert werden
// CSPin der SD-Kartenleser
int CSPin = 5;
void setup()
{
// Bezeichner für Verzeichnis und Dateien
File Verzeichnis;
File Datei;
char Dateiname[20];
Serial.begin(9600);
// auf serielle Verbindung warten
while (!Serial);
delay(1000);
// TFT starten
tft.initR(INITR_BLACKTAB);
// Rotation anpassen
tft.setRotation(1);
// schwarzer Hintergrund
tft.fillScreen(SCHWARZ);
tft.setTextSize(1);
tft.setTextColor(WEISS);
tft.setCursor(1, 1);
/*
SD-Karte mit Angabe des CSPins und der SPI-Geschwindigkeit starten
wenn die Intialisierung fehlschlägt
- keine SD-Karte vorhanden
- falsche Pinbelegung
-> es wird eine Fehlermeldung angezeigt
*/
if (!SD.begin(CSPin, SPI_SPEED))
{
tft.println("Start der SD-Karte");
tft.print("fehlgeschlagen!");
Serial.println("Start der SD-Karte fehlgeschlagen!");
}
else
{
Serial.println("SD-Karte gestartet");
tft.print("SD-Karte gestartet!");
}
delay(5000);
tft.fillScreen(SCHWARZ);
tft.setCursor(1, 1);
tft.println("Dateien:");
tft.setCursor(1, 20);
// Wurzelverzeichnis öffnen
// wenn keine Dateien gefunden wurden -> Fehlermeldung anzeigen
if (Verzeichnis.open("/"))
{
while (Datei.openNext(&Verzeichnis, O_READ))
{
Datei.getName(Dateiname, sizeof(Dateiname));
Serial.print(Dateiname);
tft.print(Dateiname);
// wenn es sich um ein Verzeichnis handelt
if (Datei.isDir())
{
Serial.println("/");
tft.println("/");
}
// es handelt sich um eine Datei
else
{
Serial.print('\t');
Serial.print(Datei.fileSize());
Serial.println(" Bytes");
tft.print(" ");
tft.print(Datei.fileSize());
tft.println(" Bytes");
}
Datei.close();
}
}
else
{
Serial.println("Keine Dateien gefunden!");
tft.println("Keine Dateien gefunden!");
}
}
void loop()
{
// belibt leer, das Programm läuft nur einmal
}
Beispiel: Fotoschau mit externen SD-Kartenleser
Als TFT-Display kommt ein ⇒TFT mit 480×320 Pixeln zum Einsatz.
Fotos zum Download
Die Fotos dürfen maximal das Format von 480×320 Pixeln haben und müssen im Format bmp vorliegen. Du kannst beliebige Fotos skalieren und entsprechend abspeichern.
![]() | ![]() | ![]() | ![]() | ![]() |
koeln.bmp | overath_bahnhof.bmp | lindos.bmp | braunwald.bmp | dresden_frauenkirche.bmp |
![]() | ![]() | ![]() | ![]() | ![]() |
chartres.bmp | strand.bmp | berlin_olympia.bmp | uni_bonn.bmp | duenen.bmp |
![]() | ![]() | ![]() | ![]() | ![]() |
st_michelle.bmp | ijlst.bmp | monschau.bmp | gaios.bmp | koeln_deutz.bmp |
Benötigte Bibliotheken


Die verwendete Bibliothek für das Display mit 480×320 Pixeln kann nicht über die Bibliotheksverwaltung installiert werden. Sie muss herunter geladen werden:
https://github.com/prenticedavid/Adafruit_ST7796S_kbv
und mit
Sketch -> Bibliothek einbinden -> zip-Bibliothek hinzufügen
installiert werden.
Bibliotheken einbinden und Variable definieren
Der Parameter Beschreibung entscheidet darüber, ob eine Beschreibung zum Foto angezeigt wird. Die Anzeige der Beschreibung nimmt einen kleinen Teil des Fotos weg.
#include "SdFat.h"
#include "Adafruit_ST7796S_kbv.h"
#include "Adafruit_ImageReader.h"
// TFT HSPI
#define TFT_CS 15
#define TFT_RST 4
#define TFT_DC 2
#define TFT_CLK 14
#define TFT_MOSI 13
/*
SD VSPI Standard-Pins
CLK 18
MOSI 23
MISO 19
CS 5
*/
// Objekt tft der Bibliothek Adafruit_ST7796S_kbv erstellen
Adafruit_ST7796S_kbv tft = Adafruit_ST7796S_kbv(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST);
// Objekt SD der Bibliothek SdFat erstellen
SdFat SD;
// Objekt des Kartenlesers wird an das Dateisystem der SD-Karte übertragen
Adafruit_ImageReader reader(SD);
Adafruit_Image Bild;
// Farben
#define SCHWARZ 0x0000
#define WEISS 0xFFFF
#define BLAU 0x001F
// 3 = FAT32
#define SD_FAT_TYPE 3
// SPI-Geschwindigkeit
#define SPI_SPEED SD_SCK_MHZ(4)
// CSPin der SD-Karte
int CSPin = 5;
// Anzeigedauer
int Intervall = 5000;
// true -> Beschreibung anzeigen
// false -> Foto ohne Beschriftung anzeigen
bool Beschreibung = true;
Der setup-Teil
Der setup-Teil startet den SD-Kartenleser und das TFT-Display. Der erfolgreiche Start des SD-Kartenlesers wird im Seriellen Monitor und auf dem TFT-Display angezeigt.
void setup()
{
Serial.begin(9600);
// auf serielle Verbindung warten
while (!Serial);
delay(1000);
// TFT starten
tft.begin();
// Rotation anpassen
tft.setRotation(1);
// schwarzer Hintergrund
tft.fillScreen(SCHWARZ);
tft.setTextSize(3);
tft.setTextColor(WEISS);
tft.setCursor(1, 20);
/*
SD-Karte mit Angabe des CSPins und der SPI-Geschwindigkeit starten
wenn die Intialisierung fehlschlägt
- keine SD-Karte vorhanden
- falsche Pinbelegung
-> es wird eine Fehlermeldung angezeigt
*/
if (!SD.begin(CSPin, SPI_SPEED))
{
tft.println("Start der SD-Karte");
tft.print("fehlgeschlagen!");
Serial.println("Start der SD-Karte fehlgeschlagen!");
}
else
{
Serial.println("SD-Karte gestartet");
tft.print("SD-Karte gestartet!");
}
delay(5000);
}
Der loop-Teil
Jedes Foto muss mit drawBMP an das TFT-Display (tft) mit den x- und y-Koordinaten des Startpunktes übergeben werden.
Je nach Zustand des Parameter Beschreibung (true/false) wird eine Information zum Foto angezeigt.
Die Umlaute müssen mit tft.write() und ⇒hexadezimalen Code definiert werden.
void loop()
{
reader.drawBMP("koeln.bmp", tft, 0, 0);
if (Beschreibung)
{
tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120);
tft.setCursor(10, 295);
tft.print("K");
// ö = 0x94
tft.write(0x94);
tft.println("ln Blick vom Messeturm");
}
delay(Intervall);
reader.drawBMP("duenen.bmp", tft, 0, 0);
if (Beschreibung)
{
tft.setCursor(10, 295);
tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120);
tft.print("D");
// ü = 0x81
tft.write(0x81);
tft.print("nen Ibiza");
}
delay(Intervall);
reader.drawBMP("overath_bahnhof.bmp", tft, 0, 0);
if (Beschreibung)
{
tft.setCursor(10, 295);
tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120);
tft.print("Overath Bahnhof");
}
delay(Intervall);
reader.drawBMP("rathaus.bmp", tft, 0, 0);
if (Beschreibung)
{
tft.setCursor(10, 295);
tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120);
tft.print("Rathaus Bergisch Gladbach");
}
delay(Intervall);
reader.drawBMP("dresden_frauenkirche.bmp", tft, 0, 0);
if (Beschreibung)
{
tft.setCursor(10, 295);
tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120);
tft.print("Dresden Frauenkirche");
}
delay(Intervall);
reader.drawBMP("chartres.bmp", tft, 0, 0);
if (Beschreibung)
{
tft.setCursor(10, 295);
tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120);
tft.print("Chartres Dom");
}
delay(Intervall);
reader.drawBMP("bonn_uni.bmp", tft, 0, 0);
if (Beschreibung)
{
tft.setCursor(10, 295);
tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120);
tft.print("Bonn Uni");
}
delay(Intervall);
reader.drawBMP("braunwald.bmp", tft, 0, 0);
if (Beschreibung)
{
tft.setCursor(10, 295);
tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120);
tft.print("Braunwald Schweiz");
}
delay(Intervall);
reader.drawBMP("koeln_deutz.bmp", tft, 0, 0);
if (Beschreibung)
{
tft.setCursor(10, 295);
tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120);
tft.print("K");
// ö = 0x94
tft.write(0x94);
tft.println("ln Deutz");
}
delay(Intervall);
reader.drawBMP("kloentaler_see.bmp", tft, 0, 0);
if (Beschreibung)
{
tft.setCursor(10, 295);
tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120);
tft.print("Kl");
// ö = 0x94
tft.write(0x94);
tft.println("ntaler See Schweiz");
}
delay(Intervall);
reader.drawBMP("sevilla.bmp", tft, 0, 0);
if (Beschreibung)
{
tft.setCursor(10, 295);
tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120);
tft.print("Sevilla Kathedrale");
}
delay(Intervall);
reader.drawBMP("st_michelle.bmp", tft, 0, 0);
if (Beschreibung)
{
tft.setCursor(10, 295);
tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120);
tft.print("St. Michelle Frankreich");
}
delay(Intervall);
reader.drawBMP("dresden_bruecke.bmp", tft, 0, 0);
if (Beschreibung)
{
tft.setCursor(10, 295);
tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120);
tft.print("Dresden 'Blaues Wunder'");
}
delay(Intervall);
reader.drawBMP("lindos.bmp", tft, 0, 0);
if (Beschreibung)
{
tft.setCursor(10, 295);
tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120);
tft.print("Lindos Rhodos");
}
delay(Intervall);
}
Quellen
Letzte Aktualisierung: