Ziele des Projekts
- Verwendung zweier SPI-Geräte: SD-Kartenleser und TFT-Display mit 160x128 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 160x128 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)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | #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 480x320 Pixeln zum Einsatz.
Fotos zum Download
Die Fotos dürfen maximal das Format von 480x320 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 480x320 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | #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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | 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:














