ESP32 mit 2,8 Zoll TFT (Cheap Yel­low Display)

Lese­zeit: 28 Minu­ten

Die Hard­ware

Beim ESP32-2432S028R han­delt es sich um ein 2,8 Zoll gro­ßes TFT-Dis­play mit 320×240 Pixeln. Auf der Rück­sei­te ist ein ESP-Wroom 32 ver­baut, er ver­fügt über WiFi und Blue­tooth. Mit JST-Ste­ckern kön­nen Peri­phe­rie­ge­rä­te ange­schlos­sen werden.

Kon­fi­gu­ra­ti­on des Mikrocontrollers

Anschluss von Peripherie

JST-Ste­cker 1,25 mm 4 Pins blau ein­ge­färbt (P3)
Pins
GND
35
22
21

JST Ste­cker 1,25 mm 4 Pins gelb ein­ge­färbt (CN1)
Pins
GND
22
27
3,3 V

Mikro JST-Ste­cker 2 Pins Laut­spre­cher­an­schluss (grün ein­ge­färbt)
26

RGB-LED

Auf der Rück­sei­te befin­det sich eine RGB-LED.
Die ein­zel­nen LEDs sind aktiv bei LOW und aus­ge­schal­tet bei HIGH.

int RoteLED = 4;
int GrueneLED = 16;
int BlaueLED = 17;

void setup()  
{ 
  pinMode(RoteLED, OUTPUT);
  pinMode(GrueneLED, OUTPUT);
  pinMode(BlaueLED, OUTPUT);
}

void loop()   
{ 
  digitalWrite(RoteLED, LOW);
  delay(500);
  digitalWrite(RoteLED, HIGH);
  delay(500);
  digitalWrite(GrueneLED, LOW);
  delay(500);
  digitalWrite(GrueneLED, HIGH);
  delay(500);
  digitalWrite(BlaueLED, LOW);
  delay(500);
  digitalWrite(BlaueLED, HIGH);
  delay(500);
}

Laut­spre­cher

Ein Laut­spre­cher wird mit einem Mikro JST-Ste­cker mit 2 Pins ange­schlos­sen. Die Laut­stär­ke kann mit Hil­fe eine Wider­stands an einem der Dräh­te redu­ziert werden.

int LAUTSPRECHER = 26; 

void setup ()  
{ 
  // kein setup-Teil notwendig
} 

void loop () 
{ 
  // tone(Ausgabepin, Frequenz, Zeit_in_Millisekunden)    
  tone(LAUTSPRECHER, 1000, 100); 

  delay(500);

  // Lautsprecher ausschalten 
  noTone(LAUTSPRECHER);
}

SD-Kar­te

Das SD-Kar­ten­mo­dul nutzt den Stan­dard Hard­ware SPI-Bus (VSPI):

Pins VSPI
23 -> COPI (MOSI)
19 -> CIPO (MISO)
18 -> CLK
5 -> CS

Das Bei­spiel­pro­gramm liest den Inhalt der SD-Kar­te und zeigt die Datei­en im Seri­el­len Moni­tor an.

#include "SdFat.h"
SdFs SD;

// 3 = FAT32
#define SD_FAT_TYPE 3

// SPI-Geschwindigkeit
#define SPI_SPEED SD_SCK_MHZ(4)

/*
  Pinbelegung:
  CIPO -> 19
  COPI -> 23
  SCK  -> 18
  CS   ->  5
*/

// CSPin der SD-Karte
int CSPin = 5;

void setup() 
{
  Serial.begin(9600);

  // auf serielle Verbindung warten
  while (!Serial);
  delay(1000);

  /*
     SD-Karte mit Angabe des CSPins starten
     wenn die Intialisierung fehlschlägt
     - keine SD-Karte vorhanden
     - falsche Pinbelegung
     -> es wird eine Fehlermeldung angezeigt
  */
  if (!SD.begin(CSPin, SPI_SPEED)) 
  {
    Serial.println("Initialisierung fehlgeschlagen!");
  } 
  else Serial.println("Initialisierung abgeschlossen");

  // Dateien im Verzeichnis anzeigen
  Serial.println(SD.ls(LS_DATE | LS_SIZE | LS_R));
}

void loop() 
{
  // bleibt leer, das Programm läuft nur einmal
}

WiFi

Bei­spiel: Ein­fa­cher Webserver

Das Pro­gramm zeigt im Brow­ser 6 Zufalls­zah­len an.
Im Seri­el­len Moni­tor wird die mit DHCP ermit­tel­te IP des ESP32-Wroom angezeigt.

Die­se Adres­se musst du in einem Brow­ser dei­ner Wahl eingeben.

#include "WiFi.h"
#include "WebServer.h"

// SSID und Passwort des Routers
char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";

WebServer Server(80);

// Minimum und Maximum der Zufallszahlen
int Minimum = 1;
int Maximum = 49;

void setup() 
{
  Serial.begin(9600);

  // auf serielle Verbindung warten
  while (!Serial);
  delay(1000);

  // WiFi starten
  WiFi.mode(WIFI_STA);
  WiFi.begin(Router, Passwort);

  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(200);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(Router);
  Serial.print("IP über DHCP: ");

  // IP anzeigen
  Serial.println(WiFi.localIP());

  // Zufallsgenerator mit dem Signal an A0 starten
  randomSeed(analogRead(A0));

  Server.begin();
  Server.on("/", SeiteBauen);
}

void loop() 
{
  Server.handleClient();
}

void SeiteBauen() 
{
  // Seite zusammenbauen
  // Kopf der HTML-Seite: Aktualisierung alle 60 Sekunden
  // kann angepasst werden
  String Nachricht = "<head><meta http-equiv=\"refresh\" content=\"60\"></head>";
  Nachricht += "<h1>Zufallszahlen</h1>";
  Nachricht += "<hr>";

  // Zufallszahlen anzeigen
  for (int i = 0; i < 7; i++) 
  {
    int Zahl = random(Minimum, Maximum);
    Nachricht += String(Zahl) + " ";
  }

  Nachricht += "<hr>";

  // Nachricht senden -> Seite anzeigen
  Server.send(200, "text/html", Nachricht);
}

Gra­fi­sche Funktionen

Das TFT-Dis­play ver­wen­det den Soft­ware SPI-Bus HSPI:

13 -> COPI (MOSI)
12 -> CIPO (MISO)
14 -> CLK
15 -> CS

Für die Ver­wen­dung des Dis­plays kön­nen zwei ver­schie­de­ne Biblio­the­ken genutzt werden:

  • Adafruit_IL9341
    Die SPI-Pins für die Ansteue­rung des TFTs wer­den direkt im Pro­gramm angegeben.
  • TFT_eSPI
    Trei­ber und SPI-Pins wer­den in ⇒Steu­er­da­tei­en ange­ge­ben. Die Biblio­thek stellt auch inter­ne Schrif­ten zur Verfügung.

Bei­de Biblio­the­ken nut­zen die Adafruit GFX-Bibliothek.

Biblio­thek Adafruit_IL9341

#include "Adafruit_ILI9341.h"

#define TFT_BL   21
#define TFT_CS   15 
#define TFT_DC    2
#define TFT_MISO 12
#define TFT_MOSI 13
#define TFT_SCLK 14
#define TFT_RST  -1

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST, TFT_MISO);

// Farben
#define SCHWARZ     0x0000
#define WEISS       0xFFFF
#define BLAU        0x001F
#define ROT         0xF800
#define GRUEN       0x07E0
#define CYAN        0x07FF
#define MAGENTA     0xF81F
#define GELB        0xFFE0
#define BRAUN       0x9A60
#define GRAU        0x7BEF
#define GRUENGELB   0xB7E0
#define DUNKELCYAN  0x03EF
#define ORANGE      0xFDA0
#define PINK        0xFE19
#define BORDEAUX    0xA000
#define HELLBLAU    0x867D
#define VIOLETT     0x915C
#define SILBER      0xC618
#define GOLD        0xFEA0

void setup()
{
  // Zufallsgenerator starten
  randomSeed(analogRead(A0));
  Serial.begin(9600);
  delay(500);
  Serial.println("Bildschirm: " + String(tft.height()) + " x " + String(tft.width()));

  pinMode(TFT_BL, OUTPUT);
  digitalWrite(TFT_BL, HIGH);

  // TFT starten
  tft.begin();

  // Rotation anpassen
  tft.setRotation(2);

  // schwarzer Hintergrund
  tft.fillScreen(SCHWARZ);

  // interne Textdarstellung
  tft.setTextSize(1);
  tft.setCursor(1, 5);
  tft.setTextColor(BLAU);
  tft.print("Text");
  delay(500);

  tft.setTextSize(3);
  tft.setCursor(1, 40);
  tft.setTextColor(GRUEN);
  tft.print("Text");
  delay(500);

  tft.setTextSize(5);
  tft.setCursor(1, 70);
  tft.setTextColor(ROT);
  tft.print("Text");
  delay(500);

  tft.setTextSize(7);
  tft.setCursor(1, 120);
  tft.setTextColor(GELB);
  tft.print("Text");
  delay(500);

  tft.setTextSize(9);
  tft.setCursor(1, 200);
  tft.setTextColor(GRAU);
  tft.print("Text");
  delay(2000);

  // Sonderzeichen darstellen
  tft.fillScreen(SCHWARZ);
  tft.setTextColor(WEISS);
  tft.setCursor(10, 20);
  tft.setTextSize(3);

  // Großstädte
  tft.println();
  tft.print("Gro");
  tft.write(0xe);
  tft.print("st");
  tft.write(0x84);
  tft.print("dte");

  // Düsseldorf
  tft.println();
  tft.print("D");
  tft.write(0x81);
  tft.print("sseldorf");

  // Köln
  tft.println();
  tft.print("K");
  tft.write(0x94);
  tft.println("ln");
  tft.println();
  tft.println("Temperatur:");
  tft.print("20");
  tft.write(0xf7);
  tft.print("C"); 
  delay(2000);

  // zufällige Pixel
  tft.fillScreen(SCHWARZ);
  for  (int i = 0; i < 700; i++)
  {
    int PixelX = random(1, tft.width());
    int PixelY = random(1, tft.height());
    tft.drawPixel(PixelX, PixelY, tft.color565(random(255),random(255),random(255)));
    delay(5);
  }
  delay(2000);

  // Linien ziehen
  tft.fillScreen(SCHWARZ);
  for (int i = 1; i < tft.height(); i+=10)
  {
    tft.drawLine(1, i, tft.width(), i, ORANGE);
  }
  delay(2000);

  // Kreise vom Mittelpunkt zeichnen
  tft.fillScreen(SCHWARZ);
  for (int i = 1; i < tft.width() / 2; i+=10)
  {
    tft.fillCircle(tft.width() / 2, tft.height() / 2, tft.width() / 2 - i, tft.color565(random(255),random(255),random(255)));
    delay(50);
  }
  delay(2000);

  // Rechtecke zeichnen
  tft.fillScreen(SCHWARZ);
  for (int i = 1; i < tft.width(); i+=10)
  {
    tft.drawRect(tft.width() / 2 - i / 2, tft.height() / 2 - i / 2 , i, i, tft.color565(random(255),random(255),random(255)));
  }
  delay(2000);

   // ausgefüllte Rechtecke zeichnen
  tft.fillScreen(SCHWARZ);
  for (int i = 1; i < tft.width() / 2; i+=10)
  {
    tft.fillRect(i, i, i, i, tft.color565(random(255),random(255),random(255)));
    delay(50);
  }
  delay(2000);

  // Dreiecke
  tft.fillScreen(SCHWARZ);
  for (int i = 1; i <tft.width(); i+=10)
  {
    tft.fillTriangle(i, i, 100, 100, 1, tft.width(), tft.color565(random(255),random(255),random(255)));
    delay(50);
  }   
}

void loop()
{
  // nichts zu tun, das Programm
  // läuft nur einmal
}

TFT_eSPI

Biblio­thek TFT_eSPI

Im Ver­zeich­nis /Arduino/libraries müs­sen zwei Datei­en ange­passt werden:

Datei User_Setup_Select.h

// Standard-Konfiguration
#include "User_Setup.h

#if defined (ILI9341_DRIVER) || defined(ILI9341_2_DRIVER) || defined (ILI9342_DRIVER)
#include <TFT_Drivers/ILI9341_Defines.h>
#define  TFT_DRIVER 0x9341
#endif

Datei User_Setup.h

// Treiber TFT
#define ILI9341_2_DRIVER
#define TFT_WIDTH  240
#define TFT_HEIGHT 320
#define TFT_BACKLIGHT_ON HIGH

// SPI-Pins
#define TFT_MOSI 13
#define TFT_SCLK 14
#define TFT_CS   15
#define TFT_DC    2
#define TFT_RST  -1
#define TFT_BL   21

#define SPI_FREQUENCY  55000000
#define SPI_READ_FREQUENCY  20000000

// Touch-Pins
#define TOUCH_IRQ 36
#define TOUCH_MOSI 32
#define TOUCH_MISO 39
#define TOUCH_CLK 25
#define TOUCH_CS 33
#define SPI_TOUCH_FREQUENCY  2500000

// Schriftarten
// Font 2-4: Buchstaben, Zahlen und Satzzeichen, keine Umlaute
// Font 6-8: Zahlen und Satzzeichen
#define LOAD_FONT2
#define LOAD_FONT4
#define LOAD_FONT6
#define LOAD_FONT7
#define LOAD_FONT8
#define LOAD_GFXFF
#define SMOOTH_FONT

Aller­dings wer­den die­se Datei­en beim Update der Biblio­thek über­schrie­ben. Es emp­fiehlt sich daher, sie an einem ande­ren Ort zu sichern.

Das Pro­gramm

#include "TFT_eSPI.h"

TFT_eSPI tft = TFT_eSPI();

// Farben
#define SCHWARZ     0x0000
#define WEISS       0xFFFF
#define BLAU        0x001F
#define ROT         0xF800
#define GRUEN       0x07E0
#define CYAN        0x07FF
#define MAGENTA     0xF81F
#define GELB        0xFFE0
#define BRAUN       0x9A60
#define GRAU        0x7BEF
#define GRUENGELB   0xB7E0
#define DUNKELCYAN  0x03EF
#define ORANGE      0xFDA0
#define PINK        0xFE19
#define BORDEAUX    0xA000
#define HELLBLAU    0x867D
#define VIOLETT     0x915C
#define SILBER      0xC618
#define GOLD        0xFEA0

void setup() 
{
  tft.init();
}

void loop()
{
  tft.fillScreen(SCHWARZ);

  tft.setTextSize(1);
  tft.setCursor(1, 5);
  tft.setTextColor(BLAU);
  tft.print("Text");
  delay(500);

  tft.setTextSize(2);
  tft.setCursor(1, 20);
  tft.setTextColor(ORANGE);
  tft.print("Text");
  delay(500);

  tft.setTextSize(3);
  tft.setCursor(1, 40);
  tft.setTextColor(GRUEN);
  tft.print("Text");
  delay(500);

  tft.setTextSize(5);
  tft.setCursor(1, 70);
  tft.setTextColor(ROT);
  tft.print("Text");
  delay(500);

  delay(2000);


  // zufällige Pixel
  tft.fillScreen(SCHWARZ);
  for  (int i = 0; i < 700; i++)
  {
    int PixelX = random(1, tft.width());
    int PixelY = random(1, tft.height());
    tft.drawPixel(PixelX, PixelY, tft.color565(random(255),random(255),random(255)));
    delay(5);
  }
  delay(2000);

  // Linien ziehen
  tft.fillScreen(SCHWARZ);
  for (int i = 1; i < tft.height(); i+=10)
  {
    tft.drawLine(1, i, tft.width(), i, ORANGE);
  }
  delay(2000);

  // Kreise vom Mittelpunkt zeichnen
  tft.fillScreen(SCHWARZ);
  for (int i = 1; i < tft.width() / 2; i+=10)
  {
    tft.fillCircle(tft.width() / 2, tft.height() / 2, tft.width() / 2 - i, tft.color565(random(255),random(255),random(255)));
    delay(50);
  }
  delay(2000);

  // Rechtecke zeichnen
  tft.fillScreen(SCHWARZ);
  for (int i = 1; i < tft.width(); i+=10)
  {
    tft.drawRect(tft.width() / 2 - i / 2, tft.height() / 2 - i / 2 , i, i, tft.color565(random(255),random(255),random(255)));
  }
  delay(2000);

   // ausgefüllte Rechtecke zeichnen
  tft.fillScreen(SCHWARZ);
  for (int i = 1; i < tft.width() / 2; i+=10)
  {
    tft.fillRect(i, i, i, i, tft.color565(random(ROT),random(GRUEN),random(BLAU)));
    delay(50);
  }
  delay(2000);

  // Dreiecke
  tft.fillScreen(SCHWARZ);
  for (int i = 1; i <tft.width(); i+=10)
  {
    tft.fillTriangle(i, i, 100, 100, 1, tft.width(), tft.color565(random(255),random(255),random(255)));
    delay(50);
  }
}

Touch-Screen ver­wen­den

Das Bei­spiel­pro­gramm erstellt zwei far­bi­ge But­tons. Beim Klick auf einen der But­tons ändert sich die Far­be und die Koor­di­na­ten des Punk­tes wer­den angezeigt.

Adafruit_ILI9341

#include "Adafruit_ILI9341.h"
#include "XPT2046_Touchscreen.h"

// Adafruit Schrift
#include "Fonts/FreeSans9pt7b.h"

#define SCHWARZ     0x0000
#define WEISS       0xFFFF
#define BLAU        0x001F
#define ROT         0xF800
#define GRUEN       0x07E0
#define CYAN        0x07FF
#define MAGENTA     0xF81F
#define GELB        0xFFE0
#define BRAUN       0x9A60
#define GRAU        0x7BEF
#define GRUENGELB   0xB7E0
#define DUNKELCYAN  0x03EF
#define ORANGE      0xFDA0
#define PINK        0xFE19
#define BORDEAUX    0xA000
#define HELLBLAU    0x867D
#define VIOLETT     0x915C
#define SILBER      0xC618
#define GOLD        0xFEA0

// TFT-Pins (Software-SPI)
#define TFT_BL   21
#define TFT_CS   15 
#define TFT_DC    2
#define TFT_MISO 12
#define TFT_MOSI 13
#define TFT_SCLK 14
#define TFT_RST  -1

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST, TFT_MISO);

// Touchscreen SPI-Pins
#define TOUCH_MOSI 32  
#define TOUCH_MISO 39  
#define TOUCH_CLK 25   
#define TOUCH_CS 33

// IRQ-Pin
#define TOUCH_IRQ 36

// SPI-Pins als Hardware-SPI
SPIClass touchscreenSPI = SPIClass(VSPI);
XPT2046_Touchscreen touchscreen(TOUCH_CS, TOUCH_IRQ);

bool FarbwechselLinkerButton = false;
bool FarbwechselRechterButton = false;

// Touchscreen Koordinaten (z = Druck)
int x, y, z;

void setup() 
{
  Serial.begin(9600);

  // SPI-Bus für den Touchscreen starten
  touchscreenSPI.begin(TOUCH_CLK, TOUCH_MISO, TOUCH_MOSI, TOUCH_CS);
  touchscreen.begin(touchscreenSPI);

  /*
    wenn die Bildschirm-Koordinaten und die Touchscreen-Kordinaten
    nicht übereinstimmen (Touchscreen ist "falsch" herum)
    Rotation des Touchscreen setzen:
    touchscreen.setRotation(3);
  */

  // TFT starten
  tft.begin();

  // Hintergrundbeleuchtung einschalten
  pinMode(TFT_BL, OUTPUT);
  digitalWrite(TFT_BL, HIGH);
  
  // Bildschirm drehen
  tft.setRotation(1);

  tft.fillScreen(SCHWARZ);

  // linker Button  
  tft.fillRect(50, 100, 100, 50, ROT);
  tft.drawRoundRect(50, 100, 100, 50, 5, WEISS);
  
  // rechter Button
  tft.fillRect(180, 100, 100, 50, GELB);
  tft.drawRoundRect(180, 100, 100, 50, 5, WEISS);
  tft.setTextSize(2);
}

void loop() 
{
  // wenn der Touchscreen berührt wurde
  if (touchscreen.tirqTouched() && touchscreen.touched()) 
  {
    // Punkte x, y und Druck (z) ermitteln
    TS_Point Punkt = touchscreen.getPoint();

    /*
      die "Rohwerte" der Punkte x und y bewegen sich zwischen 1 und 3800 bzw. 3900
      daher müssen sie mit map auf die korrekten Bildschirmmaße
      korrigiert werden
    */
    x = map(Punkt.x, 240, 3800, 1, tft.width());
    y = map(Punkt.y, 320, 3900, 1, tft.height());
    
    z = Punkt.z;

    // linker Button Koordinaten abfragen
    if (x >= 50 && x <= 150 && y >= 100 && y <= 150) 
    {
      if (FarbwechselLinkerButton) 
      {
        tft.fillRect(50, 100, 100, 50, SCHWARZ);
        tft.fillRect(50, 100, 100, 50, GRUEN);
        tft.drawRoundRect(50, 100, 100, 50, 5, WEISS);
      }
      
      else 
      {
        tft.fillRect(50, 100, 100, 50, SCHWARZ);
        tft.fillRect(50, 100, 100, 50, BLAU);
        tft.drawRoundRect(50, 100, 100, 50, 5, WEISS);
      }
      FarbwechselLinkerButton = !FarbwechselLinkerButton;
    }

    // rechter Button Koordinaten abfragen
    if (x >= 180 && x <= 280 && y >= 100 && y <= 150) 
    {
      if (FarbwechselRechterButton) 
      {
        tft.fillRect(180, 100, 100, 50, SCHWARZ);
        tft.fillRect(180, 100, 100, 50, MAGENTA);
        tft.drawRoundRect(180, 100, 100, 50, 5, WEISS);
      }

      else 
      {
        tft.fillRect(180, 100, 100, 50, SCHWARZ);
        tft.fillRect(180, 100, 100, 50, GELB);
        tft.drawRoundRect(180, 100, 100, 50, 5, WEISS);
      }
      FarbwechselRechterButton = !FarbwechselRechterButton;
    }
    KoordinatenAnzeigen(x, y, z);

    delay(100);
  }
}

void KoordinatenAnzeigen(int x, int y, int z) 
{
  Serial.print("x-Koordinate = ");
  Serial.print(x);
  Serial.print(" | y-Koordinate = ");
  Serial.print(y);
  Serial.print(" | Druck = ");
  Serial.print(z);
  Serial.println();

  tft.fillRect(1, 1, tft.width(), 90, SCHWARZ);
  tft.setCursor(10, 30);
  tft.setFont(&FreeSans9pt7b);
  tft.println("x-Koordinate: " + String(x));
  tft.println(" y-Koordinate: " + String(y));
}

TFT_eSPI

#include "TFT_eSPI.h"
TFT_eSPI tft = TFT_eSPI();

#include "XPT2046_Touchscreen.h"

#define SCHWARZ     0x0000
#define WEISS       0xFFFF
#define BLAU        0x001F
#define ROT         0xF800
#define GRUEN       0x07E0
#define CYAN        0x07FF
#define MAGENTA     0xF81F
#define GELB        0xFFE0
#define BRAUN       0x9A60
#define GRAU        0x7BEF
#define GRUENGELB   0xB7E0
#define DUNKELCYAN  0x03EF
#define ORANGE      0xFDA0
#define PINK        0xFE19
#define BORDEAUX    0xA000
#define HELLBLAU    0x867D
#define VIOLETT     0x915C
#define SILBER      0xC618
#define GOLD        0xFEA0

// Touchscreen SPI-Pins
#define TOUCH_IRQ 36
#define TOUCH_MOSI 32  
#define TOUCH_MISO 39  
#define TOUCH_CLK 25   
#define TOUCH_CS 33

// SPI-Pins als Hardware-SPI
SPIClass touchscreenSPI = SPIClass(VSPI);
XPT2046_Touchscreen touchscreen(TOUCH_CS, TOUCH_IRQ);

bool FarbwechselLinkerButton = false;
bool FarbwechselRechterButton = false;

// Touchscreen Koordinaten (z = Druck)
int x, y, z;

void setup() 
{
  Serial.begin(9600);

  // SPI-Bus für den Touchscreen starten
  touchscreenSPI.begin(TOUCH_CLK, TOUCH_MISO, TOUCH_MOSI, TOUCH_CS);
  touchscreen.begin(touchscreenSPI);

  /*
    wenn die Bildschirm-Koordinaten und die Touchscreen-Kordinaten
    nicht übereinstimmen (Touchscreen ist "falsch" herum)
    Rotation des Touchscreen setzen:
    touchscreen.setRotation(3);
  */

  // TFT starten
  tft.begin();

  // Hintergrundbeleuchtung einschalten
  pinMode(TFT_BL, OUTPUT);
  digitalWrite(TFT_BL, HIGH);
  
  // Bildschirm drehen
  tft.setRotation(1);

  tft.fillScreen(SCHWARZ);

  // linker Button  
  tft.fillRect(50, 100, 100, 50, ROT);
  tft.drawRoundRect(50, 100, 100, 50, 5, WEISS);
  
  // rechter Button
  tft.fillRect(180, 100, 100, 50, GELB);
  tft.drawRoundRect(180, 100, 100, 50, 5, WEISS);
  tft.setTextSize(2);
}

void loop() 
{
  // wenn der Touchscreen berührt wurde
  if (touchscreen.tirqTouched() && touchscreen.touched()) 
  {
    // Punkte x, y und Druck (z) ermitteln
    TS_Point Punkt = touchscreen.getPoint();

    /*
      die "Rohwerte" der Punkte x und y bewegen sich zwischen 1 und 3800 bzw. 3900
      daher müssen sie mit map auf die korrekten Bildschirmmaße
      korrigiert werden
    */
    x = map(Punkt.x, 240, 3800, 1, tft.width());
    y = map(Punkt.y, 320, 3900, 1, tft.height());
    
    z = Punkt.z;

    // linker Button Koordinaten abfragen
    if (x >= 50 && x <= 150 && y >= 100 && y <= 150) 
    {
      if (FarbwechselLinkerButton) 
      {
        tft.fillRect(50, 100, 100, 50, GRUEN);
        tft.drawRoundRect(50, 100, 100, 50, 5, WEISS);
      }
      
      else 
      {
        tft.fillRect(50, 100, 100, 50, BLAU);
        tft.drawRoundRect(50, 100, 100, 50, 5, WEISS);
      }
      FarbwechselLinkerButton = !FarbwechselLinkerButton;
    }

    // rechter Button Koordinaten abfragen
    if (x >= 180 && x <= 280 && y >= 100 && y <= 150) 
    {
      if (FarbwechselRechterButton) 
      {
        tft.fillRect(180, 100, 100, 50, PINK);
        tft.drawRoundRect(180, 100, 100, 50, 5, WEISS);
      }

      else 
      {
        tft.fillRect(180, 100, 100, 50, GELB);
        tft.drawRoundRect(180, 100, 100, 50, 5, WEISS);
      }
      FarbwechselRechterButton = !FarbwechselRechterButton;
    }
    KoordinatenAnzeigen(x, y, z);

    delay(100);
  }
}

void KoordinatenAnzeigen(int x, int y, int z) 
{
  Serial.print("x-Koordinate = ");
  Serial.print(x);
  Serial.print(" | y-Koordinate = ");
  Serial.print(y);
  Serial.print(" | Druck = ");
  Serial.print(z);
  Serial.println();

  tft.fillRect(1, 1, tft.width(), 90, SCHWARZ);
  tft.setCursor(10, 10);

  // interne Schrift Größe 2
  tft.setTextFont(2);
  tft.println("x-Koordinate: " + String(x));
  tft.setCursor(10, 40);
  tft.print("y-Koordinate: " + String(y));
}

Bei­spiel­pro­gram­me mit der Biblio­thek Adafruit_ILI9341

Tem­pe­ra­tur und Luft­feuch­tig­keit mit DHT-Sen­sor anzeigen

JST-Ste­cker 1,25 mm mit vier Pins

schwarz -> GND DHT
blau (22) -> Daten­pin DHT
gelb (27) -> nicht ange­schlos­sen
rot -> VCC DHT

#include "Adafruit_ILI9341.h"
#include "U8g2_for_Adafruit_GFX.h"

// Objekt u8g2Schriften
U8G2_FOR_ADAFRUIT_GFX u8g2Schriften;

#include "DHT.h"

int SENSOR_DHT = 22;

#define SensorTyp DHT22

// Sensor einen Namen zuweisen
DHT dht(SENSOR_DHT, SensorTyp); 

#define TFT_BL   21
#define TFT_CS   15 
#define TFT_DC    2
#define TFT_MISO 12
#define TFT_MOSI 13
#define TFT_SCLK 14
#define TFT_RST  -1

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST, TFT_MISO);

// Farben
#define SCHWARZ     0x0000
#define WEISS       0xFFFF
#define BLAU        0x001F
#define ROT         0xF800
#define GRUEN       0x07E0
#define CYAN        0x07FF
#define MAGENTA     0xF81F
#define GELB        0xFFE0
#define BRAUN       0x9A60
#define GRAU        0x7BEF
#define GRUENGELB   0xB7E0
#define DUNKELCYAN  0x03EF
#define ORANGE      0xFDA0
#define PINK        0xFE19
#define BORDEAUX    0xA000
#define HELLBLAU    0x867D
#define VIOLETT     0x915C
#define SILBER      0xC618
#define GOLD        0xFEA0

// Farben Messwerte/Piktogramm
#define FarbeLuftfeuchtigkeit GRUEN
#define FarbeTemperatur BLAU

void setup() 
{
  // Sensor starten
  dht.begin();

  // Backlight einschalten
  pinMode(TFT_BL, OUTPUT);
  digitalWrite(TFT_BL, HIGH);

  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(SCHWARZ);

  // Schriften von u8g2 tft zuordnen
  u8g2Schriften.begin(tft); 
}

void loop()
{
  TemperaturAnzeigen();
  delay(10000);
}

void TemperaturAnzeigen()
{
  // Temperatur lesen 
  String Temperatur = String(dht.readTemperature());

  // replace -> . durch , ersetzen
  Temperatur.replace(".", ",");

  // Luftfeuchtigkeit lesen 
  String Luftfeuchtigkeit = String(dht.readHumidity());

  // replace -> . durch , ersetzen
  Luftfeuchtigkeit.replace(".", ",");

  // Bereich für die Messwerte löschen
  tft.fillRect(20, 40, 270, 150, SCHWARZ);

  u8g2Schriften.setCursor(20, 100);
  u8g2Schriften.setForegroundColor(FarbeLuftfeuchtigkeit);   
  u8g2Schriften.setFont(u8g2_font_logisoso58_tf);   
  u8g2Schriften.print(Luftfeuchtigkeit + "%");

  u8g2Schriften.setCursor(20, 180);
  u8g2Schriften.setForegroundColor(FarbeTemperatur);
  u8g2Schriften.print(Temperatur + "°C");
}

Tem­pe­ra­tur und Luft­feuch­tig­keit mit DHT-Sen­sor und Touch­screen-Bedie­nung anzeigen

#include "Adafruit_ILI9341.h"
#include "U8g2_for_Adafruit_GFX.h"
#include "XPT2046_Touchscreen.h"

// Objekt u8g2Schriften
U8G2_FOR_ADAFRUIT_GFX u8g2Schriften;

#include "DHT.h"

int SENSOR_DHT = 22;

#define SensorTyp DHT22

// Sensor einen Namen zuweisen
DHT dht(SENSOR_DHT, SensorTyp); 

#define TFT_BL   21
#define TFT_CS   15 
#define TFT_DC    2
#define TFT_MISO 12
#define TFT_MOSI 13
#define TFT_SCLK 14
#define TFT_RST  -1

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST, TFT_MISO);

// Touchscreen SPI-Pins
#define TOUCH_IRQ 36
#define TOUCH_MOSI 32  
#define TOUCH_MISO 39  
#define TOUCH_CLK 25   
#define TOUCH_CS 33

// Touchscreen Koordinaten (z = Druck)
int x, y, z;

// SPI-Pins als Hardware-SPI
SPIClass touchscreenSPI = SPIClass(VSPI);
XPT2046_Touchscreen touchscreen(TOUCH_CS, TOUCH_IRQ);

// Farben
#define SCHWARZ     0x0000
#define WEISS       0xFFFF
#define BLAU        0x001F
#define ROT         0xF800
#define GRUEN       0x07E0
#define CYAN        0x07FF
#define MAGENTA     0xF81F
#define GELB        0xFFE0
#define BRAUN       0x9A60
#define GRAU        0x7BEF
#define GRUENGELB   0xB7E0
#define DUNKELCYAN  0x03EF
#define ORANGE      0xFDA0
#define PINK        0xFE19
#define BORDEAUX    0xA000
#define HELLBLAU    0x867D
#define VIOLETT     0x915C
#define SILBER      0xC618
#define GOLD        0xFEA0

// Farben Messwerte/Piktogramm
#define FarbeLuftfeuchtigkeit BLAU
#define FarbeTemperatur ROT

const unsigned char Thermometer [] PROGMEM = {
	// 'Thermometer, 34x70px
	0x00, 0x07, 0xf0, 0x00, 0x00, 0x00, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0x3f, 0xfe, 0x00, 0x00, 0x00, 
	0x7c, 0x0f, 0x00, 0x00, 0x00, 0x70, 0x07, 0x80, 0x00, 0x00, 0xe0, 0x03, 0xc0, 0x00, 0x00, 0xe0, 
	0x01, 0xc0, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x01, 0xc0, 0x01, 
	0xc0, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x0f, 0xc0, 0x01, 0xc0, 0x00, 0x0f, 0xc0, 0x01, 0xc0, 
	0x00, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00, 
	0x00, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00, 0x0f, 0xc0, 0x01, 0xc0, 0x00, 0x0f, 
	0xc0, 0x01, 0xc0, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc0, 
	0x01, 0xc0, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00, 0x0f, 0xc0, 0x01, 
	0xc0, 0x00, 0x0f, 0xc0, 0x01, 0xc0, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x00, 0xc3, 0xe1, 0xc0, 
	0x00, 0x00, 0xc3, 0xf1, 0xc0, 0x00, 0x00, 0xc3, 0xf1, 0xc0, 0x00, 0x0f, 0xc3, 0xf1, 0xc0, 0x00, 
	0x0f, 0xc3, 0xf1, 0xc0, 0x00, 0x0f, 0xc3, 0xf1, 0xc0, 0x00, 0x00, 0xc3, 0xf1, 0xc0, 0x00, 0x00, 
	0xc3, 0xf1, 0xc0, 0x00, 0x00, 0xc3, 0xf1, 0xc0, 0x00, 0x00, 0xc3, 0xf1, 0xc0, 0x00, 0x00, 0xc3, 
	0xf1, 0xc0, 0x00, 0x00, 0xc3, 0xf1, 0xc0, 0x00, 0x03, 0xc3, 0xf1, 0xf0, 0x00, 0x07, 0xc3, 0xf0, 
	0xf8, 0x00, 0x0f, 0x03, 0xf0, 0x7c, 0x00, 0x0e, 0x03, 0xe0, 0x3c, 0x00, 0x1c, 0x07, 0xf0, 0x1e, 
	0x00, 0x3c, 0x1f, 0xfc, 0x0f, 0x00, 0x38, 0x3f, 0xfe, 0x0f, 0x00, 0x78, 0x7f, 0xff, 0x07, 0x80, 
	0x70, 0x7f, 0xff, 0x87, 0x80, 0x70, 0x7f, 0xff, 0x83, 0x80, 0xf0, 0xff, 0xff, 0x83, 0xc0, 0xf0, 
	0xff, 0xff, 0xc3, 0xc0, 0xf0, 0xff, 0xff, 0xc3, 0xc0, 0xf0, 0xff, 0xff, 0xc3, 0xc0, 0xf0, 0xff, 
	0xff, 0xc3, 0xc0, 0xf0, 0xff, 0xff, 0x83, 0xc0, 0x70, 0x7f, 0xff, 0x83, 0x80, 0x70, 0x7f, 0xff, 
	0x87, 0x80, 0x78, 0x3f, 0xff, 0x07, 0x80, 0x38, 0x3f, 0xfe, 0x0f, 0x00, 0x3c, 0x0f, 0xfc, 0x0f, 
	0x00, 0x1e, 0x03, 0xe0, 0x1e, 0x00, 0x1f, 0x00, 0x00, 0x3e, 0x00, 0x0f, 0x00, 0x00, 0x7c, 0x00, 
	0x07, 0xe0, 0x01, 0xf8, 0x00, 0x03, 0xf8, 0x07, 0xf0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 
	0x7f, 0xff, 0x80, 0x00, 0x00, 0x1f, 0xfe, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00
};

// Arrays Piktogramme
const unsigned char Regen [] PROGMEM = {
	// 'Regen, 60x49px
	0x00, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x02, 0x08, 0x21, 0x04, 0x10, 0x00, 0x00, 0x00, 0x06, 0x18, 0x63, 0x0c, 0x30, 0x80, 0x00, 
	0x00, 0x06, 0x10, 0x63, 0x0c, 0x31, 0x80, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x20, 0x84, 0x10, 0x41, 0x08, 0x20, 0x00, 0x00, 0x61, 0x8c, 0x30, 0xc3, 0x18, 0x60, 0x00, 
	0x08, 0xc1, 0x8c, 0x30, 0xc3, 0x18, 0x61, 0x00, 0x00, 0x41, 0x04, 0x20, 0x82, 0x08, 0x40, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x30, 0x86, 0x18, 0x43, 0x04, 0x30, 0x80, 
	0x18, 0x71, 0x86, 0x18, 0xc3, 0x0c, 0x31, 0x80, 0x18, 0x21, 0x84, 0x10, 0xc3, 0x0c, 0x21, 0x80, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x18, 0x21, 0x04, 0x10, 0x42, 0x18, 0x40, 
	0x86, 0x18, 0x63, 0x0c, 0x30, 0xc6, 0x18, 0xc0, 0x86, 0x10, 0x63, 0x0c, 0x30, 0xc6, 0x18, 0xc0, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x18, 0x21, 0x04, 0x10, 0xc2, 0x0c, 0x21, 0x00, 0x30, 0x63, 0x0c, 0x31, 0xc6, 0x0c, 0x63, 0x00, 
	0x30, 0x63, 0x0c, 0x31, 0x86, 0x18, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x06, 0x10, 0x43, 0x08, 0x20, 0x86, 0x10, 0x00, 0x06, 0x30, 0xc3, 0x18, 0x61, 0x86, 0x30, 0x00, 
	0x04, 0x30, 0xc2, 0x18, 0x61, 0x8c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x80, 0x00, 0x00, 0x0c, 0x30, 0xc6, 0x18, 0x61, 0x00, 0x00, 
	0x00, 0x00, 0x61, 0xc6, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00, 0x60, 0x86, 0x10, 0x60, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

void setup() 
{
  Serial.begin(9600);

  // Sensor starten
  dht.begin();

  // SPI-Bus für den Touchscreen starten
  touchscreenSPI.begin(TOUCH_CLK, TOUCH_MISO, TOUCH_MOSI, TOUCH_CS);
  touchscreen.begin(touchscreenSPI);

  // Backlight einschalten
  pinMode(TFT_BL, OUTPUT);
  digitalWrite(TFT_BL, HIGH);

  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(SCHWARZ);

  // Schriften von u8g2 tft zuordnen
  u8g2Schriften.begin(tft); 

	// Button
	tft.fillRect(20, 180, 200, 50, ROT);
  tft.drawRoundRect(20, 180, 200, 50, 5, WEISS);
	tft.drawRoundRect(19, 179, 199, 49, 5, WEISS);
	u8g2Schriften.setCursor(30, 210);
	u8g2Schriften.setForegroundColor(WEISS);
  u8g2Schriften.setBackgroundColor(ROT);
	u8g2Schriften.setFont(u8g2_font_inb16_mf);
	u8g2Schriften.print("Aktualisieren");

  // Piktogramme anzeigen
  tft.drawBitmap(1, 30, Regen, 60, 49, FarbeLuftfeuchtigkeit);
  tft.drawBitmap(10, 100, Thermometer, 34, 70, FarbeTemperatur);

  TemperaturAnzeigen();
}

void loop()
{
  // wenn der Touchscreen berührt wurde
  if (touchscreen.tirqTouched() && touchscreen.touched()) 
  {
    // Punkte x, y und Druck (z) ermitteln
    TS_Point Punkt = touchscreen.getPoint();

    /*
      die "Rohwerte" der Punkte x und y bewegen sich zwischen 1 und 3800 bzw. 3900
      daher müssen sie mit map auf die korrekten Bildschirmmaße
      korrigiert werden
    */
    x = map(Punkt.x, 240, 3800, 1, tft.width());
    y = map(Punkt.y, 320, 3900, 1, tft.height());
    
    z = Punkt.z;
    
    // Kordinaten im Seriellen Monitor anzeigen
    KoordinatenAnzeigen(x, y, z);
    
    // die Koordinaten werden durch die Punkte  des Buttons festgelegt
    if (x >= 20 && x <= 200 && y >= 180 && y <= 250) 
    {
      TemperaturAnzeigen();
    }
  }
  delay(100);
}

void TemperaturAnzeigen()
{
  // Temperatur lesen 
  String Temperatur = String(dht.readTemperature());

  // replace -> . durch , ersetzen
  Temperatur.replace(".", ",");

  // Luftfeuchtigkeit lesen 
  String Luftfeuchtigkeit = String(dht.readHumidity());

  // replace -> . durch , ersetzen
  Luftfeuchtigkeit.replace(".", ",");

  // Beriech für die Messwerte löschen
  tft.fillRect(65, 10, 270, 150, SCHWARZ);

  u8g2Schriften.setBackgroundColor(SCHWARZ);
  u8g2Schriften.setCursor(70, 80);
  u8g2Schriften.setForegroundColor(FarbeLuftfeuchtigkeit);   
  u8g2Schriften.setFont(u8g2_font_logisoso58_tf);   
  u8g2Schriften.print(Luftfeuchtigkeit + "%");

  u8g2Schriften.setCursor(70, 160);
  u8g2Schriften.setForegroundColor(FarbeTemperatur);   
  u8g2Schriften.setForegroundColor(FarbeTemperatur);
  u8g2Schriften.print(Temperatur + "°C");
}

void KoordinatenAnzeigen(int x, int y, int z) 
{
  Serial.print("x-Koordinate = ");
  Serial.print(x);
  Serial.print(" | y-Koordinate = ");
  Serial.print(y);
  Serial.print(" | Druck = ");
  Serial.print(z);
  Serial.println();
}

Tem­pe­ra­tur und Luft­druck mit BMP280 anzeigen

Der nor­ma­le I²C-Pin 21 kann nicht ver­wen­det wer­den, weil er die Hin­ter­grund­be­leuch­tung des Dis­plays ein­schal­tet. Die I²C-Pins müs­sen daher "umge­lenkt" werden.

Die Stan­dard-HEX-Adres­se des BMP280 ist 0×77. In die­sem Fall genügt der Auf­ruf bmp.begin().
Wenn das nicht funk­tio­niert, kannst du die HEX-Adres­se mit fol­gen­den Pro­gramm her­aus­fin­den.
Dem Auf­ruf von bmp.begin muss dann in den Klam­mern die HEX-Adres­se mit­ge­teilt werden.

#include "Wire.h"

// I2C-Pins umlenken
#define SDA_PIN 22
#define SCL_PIN 27

void setup()
{
  // Wire mit geänderten I2C-Pins starten
  Wire.begin(SDA_PIN, SCL_PIN);
  Serial.begin(9600);
  delay(1000);
  Serial.print("I2C Scanner");
}

void loop()
{
  byte Fehler, Adresse;
  int Geraete = 0;
  Serial.println("Starte Scanvorgang");

  for (Adresse = 1; Adresse < 127; Adresse++ )
  {
    // Übertragung starten
    Wire.beginTransmission(Adresse);

    // wenn die Übertragung beendet wird
    Fehler = Wire.endTransmission();

    if (Fehler == 0)
    {
      Serial.print("I2C Gerät gefunden - Adresse: 0x");
      if (Adresse < 16) Serial.print("0");
      Serial.print(Adresse, HEX);
      Serial.println("");
      Geraete++;
    }
  }
  if (Geraete == 0) Serial.println("Keine I2C Geräte gefunden\n");
  else Serial.println("Scanvorgang abgeschlossen");

  delay(5000);
}

JST-Ste­cker 1,25 mm mit vier Pins

schwarz -> GND
blau -> SDA (22)
gelb -> SCL (27)
rot -> VCC

Das Pro­gramm

#include "Adafruit_ILI9341.h"
#include "U8g2_for_Adafruit_GFX.h"

// Objekt u8g2Schriften
U8G2_FOR_ADAFRUIT_GFX u8g2Schriften;

#include "Adafruit_BMP280.h"

Adafruit_BMP280 bmp;

#define SDA_PIN 22
#define SCL_PIN 27

#define TFT_BL   21
#define TFT_CS   15 
#define TFT_DC    2
#define TFT_MISO 12
#define TFT_MOSI 13
#define TFT_SCLK 14
#define TFT_RST  -1

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST, TFT_MISO);

// Farben
#define SCHWARZ     0x0000
#define WEISS       0xFFFF
#define BLAU        0x001F
#define ROT         0xF800
#define GRUEN       0x07E0
#define CYAN        0x07FF
#define MAGENTA     0xF81F
#define GELB        0xFFE0
#define BRAUN       0x9A60
#define GRAU        0x7BEF
#define GRUENGELB   0xB7E0
#define DUNKELCYAN  0x03EF
#define ORANGE      0xFDA0
#define PINK        0xFE19
#define BORDEAUX    0xA000
#define HELLBLAU    0x867D
#define VIOLETT     0x915C
#define SILBER      0xC618
#define GOLD        0xFEA0

void setup() 
{
  // Sensor starten
  Wire.begin(SDA_PIN, SCL_PIN);
  bmp.begin();

  // Backlight einschalten
  pinMode(TFT_BL, OUTPUT);
  digitalWrite(TFT_BL, HIGH);

  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(SCHWARZ);

  // Schriften von u8g2 tft zuordnen
  u8g2Schriften.begin(tft); 
}

void loop()
{
  DatenAnzeigen();
  delay(10000);
}

void DatenAnzeigen()
{
  // Temperatur lesen 
  String Temperatur = String(bmp.readTemperature());

  // replace -> . durch , ersetzen
  Temperatur.replace(".", ",");

  String Luftdruck = String(bmp.readPressure() / 100);
  Luftdruck.replace(".", ",");

  // Beriech für die Messwerte löschen
  tft.fillRect(1, 40, 300, 150, SCHWARZ);

  u8g2Schriften.setCursor(10, 100);
  u8g2Schriften.setForegroundColor(BLAU);   
  u8g2Schriften.setFont(u8g2_font_logisoso42_tf);   
  u8g2Schriften.print(Luftdruck + " hPa");

  u8g2Schriften.setCursor(10, 180);
  u8g2Schriften.setForegroundColor(ROT);
  u8g2Schriften.print(Temperatur + "°C");
}

Ana­lo­ge Uhr mit Temperaturanzeige

Das Pro­gramm

#include "WiFi.h"
#include "time.h"
#include "Adafruit_ILI9341.h"
#include "U8g2_for_Adafruit_GFX.h"
#include "DHT.h"

// Objekt u8g2Schriften
U8G2_FOR_ADAFRUIT_GFX u8g2Schriften;

int SENSOR_DHT = 22;

#define SensorTyp DHT22

// Sensor einen Namen zuweisen
DHT dht(SENSOR_DHT, SensorTyp); 

#define TFT_BL   21
#define TFT_CS   15 
#define TFT_DC    2
#define TFT_MISO 12
#define TFT_MOSI 13
#define TFT_SCLK 14
#define TFT_RST  -1

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST, TFT_MISO);

// WiFi-Daten anpassen
char Router[] = "Router_SSID";
char Passwort[] = "xxxxxxxx";

// Variablen des TFTs (Höhe, Breite, Radius)
const int MitteHoehe = 120;
const int MitteBreite = 120;
const int Radius = 120;

// Multiplikatoren für x- y-Positionen der Stunden, Minuten und Sekunden
float SekundePosX = 0, SekundePosY = 0, MinutePosX = 0, MinutePosY = 0, StundePosX = 0, StundePosY = 0;
float GradSekunden = 0, GradMinuten = 0, GradStunden = 0;

// x- y-Koordinaten für die Anzeige Stunden, Minuten und Sekunden
int SekundenZeigerX = MitteHoehe, SekundenZeigerY = MitteHoehe;
int MinutenZeigerX = MitteHoehe, MinutenZeigerY = MitteHoehe;
int StundenZeigerX = MitteHoehe, StundenZeigerY = MitteHoehe; 

// Start wird nur beim ersten Start für den Aufbau des TFTs benötigt
bool Start = 1;

// Variablen für die Markierungen und Punkte und Striche des Ziffernblatts
float PosX, PosY;
int PunktX, PunktY, PunktX1, PunktX2, PunktY1, PunktY2;

// Variablen für die Zeit
int Stunden, Minuten, Sekunden;

// Farben
#define SCHWARZ     0x0000
#define WEISS       0xFFFF
#define BLAU        0x001F
#define ROT         0xF800
#define GRUEN       0x07E0
#define CYAN        0x07FF
#define MAGENTA     0xF81F
#define GELB        0xFFE0
#define BRAUN       0x9A60
#define GRAU        0x7BEF
#define GRUENGELB   0xB7E0
#define DUNKELCYAN  0x03EF
#define ORANGE      0xFDA0
#define PINK        0xFE19
#define BORDEAUX    0xA000
#define HELLBLAU    0x867D
#define VIOLETT     0x915C
#define SILBER      0xC618
#define GOLD        0xFEA0

// Farben innerer Kreis, Randfarbe und Zeigerfarbe
// die Farben der Zeiger können aber auch individuell gesetzt werden
const int Kreisfarbe = SCHWARZ;
const int Zeigerfarbe = WEISS;
const int Randfarbe = BORDEAUX;

// true -> Datum anzeigen
// false -> Datum nicht anzeigen
bool DatumAnzeigen = true;

// true -> Sekundenzeiger nur als Kreis
bool SekundenzeigerKreis = true;

// Ziffern 12 3 6 9 anzeigen/nicht anzeigen
bool Ziffernanzeigen = true;

// NTP-Server aus dem Pool
#define Zeitserver "de.pool.ntp.org"

/*
  Liste der Zeitzonen
  https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  Zeitzone CET = Central European Time -1 -> 1 Stunde zurück
  CEST = Central European SuMinutener Time von
  M3 = März, 5.0 = Sonntag 5. Woche, 02 = 2 Uhr
  bis M10 = Oktober, 5.0 = Sonntag 5. Woche 03 = 3 Uhr
*/
#define Zeitzone "CET-1CEST,M3.5.0/02,M10.5.0/03"

// time_t enthält die Anzahl der Sekunden seit dem 1.1.1970 0 Uhr
time_t aktuelleZeit;

/* 
  Struktur tm
  tm_hour -> Stunde: 0 bis 23
  tm_min -> Minuten: 0 bis 59
  tm_sec -> Sekunden 0 bis 59
  tm_mday -> Tag 1 bis 31
  tm_mon -> Monat: 0 (Januar) bis 11 (Dezember)
  tm_year -> Jahre seit 1900
  tm_yday -> vergangene Tage seit 1. Januar des Jahres
  tm_isdst -> Wert > 0 = SoMinutenerzeit (dst = daylight saving time)
*/
tm Zeit;

void setup() 
{
  // Sensor starten
  dht.begin();

    // Schriften von u8g2 tft zuordnen
  u8g2Schriften.begin(tft); 

  Serial.begin(9600);

  // Zeitzone: Parameter für die zu ermittelnde Zeit
  configTzTime(Zeitzone, Zeitserver);

  // WiFi starten
  WiFi.mode(WIFI_STA);
  WiFi.begin(Router, Passwort);

  Serial.println("------------------------");

  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(200);
    Serial.print(".");
  }
  
  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(Router);
  Serial.print("IP über DHCP: ");
  Serial.println(WiFi.localIP());

  // Zeit holen
  time(&aktuelleZeit);

  // localtime_r -> Zeit in die lokale Zeitzone setzen
  localtime_r(&aktuelleZeit, &Zeit);

  // Zeit in Stunden, Minuten und Sekunden
  Stunden = Zeit.tm_hour, Minuten = Zeit.tm_min, Sekunden = Zeit.tm_sec;
  
  // Hintergrundbeleuchtung einschalten
  pinMode(TFT_BL, OUTPUT);
  digitalWrite(TFT_BL, HIGH);

  tft.begin();
  tft.setRotation(2);
  tft.fillScreen(Kreisfarbe);

  // 4 Pixel breiter äußerer Rand, Farbe au der Farbpalette wählen
  tft.drawCircle(MitteHoehe, MitteBreite, Radius - 1, Randfarbe);
  tft.drawCircle(MitteHoehe, MitteBreite, Radius - 2, Randfarbe);
  tft.drawCircle(MitteHoehe, MitteBreite, Radius - 3, Randfarbe);
  tft.drawCircle(MitteHoehe, MitteBreite, Radius - 4, Randfarbe);

  // innere Fläche bis auf den Rand von 4 Pixeln vollständig löschen
  // wenn andere Farbe als äußerer Rand gewählt wird ergibt sich ein schmaler Rand
  tft.fillCircle(MitteHoehe, MitteBreite, Radius - 4, Kreisfarbe);

  /*
    alle 30° Linie am Rand als Stundenmarkierung zeichnen
    DEG_TO_RAD (= PI/180 = 0.0174532925) -> Winkel in Bogenmaß umrechnen
    sin/cos berechnen die x-/y-Kordinaten des Punktes auf der Kreislinie
  */
  for (int i = 0; i < 360; i += 30) 
  {
    PosX = cos((i - 90) * DEG_TO_RAD);
    PosY = sin((i - 90) * DEG_TO_RAD);

    // kurze Linien zeichnen, von 114 bis 100 vom äußeren Rand aus
    // Farbe individuell wählbar
    int PunktX1 = PosX * 110 + Radius;
    int PunktY1 = PosY * 110 + Radius;
    int PunktX2 = PosX * 100 + Radius;
    int PunktY2 = PosY * 100 + Radius;

    // keine Striche an der Position der Zahlen
    if (PunktX1 == 10 || PunktX1 == 120 || PunktX1 == 230)
    {
      tft.drawLine(PunktX1, PunktY1, PunktX2, PunktY2, Kreisfarbe);
    }
    else tft.drawLine(PunktX1, PunktY1, PunktX2, PunktY2, Zeigerfarbe);
  }

  // alle 6 Grad Punkte als Sekundenmarkierung zeichnen
  for (int i = 0; i < 360; i += 6) 
  {
    PosX = cos((i - 90) * DEG_TO_RAD);
    PosY = sin((i - 90) * DEG_TO_RAD);

    // Positionen der Punkte
    // 108 -> Abstand vom Mittelpunkt
    PunktX = PosX * 108 + Radius;
    PunktY = PosY * 108 + Radius;
    tft.drawPixel(PunktX, PunktY, Zeigerfarbe);  
  }

  // Markierung 12 3 6 9
  if (Ziffernanzeigen)
  {
    u8g2Schriften.setFont(u8g2_font_helvB14_tf);  
    u8g2Schriften.setForegroundColor(Zeigerfarbe);
    u8g2Schriften.setCursor(110, 25);
    u8g2Schriften.print("12");

    u8g2Schriften.setCursor(10, 125);
    u8g2Schriften.print("9");

    u8g2Schriften.setCursor(220, 125);
    u8g2Schriften.print("3");
  
    u8g2Schriften.setCursor(113, 230);
    u8g2Schriften.print("6");
  }

  if (DatumAnzeigen)
  {
    ZeigeDatum();
  }

  TemperaturAnzeigen();
}

void loop() 
{
  // Sekunden weiter zählen
  // wenn millis() ohne Rest durch 1000 teilbar ist
  if (millis() %1000 == 0)
  {
    Sekunden++;  

    if (Sekunden == 60) 
    { 
      Sekunden = 0; 
      Minuten++; 

      TemperaturAnzeigen();
      
      // Zeit jede Minute mit Zeitserver synchronisieren
      // aktuelle Zeit holen
      time(&aktuelleZeit);

      // localtime_r -> Zeit in die lokale Zeitzone setzen
      localtime_r(&aktuelleZeit, &Zeit);

      // Zeit in Stunden, Minuten und Sekunden
      Stunden = int(Zeit.tm_hour), Minuten = int(Zeit.tm_min), Sekunden = int(Zeit.tm_sec);

      if (Minuten > 59) 
      {
        Minuten = 0;
        Stunden++;  
        if (Stunden > 11) 
        {
          Stunden = 0;
        }
      }
    }

    // Datum anzeigen/nicht anzeigen
    if (DatumAnzeigen && !SekundenzeigerKreis)
    {
      // Anzeige des Datums nur aktualisieren,
      // wenn sich der Sekundenzeiger darüber befindet
      if (Sekunden > 23 & Sekunden < 40)
      {
        ZeigeDatum();
      }
    }

    // Vorausberechnung der x- und y-Koordinaten
    // 0-59 -> 0-354 = Faktor 6
    GradSekunden = Sekunden * 6;    

    // Minuten+Sekunden in Relation zu 3600 setzen
    // 60 / 3600 = 0.01666667         
    GradMinuten = Minuten * 6 + GradSekunden * 0.01666667; 

    // 30 / 3600 = 0.0833333
    // Stunden+Minuten in Relation zu 360 setzen
    // 0-11 -> 0-360 
    GradStunden = Stunden * 30 + GradMinuten * 0.0833333;  // 0-11 -> 0-360 
    StundePosX = cos((GradStunden - 90) * DEG_TO_RAD);
    StundePosY = sin((GradStunden - 90) * DEG_TO_RAD);

    MinutePosX = cos((GradMinuten - 90) * DEG_TO_RAD) ;
    MinutePosY = sin((GradMinuten - 90) * DEG_TO_RAD);

    SekundePosX = cos((GradSekunden - 90) * DEG_TO_RAD);
    SekundePosY = sin((GradSekunden - 90) * DEG_TO_RAD);

    // nach jeder Minute Minuten-/Stundenzeiger löschen
    // oder einmalig beim Start der Anzeige
    if (Sekunden == 0 || Start) 
    {
      // Datum erneuern wenn es korrekt ist (!= 1970)
      if (Zeit.tm_year + 1900 != 1970 && DatumAnzeigen)
      {
        ZeigeDatum();
      }
      
      Start = false;
      tft.drawLine(StundenZeigerX, StundenZeigerY, MitteHoehe, MitteHoehe + 1, Kreisfarbe);  

      // 62 Pixel -> Länge des Stundenzeigers
      // Mittelpunkt + 1 -> Mittelpunkt soll nicht gelöscht werden
      StundenZeigerX = StundePosX * 62 + MitteHoehe + 1;
      StundenZeigerY = StundePosY * 62 + MitteHoehe + 1;
      tft.drawLine(MinutenZeigerX, MinutenZeigerY, MitteHoehe, MitteHoehe + 1, Kreisfarbe);

      // 84 Pixel -> Länge des Minutenzeigers
      // Mittelpunkt + 1 -> Mittelpunkt soll nicht gelöscht werden
      MinutenZeigerX = MinutePosX * 84 + MitteHoehe;
      MinutenZeigerY = MinutePosY * 84 + MitteHoehe + 1;
    }

    // Sekundenzeiger löschen
    if (!SekundenzeigerKreis) tft.drawLine(SekundenZeigerX, SekundenZeigerY, MitteHoehe, MitteHoehe + 1, Kreisfarbe);

    // Kreis am Sekundenzeiger löschen, Radius 5
    tft.fillCircle(SekundenZeigerX, SekundenZeigerY, 5, Kreisfarbe);

    // 85 Pixel -> Länge des Sekundenzeigers
    SekundenZeigerX = SekundePosX * 85 + MitteHoehe + 1;
    SekundenZeigerY = SekundePosY * 85 + MitteHoehe + 1;

    // Zeiger neu zeichnen
    // Sekunden Linie nur anzeigen wenn SekundenzeigerKreis false
    if (!SekundenzeigerKreis) tft.drawLine(SekundenZeigerX, SekundenZeigerY, MitteHoehe, MitteHoehe + 1, ROT);
    
    // Minuten
    tft.drawLine(MinutenZeigerX, MinutenZeigerY, MitteHoehe, MitteHoehe + 1, Zeigerfarbe);

    // Stunden
    tft.drawLine(StundenZeigerX, StundenZeigerY, MitteHoehe, MitteHoehe + 1, Zeigerfarbe);

    // Kreis an der Spitze des Sekundenzeigers, Radius 5
    tft.fillCircle(SekundenZeigerX, SekundenZeigerY, 5, ROT);

    // Mittelpunkt zeichnen
    tft.fillCircle(MitteHoehe, MitteHoehe + 1, 3, Zeigerfarbe); 
  }
}

void ZeigeDatum()
{
  u8g2Schriften.setFont(u8g2_font_helvB14_tf);    
  u8g2Schriften.setCursor(75, 180);
  u8g2Schriften.setForegroundColor(GRUEN);
      
  // Bildschirmbereich für das Datum löschen
  tft.fillRect(75, 160, 125, 25, Kreisfarbe);
  if (Zeit.tm_mday < 10) u8g2Schriften.print("0");
  u8g2Schriften.print(Zeit.tm_mday);
  u8g2Schriften.print(".");

  // Monat: führende 0 ergänzen
  if (Zeit.tm_mon < 9) u8g2Schriften.print("0");
    
  // Zählung beginnt mit 0 -> +1
  u8g2Schriften.print(Zeit.tm_mon + 1);
  u8g2Schriften.print(".");

  // Anzahl Jahre seit 1900
  u8g2Schriften.print(Zeit.tm_year + 1900);
}

void TemperaturAnzeigen()
{
  // Temperatur lesen 
  String Temperatur = String(dht.readTemperature());

  // replace -> . durch , ersetzen
  Temperatur.replace(".", ",");

  // Luftfeuchtigkeit lesen 
  String Luftfeuchtigkeit = String(dht.readHumidity());

  // replace -> . durch , ersetzen
  Luftfeuchtigkeit.replace(".", ",");

  tft.fillRect(10, 250, 125, 70, SCHWARZ);
  u8g2Schriften.setForegroundColor(BLAU);   
  u8g2Schriften.setBackgroundColor(SCHWARZ);
  u8g2Schriften.setCursor(10, 275);
  u8g2Schriften.setFont(u8g2_font_helvB24_tf);   
  u8g2Schriften.print(Luftfeuchtigkeit + " %");

  u8g2Schriften.setCursor(10, 310);
  u8g2Schriften.setForegroundColor(ROT);
  u8g2Schriften.print(Temperatur + " °C");
}

Foto­schau

koeln.bmpoverath_bahnhof.bmplindos.bmpbraunwald.bmpdresden_frauenkirche.bmp
chartres.bmpstrand.bmpberlin_olympia.bmpuni_bonn.bmpduenen_ibiza.bmp
st_michelle.bmpijlst.bmpmonschau.bmpgaios.bmpkoeln_deutz.bmp

Das Pro­gramm

#include "SdFat.h"
#include "Adafruit_ILI9341.h"
#include "Adafruit_ImageReader.h"

#define TFT_BL   21
#define TFT_CS   15 
#define TFT_DC    2
#define TFT_MISO 12
#define TFT_MOSI 13
#define TFT_SCLK 14
#define TFT_RST  -1

/* 
  SD VSPI Standard-Pins
  CLK    18
  MOSI   23
  MISO   19
  CS      5
*/

// Objekt tft der Bibliothek Adafruit_ST7796S_kbv erstellen
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST, TFT_MISO);

// 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 = 6000;

bool Beschreibung = true;

void setup() 
{
  Serial.begin(9600);

  // auf serielle Verbindung warten
  while (!Serial);
  delay(1000);
 
  // TFT starten
  tft.begin();
  
  // Hintergrundbeleuchtung einschalten
  pinMode(TFT_BL, OUTPUT);
  digitalWrite(TFT_BL, HIGH);
  
  // Rotation anpassen
  tft.setRotation(3);

  // schwarzer Hintergrund
  tft.fillScreen(SCHWARZ);
  tft.setTextSize(2);
  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);
  tft.setTextSize(2);
}

void loop() 
{ 
  reader.drawBMP("strand.bmp", tft, 0, 0);

  if (Beschreibung)
  {
    tft.setCursor(10, 220);  
    tft.fillRect(1, 220, tft.width(), tft.height(), SCHWARZ);  
    tft.print("Strand Algarve");
  }
  delay(Intervall);
 
  reader.drawBMP("koeln.bmp", tft, 0, 0);

  if (Beschreibung)
  {
    tft.setCursor(10, 220);  
    tft.fillRect(1, 220, tft.width(), tft.height(), SCHWARZ); 
    tft.print("K");
    // ö = 0x94
    tft.write(0x94);
    tft.println("ln Blick vom Messeturm");
  }
  
  delay(Intervall); 
 
  reader.drawBMP("berlin_olympia.bmp", tft, 0, 0);
  if (Beschreibung)
  {
    tft.setCursor(10, 220);  
    tft.fillRect(1, 220, tft.width(), tft.height(), SCHWARZ); 
    tft.print("Berlin Olympiastadion");
  }
  delay(Intervall);
 
  reader.drawBMP("walhalla.bmp", tft, 0, 0);
  if (Beschreibung)
  {;  
    tft.setCursor(10, 220);  
    tft.fillRect(1, 220, tft.width(), tft.height(), SCHWARZ); 
    tft.print("Walhalla Donaustauf");
  }

  delay(Intervall);
 
  reader.drawBMP("rathaus.bmp", tft, 0, 0);

  if (Beschreibung)
  {
    tft.setCursor(10, 220);  
    tft.fillRect(1, 220, tft.width(), tft.height(), SCHWARZ); 
    tft.print("Rathaus Bergisch Gladbach");
  }

  delay(Intervall);

  reader.drawBMP("gaios.bmp", tft, 0, 0);

 if (Beschreibung)
  {
    tft.setCursor(10, 220);  
    tft.fillRect(1, 220, tft.width(), tft.height(), SCHWARZ); 
    tft.print("Gaios Griechenland");
  }

  delay(Intervall);

  reader.drawBMP("dresden_frauenkirche.bmp", tft, 0, 0);

  if (Beschreibung)
  { 
    tft.setCursor(10, 220);  
    tft.fillRect(1, 220, tft.width(), tft.height(), SCHWARZ); 
    tft.print("Dresden Frauenkirche");
  }

  delay(Intervall);

  reader.drawBMP("dhuenntalsperre.bmp", tft, 0, 0);
  
  if (Beschreibung)
  {
    tft.setCursor(10, 220);  
    tft.fillRect(1, 220, tft.width(), tft.height(), SCHWARZ); 
    tft.print("Dh");
    // ü = 0x81
    tft.write(0x81);
    tft.print("nntalsperre");
  }

  delay(Intervall);
  
  reader.drawBMP("chartres.bmp", tft, 0, 0);

  if (Beschreibung)
  {
    tft.setCursor(10, 220);  
    tft.fillRect(1, 220, tft.width(), tft.height(), SCHWARZ); 
    tft.print("Chartres Dom");
  }

  delay(Intervall);

  reader.drawBMP("braunwald.bmp", tft, 0, 0);

  if (Beschreibung)
  {
    tft.setCursor(10, 115);  
    tft.setCursor(10, 220);  
    tft.fillRect(1, 220, tft.width(), tft.height(), SCHWARZ); 
    tft.print("Braunwald Schweiz");
  }

  delay(Intervall);
   
  reader.drawBMP("koeln_deutz.bmp", tft, 0, 0);

  if (Beschreibung)
  {
    tft.setCursor(10, 220);  
    tft.fillRect(1, 220, tft.width(), tft.height(), SCHWARZ); 
    tft.print("K");
    // ö = 0x94
    tft.write(0x94);
    tft.println("ln Deutz");
  }

  delay(Intervall);

  reader.drawBMP("sevilla.bmp", tft, 0, 0);
  
  if (Beschreibung)
  {
    tft.setCursor(10, 220);  
    tft.fillRect(1, 220, tft.width(), tft.height(), SCHWARZ); 
    tft.print("Sevilla Kathedrale");
  }
  delay(Intervall);
   
  reader.drawBMP("hoheward.bmp", tft, 0, 0);
  
  if (Beschreibung)
  {
    tft.setCursor(10, 220);  
    tft.fillRect(1, 220, tft.width(), tft.height(), SCHWARZ); 
    tft.print("Hoheward Herten");
  }
  
  delay(Intervall);

  reader.drawBMP("carvoeiro.bmp", tft, 0, 0);
  
  if (Beschreibung)
  {
    tft.setCursor(10, 220);  
    tft.fillRect(1, 220, tft.width(), tft.height(), SCHWARZ); 
    tft.print("Carvoeiro Portugal");
  }

  delay(Intervall);

  reader.drawBMP("st_michelle.bmp", tft, 0, 0);
  
  if (Beschreibung)
  {
    tft.setCursor(10, 220);  
    tft.fillRect(1, 220, tft.width(), tft.height(), SCHWARZ); 
    tft.print("St. Michelle Frankreich");
  }

  delay(Intervall);

  reader.drawBMP("dresden_bruecke.bmp", tft, 0, 0);

  if (Beschreibung)
  {
    tft.setCursor(10, 115);  
    tft.setCursor(10, 220);  
    tft.fillRect(1, 220, tft.width(), tft.height(), SCHWARZ); 
    tft.print("Dresden 'Blaues Wunder'");
  }
}

Ana­lo­ge Uhr mit Tem­pe­ra­tur­an­zei­ge mit der Biblio­thek TFT_eSPI

#include "WiFi.h"
#include "time.h"
#include "TFT_eSPI.h"
#include "U8g2_for_TFT_eSPI.h"
#include "DHT.h"

int SENSOR_DHT = 22;

#define SensorTyp DHT22

// Sensor einen Namen zuweisen
DHT dht(SENSOR_DHT, SensorTyp); 

// Objekt für Schriften von U8g2 (u8g2Schriften)
U8g2_for_TFT_eSPI u8g2Schriften;

TFT_eSPI tft = TFT_eSPI();

// WiFi-Daten
char Router[] = "FRITZ!Box 7590 LB";
char Passwort[] = "anea1246";

// Variablen des TFTs (Höhe, Breite, Radius)
const int MitteHoehe = 120;
const int MitteBreite = 120;
const int Radius = 120;

// Multiplikatoren für x- y-Positionen der Stunden, Minuten und Sekunden
float SekundePosX = 0, SekundePosY = 0, MinutePosX = 0, MinutePosY = 0, StundePosX = 0, StundePosY = 0;
float GradSekunden = 0, GradMinuten = 0, GradStunden = 0;

// x- y-Koordinaten für die Anzeige Stunden, Minuten und Sekunden
int SekundenZeigerX = MitteHoehe, SekundenZeigerY = MitteHoehe;
int MinutenZeigerX = MitteHoehe, MinutenZeigerY = MitteHoehe;
int StundenZeigerX = MitteHoehe, StundenZeigerY = MitteHoehe; 

// Start wird nur beim ersten Start für den Aufbau des TFTs benötigt
bool Start = 1;

// Variablen für die Markierungen und Punkte und Striche des Ziffernblatts
float PosX, PosY;
int PunktX, PunktY, PunktX1, PunktX2, PunktY1, PunktY2;

// Variablen für die Zeit
int Stunden, Minuten, Sekunden;

// Farben
#define SCHWARZ     0x0000
#define WEISS       0xFFFF
#define BLAU        0x001F
#define ROT         0xF800
#define GRUEN       0x07E0
#define CYAN        0x07FF
#define MAGENTA     0xF81F
#define GELB        0xFFE0
#define BRAUN       0x9A60
#define GRAU        0x7BEF
#define GRUENGELB   0xB7E0
#define DUNKELCYAN  0x03EF
#define ORANGE      0xFDA0
#define PINK        0xFE19
#define BORDEAUX    0xA000
#define HELLBLAU    0x867D
#define VIOLETT     0x915C
#define SILBER      0xC618
#define GOLD        0xFEA0

// Farben innerer Kreis, Randfarbe und Zeigerfarbe
// die Farben der Zeiger können aber auch individuell gesetzt werden
const int Kreisfarbe = SCHWARZ;
const int Zeigerfarbe = WEISS;
const int Randfarbe = BORDEAUX;

// true -> Datum anzeigen
// false -> Datum nicht anzeigen
bool DatumAnzeigen = true;

// Ziffern 12 3 6 9 anzeigen/nicht anzeigen
bool Ziffernanzeigen = true;

// true -> Sekundenzeiger nur als Kreis
bool SekundenzeigerKreis = true;

// NTP-Server aus dem Pool
#define Zeitserver "de.pool.ntp.org"

/*
  Liste der Zeitzonen
  https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  Zeitzone CET = Central European Time -1 -> 1 Stunde zurück
  CEST = Central European SuMinutener Time von
  M3 = März, 5.0 = Sonntag 5. Woche, 02 = 2 Uhr
  bis M10 = Oktober, 5.0 = Sonntag 5. Woche 03 = 3 Uhr
*/
#define Zeitzone "CET-1CEST,M3.5.0/02,M10.5.0/03"

// time_t enthält die Anzahl der Sekunden seit dem 1.1.1970 0 Uhr
time_t aktuelleZeit;

/* 
  Struktur tm
  tm_hour -> Stunde: 0 bis 23
  tm_min -> Minuten: 0 bis 59
  tm_sec -> Sekunden 0 bis 59
  tm_mday -> Tag 1 bis 31
  tm_mon -> Monat: 0 (Januar) bis 11 (Dezember)
  tm_year -> Jahre seit 1900
  tm_yday -> vergangene Tage seit 1. Januar des Jahres
  tm_isdst -> Wert > 0 = SoMinutenerzeit (dst = daylight saving time)
*/
tm Zeit;

unsigned long Zeitmessung = 0;  

void setup() 
{
  // Sensor starten
  dht.begin();

  Serial.begin(9600);

  // Schriften von u8g2 tft zuordnen
  u8g2Schriften.begin(tft);

  // Zeitzone: Parameter für die zu ermittelnde Zeit
  configTzTime(Zeitzone, Zeitserver);

  // WiFi starten
  WiFi.mode(WIFI_STA);
  WiFi.begin(Router, Passwort);

  Serial.println("------------------------");

  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(200);
    Serial.print(".");
  }
  
  Serial.println();
  Serial.print("Verbunden mit ");
  Serial.println(Router);
  Serial.print("IP über DHCP: ");
  Serial.println(WiFi.localIP());

  // Zeit holen
  time(&aktuelleZeit);

  // localtime_r -> Zeit in die lokale Zeitzone setzen
  localtime_r(&aktuelleZeit, &Zeit);

  // Zeit in Stunden, Minuten und Sekunden
  Stunden = Zeit.tm_hour, Minuten = Zeit.tm_min, Sekunden = Zeit.tm_sec;
  
  tft.begin();
  tft.setRotation(2);
  tft.fillScreen(SCHWARZ);

  // 4 Pixel breiter äußerer Rand, Farbe au der Farbpalette wählen
  tft.drawCircle(MitteHoehe, MitteBreite, Radius - 1, Randfarbe);
  tft.drawCircle(MitteHoehe, MitteBreite, Radius - 2, Randfarbe);
  tft.drawCircle(MitteHoehe, MitteBreite, Radius - 3, Randfarbe);
  tft.drawCircle(MitteHoehe, MitteBreite, Radius - 4, Randfarbe);

  // innere Fläche bis auf den Rand von 4 Pixeln vollständig löschen
  // wenn andere Farbe als äußerer Rand gewählt wird ergibt sich ein schmaler Rand
  tft.fillCircle(MitteHoehe, MitteBreite, Radius - 4, Kreisfarbe);

  /*
    alle 30° Linie am Rand als Stundenmarkierung zeichnen
    DEG_TO_RAD (= PI/180 = 0.0174532925) -> Winkel in Bogenmaß umrechnen
    sin/cos berechnen die x-/y-Kordinaten des Punktes auf der Kreislinie
  */
  for (int i = 0; i < 360; i += 30) 
  {
    PosX = cos((i - 90) * DEG_TO_RAD);
    PosY = sin((i - 90) * DEG_TO_RAD);

    // kurze Linien zeichnen, von 114 bis 100 vom äußeren Rand aus
    // Farbe individuell wählbar
    int PunktX1 = PosX * 110 + Radius;
    int PunktY1 = PosY * 110 + Radius;
    int PunktX2 = PosX * 100 + Radius;
    int PunktY2 = PosY * 100 + Radius;

    tft.drawLine(PunktX1, PunktY1, PunktX2, PunktY2, Zeigerfarbe);

    // keine Striche an der Position der Zahlen
    if (Ziffernanzeigen)
    {
      if (PunktX1 == 10 || PunktX1 == 120 || PunktX1 == 230)
      {
        tft.drawLine(PunktX1, PunktY1, PunktX2, PunktY2, Kreisfarbe);
      }
    }
  }

  // alle 6 Grad Punkte als Minutenmarkierung zeichnen
  for (int i = 0; i < 360; i += 6) 
  {
    PosX = cos((i - 90) * DEG_TO_RAD);
    PosY = sin((i - 90) * DEG_TO_RAD);

    // Positionen der Punkte
    // 108 -> Abstand vom Mittelpunkt
    PunktX = PosX * 108 + Radius;
    PunktY = PosY * 108 + Radius;
    tft.drawPixel(PunktX, PunktY, Zeigerfarbe);  
  }

  // Markierung 12 3 6 9
   if (Ziffernanzeigen)
  {
    tft.setTextSize(2);
    tft.setTextColor(Zeigerfarbe);
    tft.setCursor(110, 16);
    tft.print("12");

    tft.setCursor(10, 110);
    tft.print("9");

    tft.setCursor(220, 110);
    tft.print("3");
  
    tft.setCursor(113, 220);
    tft.print("6");
  }

  if (DatumAnzeigen)
  {
    ZeigeDatum();
  }

  TemperaturAnzeigen();

  Zeitmessung = millis() + 1000; 
}

void loop() 
{
  // Sekunden weiter zählen
  if (Zeitmessung < millis()) 
  {
    Zeitmessung += 1000;
    Sekunden ++;

    if (Sekunden == 60) 
    { 
      Sekunden = 0; 
      Minuten++; 
      TemperaturAnzeigen();

      // Zeit jede Sekunde mit Zeitserver synchronisieren
      // aktuelle Zeit holen
      time(&aktuelleZeit);

      // localtime_r -> Zeit in die lokale Zeitzone setzen
      localtime_r(&aktuelleZeit, &Zeit);

      // Zeit in Stunden, Minuten und Sekunden
      Stunden = int(Zeit.tm_hour), Minuten = int(Zeit.tm_min), Sekunden = int(Zeit.tm_sec);

      if (Minuten > 59) 
      {
        Minuten = 0;
        Stunden++;  
        if (Stunden > 11) 
        {
          Stunden = 0;
          
          // Datum anzeigen/nicht anzeigen
          if (DatumAnzeigen) ZeigeDatum();
        }
      }
    }

    // Datum anzeigen/nicht anzeigen
    if (DatumAnzeigen && !SekundenzeigerKreis)
    {
      // Anzeige des Datums nur aktualisieren,
      // wenn sich der Sekundenzeiger darüber befindet
      if (Sekunden > 23 & Sekunden < 40)
      {
        ZeigeDatum();
      }
    }
    // Vorausberechnung der x- und y-Koordinaten
    // 0-59 -> 0-354 = Faktor 6
    GradSekunden = Sekunden * 6; 

    // Minuten+Sekunden in Relation zu 3600 setzen
    // 60 / 3600 = 0.01666667         
    GradMinuten = Minuten * 6 + GradSekunden * 0.01666667; 

    // 30 / 3600 = 0.0833333
    // Stunden+Minuten in Relation zu 360 setzen
    // 0-11 -> 0-360 
    GradStunden = Stunden * 30 + GradMinuten * 0.0833333;  // 0-11 -> 0-360 
    StundePosX = cos((GradStunden - 90) * DEG_TO_RAD);
    StundePosY = sin((GradStunden - 90) * DEG_TO_RAD);

    MinutePosX = cos((GradMinuten - 90) * DEG_TO_RAD) ;
    MinutePosY = sin((GradMinuten - 90) * DEG_TO_RAD);

    SekundePosX = cos((GradSekunden - 90) * DEG_TO_RAD);
    SekundePosY = sin((GradSekunden - 90) * DEG_TO_RAD);

    // nach jeder Minute Minuten-/Stundenzeiger löschen
    // oder einmalig beim Start der Anzeige
    if (Sekunden == 0 || Start) 
    {
      // Datum erneuern wenn es korrekt ist (!= 1970)
      if (Zeit.tm_year + 1900 != 1970 && DatumAnzeigen)
      {
        ZeigeDatum();
      }
      
      Start = false;
      tft.drawLine(StundenZeigerX, StundenZeigerY, MitteHoehe, MitteHoehe + 1, Kreisfarbe);  

      // 62 Pixel -> Länge des Stundenzeigers
      // Mittelpunkt + 1 -> Mittelpunkt soll nicht gelöscht werden
      StundenZeigerX = StundePosX * 62 + MitteHoehe + 1;
      StundenZeigerY = StundePosY * 62 + MitteHoehe + 1;
      tft.drawLine(MinutenZeigerX, MinutenZeigerY, MitteHoehe, MitteHoehe + 1, Kreisfarbe);

      // 84 Pixel -> Länge des Minutenzeigers
      // Mittelpunkt + 1 -> Mittelpunkt soll nicht gelöscht werden
      MinutenZeigerX = MinutePosX * 84 + MitteHoehe;
      MinutenZeigerY = MinutePosY * 84 + MitteHoehe + 1;
    }
    
        // Kreis am Sekundenzeiger löschen, Radius 5
    tft.fillCircle(SekundenZeigerX, SekundenZeigerY, 5, Kreisfarbe);

    // 85 Pixel -> Länge des Sekundenzeigers
    SekundenZeigerX = SekundePosX * 85 + MitteHoehe + 1;
    SekundenZeigerY = SekundePosY * 85 + MitteHoehe + 1;

    // Zeiger neu zeichnen
    // Sekunden Linie nur anzeigen wenn SekundenzeigerKreis false
    if (!SekundenzeigerKreis) tft.drawLine(SekundenZeigerX, SekundenZeigerY, MitteHoehe, MitteHoehe + 1, ROT);

    // Minuten
    tft.drawLine(MinutenZeigerX, MinutenZeigerY, MitteHoehe, MitteHoehe + 1, Zeigerfarbe);

    // Stunden
    tft.drawLine(StundenZeigerX, StundenZeigerY, MitteHoehe, MitteHoehe + 1, Zeigerfarbe);

    // Kreis an der Spitze des Sekundenzeigers, Radius 5
    tft.fillCircle(SekundenZeigerX, SekundenZeigerY, 5, ROT);

    // Mittelpunkt zeichnen
    tft.fillCircle(MitteHoehe, MitteHoehe + 1, 3, Zeigerfarbe); 
  }
}

void ZeigeDatum()
{
  u8g2Schriften.setFont(u8g2_font_helvB14_tf);    
  u8g2Schriften.setCursor(75, 180);
  u8g2Schriften.setForegroundColor(GRUEN);
      
  // Bildschirmbereich für das Datum löschen
  tft.fillRect(75, 160, 125, 25, Kreisfarbe);
  if (Zeit.tm_mday < 10) u8g2Schriften.print("0");
  u8g2Schriften.print(Zeit.tm_mday);
  u8g2Schriften.print(".");

  // Monat: führende 0 ergänzen
  if (Zeit.tm_mon < 9) u8g2Schriften.print("0");
    
  // Zählung beginnt mit 0 -> +1
  u8g2Schriften.print(Zeit.tm_mon + 1);
  u8g2Schriften.print(".");

  // Anzahl Jahre seit 1900
  u8g2Schriften.print(Zeit.tm_year + 1900);
}

void TemperaturAnzeigen()
{
  // Temperatur lesen 
  String Temperatur = String(dht.readTemperature());

  // replace -> . durch , ersetzen
  Temperatur.replace(".", ",");

  // Luftfeuchtigkeit lesen 
  String Luftfeuchtigkeit = String(dht.readHumidity());

  // replace -> . durch , ersetzen
  Luftfeuchtigkeit.replace(".", ",");

  tft.fillRect(10, 250, 125, 70, SCHWARZ);
  u8g2Schriften.setForegroundColor(BLAU);   
  u8g2Schriften.setBackgroundColor(SCHWARZ);
  u8g2Schriften.setCursor(10, 275);
  u8g2Schriften.setFont(u8g2_font_helvB24_tf);   
  u8g2Schriften.print(Luftfeuchtigkeit + " %");

  u8g2Schriften.setCursor(10, 310);
  u8g2Schriften.setForegroundColor(ROT);
  u8g2Schriften.print(Temperatur + " °C");
}

Quel­len


Letzte Aktualisierung: Mai 14, 2025 @ 20:38