ESP32 Radio

Pro­gramm mit zwei Tastern

#include "Arduino.h"
#include "WiFi.h"
#include "VS1053.h" 
#include "ESP32_VS1053_Stream.h"
#include "LCDIC2.h"

// 4-zeiliges LCD
LCDIC2 lcd(0x27, 20, 4);

#include "OneButton.h"

#define VS1053_CS 5
#define VS1053_DCS 16
#define VS1053_DREQ 4

// Pins Taster
int TasterLautstaerke = 12;
int TasterSender = 14;

OneButton SenderWahl(TasterSender, true);
OneButton LautstaerkeEinstellen(TasterLautstaerke, true);

// Variablen Sender
int SenderIndex = 0;
int AnzahlSender = 0;

int Lautstaerke = 80;
int GesicherteLautstaerke = Lautstaerke;

ESP32_VS1053_Stream stream;

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

const char* Sender[] = 
{
  "http://wdr-1live-live.icecast.wdr.de/wdr/1live/live/mp3/128/stream.mp3",  // 1Live
  "http://wdr-wdr2-bergischesland.icecast.wdr.de/wdr/wdr2/bergischesland/mp3/128/stream.mp3", // WDR2
  "http://wdr-wdr4-live.icecast.wdr.de/wdr/wdr4/live/mp3/128/stream.mp3", // WDR4 
  "http://liveradio.swr.de/sw282p3/swr3/play.mp3", // SWR3
  "http://dispatcher.rndfnk.com/swr/swr4/ko/mp3/128/stream.mp3", // SWR4
  "http://avw.mdr.de/streams/284321-1_mp3_high.m3u", // MDR JUMP Rock channel
  "http://dispatcher.rndfnk.com/hr/hr1/rheinmain/high", // HR1
  "http://www.ndr.de/resources/metadaten/audio/m3u/ndr2_hh.m3u", // NDR Hamburg
  "http://dispatcher.rndfnk.com/rbb/rbb888/live/mp3/mid", // RBB 88,8
  "http://liveradio.sr.de/sr/sr3/mp3/128/stream.mp3", // SR 3
  "http://icecast.ndr.de/ndr/njoy/live/mp3/128/stream.mp3", // N-Joy
  "http://st01.sslstream.dlf.de/dlf/01/128/mp3/stream.mp3?aggregator=web", // Deutschlandfunk
  "http://stream.lokalradio.nrw/444z6rq", // Radio Berg
  "http://orf-live.ors-shoutcast.at/oe3-q2a", // Ö3
  "http://antennebrandenburg.de/livemp3", // Antenne Brandenburg
  "http://stream.antenne.de/antenne/stream/mp3", // Antenne Bayern live
  "http://stream.antenne.de/antenne-bayern-70er-rock/stream/mp3", // Antenne Bayern 70er Rock
  "http://stream.antenne.de/classic-rock-live/stream/mp3", // Antenne Bayern Classic Rock
  "http://stream.antenne.de/antenne-bayern-80er-rock/stream/mp3", // Antenne Bayern 80er Rock
  "http://classicrock.radioarabella.de/arabella-classicrock.mp3", // Radio Arabella
  "http://www.charivari.de/webradio/r8082.m3u", // Radio Charivari München
};

const char *Beschreibung[]
{
  "1Live", "WDR 2", "WDR 4", "SWR 3", "SWR 4", "MDR JUMP", "HR 1", "NDR 2", "RBB 88,8", 
  "SR 3", "N-Joy", "Deutschlandfunk","Radio Berg", "\xEF 3", "Antenne Brandenburg", "Antenne Bayern live", 
  "Antenme Bayern 70er", "Antenne Bayern Rock", "Antenne Bayern 80er", 
  "Radio Arabella", "Radio Charivari"
};

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

  // LCD starten
  lcd.begin();

  // Cursor "verstecken"
  lcd.setCursor(false);

  /*
    Aktionen dem Modus der Tasters zuordnen
    setPressTicks(500);
    setClickTicks(200);
    setDebounceTicks(50);
  */
  SenderWahl.attachClick(SenderVor);
  SenderWahl.attachDoubleClick(SenderZurueck);
  SenderWahl.attachLongPressStop(ErsterSender);

  LautstaerkeEinstellen.attachClick(Leiser);
  LautstaerkeEinstellen.attachDoubleClick(Lauter);
  LautstaerkeEinstellen.attachLongPressStop(TonAus);

  // pinModes definieren
  pinMode(TasterSender, INPUT_PULLUP);
  pinMode(TasterLautstaerke, INPUT_PULLUP);

  // auf Seriellen Monitor warten
  while (!Serial)
  {
    delay(10);
  }

  // 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(WiFi.SSID());
  Serial.print("IP über DHCP: ");
  Serial.println(WiFi.localIP());

  // Start SPI bus
  SPI.setHwCs(true);
  SPI.begin();

  // Decoder starten
  if (!stream.startDecoder(VS1053_CS, VS1053_DCS, VS1053_DREQ) || !stream.isChipConnected()) 
  {
    Serial.println("Decoder konnte nicht gestartet werden ..");
    Serial.println("Programm angehalten!");
    while (1);
  }

  Serial.println("MP3-Decoder gestartet ...");

  // Sender verbinden
  stream.connecttohost(Sender[SenderIndex]);

  // wenn der Stream nicht mehr läuft ...
  if (!stream.isRunning()) 
  {
    Serial.println("Radio wird neu gestartet ...");
    stream.stopSong();
    stream.connecttohost(Sender[SenderIndex]);
  }

  Serial.print("Codec: ");
  Serial.println(stream.currentCodec());

  Serial.print("Bitrate: ");
  Serial.print(stream.bitrate());
  Serial.println(" kbps");
  stream.setVolume(Lautstaerke);

  // Anzahl der Sender im Array feststellen
  AnzahlSender = sizeof(Sender) / sizeof(Sender[0]);
  Serial.println("Anzahl der Sender:" + String(AnzahlSender));
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(Beschreibung[SenderIndex]);
  lcd.setCursor(0, 1);
  lcd.print("Lautst\xe1rke: " + String(Lautstaerke) + "  ");
}

void loop() 
{
  SenderWahl.tick();
  delay(10);
  LautstaerkeEinstellen.tick();
  delay(10);

  // wenn Stream gestoppt -> neu verbinden
  if (!stream.isRunning()) 
  {
    // stream.stopSong();
    stream.connecttohost(Sender[SenderIndex]);
  }

  // Stream abspielen
  stream.loop();
  delay(5);
}

// Sender im Seriellen Monitor anzeigen
void audio_showstation(const char* info) 
{
  Serial.printf("Station: %s\n", info);
}

// Titel anzeigen
void audio_showstreamtitle(const char* info) 
{
  String Titel = String(info);
  Titel.replace(" - ", " ");
  Titel.replace(" / ", " ");
  Titel.replace(" von ", " ");
  if (Titel.length() > 20) Titel = Titel.substring(0, 20);
  lcd.setCursor(0,2);
  lcd.print(Titel);
  Serial.printf("Titel: %s\n", info);
}

void audio_eof_stream(const char* info) 
{
  Serial.printf("Ende: %s\n", info);
}

void SenderVor()
{
  // wenn der letzte Sender -> zurück auf 0
  if (SenderIndex >= AnzahlSender - 1) SenderIndex = 0;
  else SenderIndex++;
  Serial.println(SenderIndex);
  stream.stopSong();
  stream.connecttohost(Sender[SenderIndex]);
  
  // Sender/Lautstärke auf dem LCD anzeigen
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(Beschreibung[SenderIndex]);
  lcd.setCursor(0, 1);
  lcd.print("Lautst\xe1rke: " + String(Lautstaerke) + "  ");
}

void SenderZurueck()
{
  // wenn der letzte Sender -> zurück auf 0
  if (SenderIndex == 0) SenderIndex = AnzahlSender - 1;
  else SenderIndex--;
  Serial.println(SenderIndex);
  stream.stopSong();
  stream.connecttohost(Sender[SenderIndex]);
 
  // Sender/Lautstärke auf dem LCD anzeigen
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(Beschreibung[SenderIndex]);
  lcd.setCursor(0, 1);
  lcd.print("Lautst\xe1rke: " + String(Lautstaerke) + "  ");
}

void Leiser()
{
  if (Lautstaerke > 5) Lautstaerke -= 5;
  // if (Lautstaerke == 0) Lautstaerke += 5;
  GesicherteLautstaerke = Lautstaerke;
  stream.setVolume(Lautstaerke);
  Serial.println("Lautstärke: " + String(Lautstaerke));
  lcd.setCursor(0, 1);
  lcd.print("Lautst\xe1rke: " + String(Lautstaerke) + "  ");
}

void Lauter()
{
  if (Lautstaerke < 95) Lautstaerke += 5;
  GesicherteLautstaerke = Lautstaerke;
  stream.setVolume(Lautstaerke);
  Serial.println("Lautstärke: " + String(Lautstaerke));
  lcd.setCursor(0, 1);
  lcd.print("Lautst\xe1rke: " + String(Lautstaerke) + "  ");
}

void TonAus()
{
  if (Lautstaerke == 0) 
  {
    stream.setVolume(GesicherteLautstaerke);
    lcd.setCursor(0, 1);
    lcd.print("Ton ein         ");
    Lautstaerke = GesicherteLautstaerke;
  }
  else
  {
    Lautstaerke = 0;
    stream.setVolume(Lautstaerke);
    Serial.println("Lautstärke: " + String(Lautstaerke));
    lcd.setCursor(0, 1);
    lcd.print("Ton aus         ");
  }
}

void ErsterSender()
{
  SenderIndex = 0;
  Serial.println(SenderIndex);
  stream.stopSong();
  stream.connecttohost(Sender[SenderIndex]);
 
  // Sender/Lautstärke auf dem LCD anzeigen
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(Beschreibung[SenderIndex]);
  lcd.setCursor(0, 1);
  lcd.print("Lautst\xe1rke: " + String(Lautstaerke) + "  ");
}

Pro­gramm mit drei Tastern

lau­ter - lei­ser - Senderwahl 

Sen­sor SCD4x: Tem­pe­ra­tur, Luft­feuch­tig­keit und CO2 messen

Selbst­test

#include "Arduino.h"
#include "SensirionI2cScd4x.h"
#include "Wire.h"

SensirionI2cScd4x sensor;

float TemperaturAbweichung;
uint32_t LuftdruckAnpassung;
uint16_t HoeheAnpassung;
uint16_t ASCaktiviert;
uint16_t ASCZiel;
uint16_t KalibrierungInitialPeriode;
uint16_t KalibrierungStandardPeriode;
uint16_t sensorStatus;

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

  // I2C
  Wire.begin();
  sensor.begin(Wire, SCD41_I2C_ADDR_62);

  // R4 WiFi mit QWIIC-Anschluss
  // Wire1.begin();
  // sensor.begin(Wire1, SCD41_I2C_ADDR_62);
  
  delay(30);

  sensor.wakeUp();
  sensor.stopPeriodicMeasurement();
  sensor.reinit();

  sensor.getTemperatureOffset(TemperaturAbweichung);
  Serial.print(F("Temperatur Anpassung °C: "));
  Serial.println(TemperaturAbweichung);

  sensor.getAmbientPressure(LuftdruckAnpassung);
  Serial.print(F("Luftdruck Anpassung in Pa: "));
  Serial.println(LuftdruckAnpassung);

  sensor.getSensorAltitude(HoeheAnpassung);
  Serial.print(F("Anpassung Höhe in m: "));
  Serial.println(HoeheAnpassung);
  Serial.println();

  Serial.println(F("Automatische Selbstkalibrierung (ASC):"));
  sensor.getAutomaticSelfCalibrationEnabled(ASCaktiviert);
  if (ASCaktiviert) 
  {
    Serial.println(F("aktiviert"));
  } 
  else Serial.println(F("nicht aktiviert"));

  sensor.getAutomaticSelfCalibrationTarget(ASCZiel);
  Serial.print(F(" - Ziel für die automatische Kalibrierung in ppm: "));
  Serial.println(ASCZiel);

  sensor.getAutomaticSelfCalibrationInitialPeriod(KalibrierungInitialPeriode);
  Serial.print(F(" - Periode für die Initielisierung in Stunden: "));
  Serial.println(KalibrierungInitialPeriode);

  sensor.getAutomaticSelfCalibrationStandardPeriod(KalibrierungStandardPeriode);
  Serial.print(F(" - Standard-Periode in Stunden: "));
  Serial.println(KalibrierungStandardPeriode);
  Serial.println();

  Serial.print(F("Selbsttest durchführen ... "));
  sensor.performSelfTest(sensorStatus);

  if(sensorStatus == 0) Serial.println("Der Sensor funktioniert einwandfrei!");
  else 
  {
    Serial.println("Fehler beim Test des Sensors!");
    while(1);
  }
}

void loop() 
{
  // bleibt leer
}

Peri­odi­sche Messung

LCD

#include "Arduino.h"
#include "SensirionI2cScd4x.h"
#include "Wire.h"
#include "LCDIC2.h"

// 4-zeiliges LCD
LCDIC2 lcd(0x27, 20, 4);

uint16_t sensorStatus = 1;

SensirionI2cScd4x sensor;

void setup() 
{
  // LCD starten
  lcd.begin();

  // Cursor "verstecken"
  lcd.setCursor(false);

  // auf Seriellen Monitor warten
  Serial.begin(9600);
  while (!Serial) 
  {
    delay(200);
  }

  // I2C
  Wire.begin();
  sensor.begin(Wire, SCD41_I2C_ADDR_62);

  // auf Werkseinstellungen zurücksetzen
  // sensor.performFactoryReset();

  delay(30);

  // Sensor aufwecken
  sensor.wakeUp();

  // periodische Messung stoppen
  sensor.stopPeriodicMeasurement();

  // Vor­ein­stel­lun­gen aus dem EEPROM lesen
  sensor.reinit();
  
  sensor.performSelfTest(sensorStatus);

  if(sensorStatus == 0) Serial.println("Der Sensor funktioniert einwandfrei!");
  else 
  {
    Serial.println("Fehler beim Test des Sensors!");
    while(1);
  }

  // Höhe des Standorts in m
  sensor.setSensorAltitude(80);

  // Temperaturschwankung berücksichtigen
  sensor.setTemperatureOffset(2.0);

  // Mittelwert des Luftdrucks hPa *100
  // nur sinnvoll, wenn ein präzises Messgerät verfügbar ist
  // sensor.setAmbientPressure(100400);;

  // Periodic: alle 5 Sekunden messen
  // auskommentieren bei SingleShot
  sensor.startPeriodicMeasurement();
}

void loop() 
{
  bool SensorBereit = false;
  uint16_t CO2 = 0;
  float Temperatur = 0.0;
  float Luftfeuchtigkeit = 0.0;

  sensor.getDataReadyStatus(SensorBereit);

  // wenn der Sensor bereit ist -> Messung durchführen
  if (SensorBereit) 
  {  
    // periodische Messung
    sensor.readMeasurement(CO2, Temperatur, Luftfeuchtigkeit);

    String AnzeigeTemperatur = String(Temperatur);
    String AnzeigeLuftfeuchtigkeit = String(Luftfeuchtigkeit);

    AnzeigeTemperatur.replace(".", ",");
    AnzeigeLuftfeuchtigkeit.replace(".", ",");

    // Anzeige Serieller Monitor
    Serial.print("CO2 Konzentration: ");
    Serial.print(CO2);
    Serial.println(" ppm");
    Serial.print("Temperatur: ");
    Serial.print(AnzeigeTemperatur);
    Serial.println("°C");
    Serial.print("Luftfeuchtigkeit: ");
    Serial.print(AnzeigeLuftfeuchtigkeit);
    Serial.println("%");
    Serial.println("------------------------");

    // Anzeige LCD
    lcd.setCursor(0, 0);
    lcd.print("Temperatur: ");
    lcd.print(AnzeigeTemperatur);
    lcd.print("\337C ");

    lcd.setCursor(0, 1);
    lcd.print("Luftfeuchtigkeit: ");
    lcd.setCursor(0, 2);
    lcd.print(AnzeigeLuftfeuchtigkeit);
    lcd.print("% ");

    lcd.setCursor(0, 3);
    lcd.print("CO2: ");
    lcd.print(String(CO2));
    lcd.print(" ppm ");
  }
}

OLED

#include "Arduino.h"
#include "SensirionI2cScd4x.h"
#include "Wire.h"
#include "U8g2lib.h"

// 0,96 Zoll SSD1306
U8G2_SSD1306_128X64_NONAME_1_HW_I2C oled(U8G2_R0);

// 2,08 Zoll SH122
// U8G2_SH1122_256X64_1_HW_I2C oled(U8G2_R0);

uint16_t sensorStatus = 1;

SensirionI2cScd4x sensor;

void setup() 
{
  oled.begin();

  // Schriftart OLED 2,08
  oled.setFont(u8g2_font_helvB14_tf);

  Serial.begin(9600);
  while (!Serial) 
  {
    delay(200);
  }

  Wire.begin();
  sensor.begin(Wire, SCD41_I2C_ADDR_62);

  // auf Werkseinstellungen zurücksetzen
  // sensor.performFactoryReset();

  delay(30);

  // Sensor aufwecken
  sensor.wakeUp();

  // periodische Messung stoppen
  sensor.stopPeriodicMeasurement();

  // Vor­ein­stel­lun­gen aus dem EEPROM lesen
  sensor.reinit();
  
  sensor.performSelfTest(sensorStatus);

  if(sensorStatus == 0) Serial.println("Der Sensor funktioniert einwandfrei!");
  else 
  {
    Serial.println("Fehler beim Test des Sensors!");
    while(1);
  }

  // Höhe des Standorts in m
  sensor.setSensorAltitude(80);

  // Temperaturschwankung berücksichtigen
  sensor.setTemperatureOffset(0.5);
  
  // Periodic: alle 5 Sekunden messen
  // auskommentieren bei SingleShot
  sensor.startPeriodicMeasurement();

  // LowPower: alle 30 Sekunden messen
  // sensor.startLowPowerPeriodicMeasurement();
}

void loop() 
{
  bool SensorBereit = false;
  uint16_t CO2 = 0;
  float Temperatur = 0.0;
  float Luftfeuchtigkeit = 0.0;

  sensor.getDataReadyStatus(SensorBereit);

  // wenn der Sensor bereit ist -> Messung durchführen
  if (SensorBereit) 
  {  
    // periodische Messung
    sensor.readMeasurement(CO2, Temperatur, Luftfeuchtigkeit);

    String AnzeigeTemperatur = String(Temperatur);
    String AnzeigeLuftfeuchtigkeit = String(Luftfeuchtigkeit);

    AnzeigeTemperatur.replace(".", ",");
    AnzeigeLuftfeuchtigkeit.replace(".", ",");

    // Anzeige Serieller Monitor
    Serial.print("CO2 Konzentration: ");
    Serial.print(CO2);
    Serial.println(" ppm");
    Serial.print("Temperatur: ");
    Serial.print(AnzeigeTemperatur);
    Serial.println("°C");
    Serial.print("Luftfeuchtigkeit: ");
    Serial.print(AnzeigeLuftfeuchtigkeit);
    Serial.println("%");
    Serial.println("------------------------");

    oled.clearDisplay();
    do 
    {
      oled.setCursor(5, 14);
    
      // OLED 2,08
      // oled.print("Temperatur: ");
      oled.print(AnzeigeTemperatur);

      // Grad-Zeichen
      oled.print((char)176);
      oled.print("C");

      oled.setCursor(5, 34);
    
      // OLED 2,08
      // oled.print("Luftfeuchtigkeit: ");
      oled.print(AnzeigeLuftfeuchtigkeit);
      oled.print("%");

      oled.setCursor(5, 56);
    
      // OLED 2,08
      // oled.print("CO2: ");
      oled.print(String(CO2));
      oled.print(" ppm");
    } 
    while (oled.nextPage());
  }
}

TFT mit ESP32

Beach­te die ⇒SPI-Pins der Mikrocontroller.

ESP-NOW Daten übertragen

MAC-Adres­se feststellen

#include "WiFi.h"

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

  WiFi.mode(WIFI_STA);

  Serial.print("MAC-Adresse: ");

  // MAC-Adresse ermitteln
  String MACAdresse = WiFi.macAddress();
  Serial.println(MACAdresse);

  String FormatierteMACAdresse;
  Serial.print("Formatierte MAC-Adresse: ");

  int index = 0;
  
  // MAC-Adresse besteht aus 6 durch : getrennten Elementen
  for (int i = 0; i < 6; i++) 
  {
    // index: Abstand zum nächsten Wert 2 Ziffern + :
    FormatierteMACAdresse += "0x" + MACAdresse.substring(index, index + 3);
    index += 3;
  }

  FormatierteMACAdresse.replace(":", ", ");
  Serial.println("{" + FormatierteMACAdresse + "}");
}

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

Text­nach­richt senden

Sen­der

#include "esp_now.h"
#include "WiFi.h"

// MAC-Adresse des Empfängers -> muss angepasst werden
uint8_t EmpfaengerAdresse[] = {0x10, 0xB4, 0x1D, 0x14, 0x72, 0x00};

// enthält die Information über den ESP mit dem kommuniziert werden soll
esp_now_peer_info_t EmpfangerInfo;

void NachrichtGesendet(const uint8_t *EmpfaengerAdresse, esp_now_send_status_t Status) 
{
  if(Status == ESP_NOW_SEND_SUCCESS) Serial.println("Nachricht gesendet");
}

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

  // Stations-Modus
  WiFi.mode(WIFI_STA);

  // ESP-NOW initialisieren
  if (esp_now_init() != ESP_OK) 
  {
    Serial.println("ESP-NOW konnte nicht gestartet werden!");
    return;
  } 
  else Serial.println("ESP_NOW erfolgreich initialisiert! ");

  /*
    Informationen zum ESP hinzufügen (esp_now_peer_info_t)
    peer_address -> MAC-Adresse
    channel -> Kanal der Verbindung (0-13)
    encrypt = false -> keine Verschlüsselung
  */
  // MAC-Adresse des ESPs nach peer_addr kopieren
  memcpy(EmpfangerInfo.peer_addr, EmpfaengerAdresse, 6);
  EmpfangerInfo.channel = 0;
  EmpfangerInfo.encrypt = false;

  if (esp_now_add_peer(&EmpfangerInfo) != ESP_OK) 
  {
    Serial.println("Empfänger konnte nicht hinzugefügt werden!");
    return;
  }

  // anzeigen, ob Nachricht erfolgreich gesendet wurde
  esp_now_register_send_cb((esp_now_send_cb_t) NachrichtGesendet);   
}

void loop() 
{
  int Zahl = random(1, 1000);

  // Zahl in char-Array umwandeln
  String Zufallszahl = String(Zahl);
  Serial.println(Zufallszahl);

  char Daten[Zufallszahl.length() + 1];
  Zufallszahl.toCharArray(Daten, Zufallszahl.length() + 1);

  // Nachricht an Empfänger senden
  esp_err_t Fehler = esp_now_send(EmpfaengerAdresse, (uint8_t *)&Daten, sizeof(Daten) - 1);
  if (Fehler != ESP_OK) Serial.println("Fehler beim Senden an Empfänger ");
  else Serial.println("Nachricht gesendet!");
  delay(5000);
}

Emp­fän­ger

#include "esp_now.h"
#include "WiFi.h"

/*
  Funktion DatenEmpfangen 
  Parameter: 
  MACAdresse
  empfangeneDaten
  LaengeDaten
*/
void DatenEmpfangen(const uint8_t * MACAdresse, const uint8_t * empfangeneDaten, int LaengeDaten) 
{
  Serial.println("Nachricht vom Sender ...");
  Serial.print("Zufallszahl: ");
  for(int i = 0; i < LaengeDaten; i++)
  {
    Serial.print((char)empfangeneDaten[i]);
  }
  Serial.println();

  Serial.println("------------------------");
}
 
void setup() 
{
  Serial.begin(9600);
  
  // WiFi im Stations-Modus starten
  WiFi.mode(WIFI_STA);

  // ESP-NOW initialisieren
  if (esp_now_init() != ESP_OK) 
  {
    Serial.println("ESP-NOW konnte nicht gestartet werden!");
    return;
  } 
  else Serial.println("ESP_NOW erfolgreich initialisiert! ");
  
  // Funktion DatenEmpfangen mit Rückgabewert registrieren 
  esp_now_register_recv_cb(esp_now_recv_cb_t(DatenEmpfangen));
}
 
void loop() 
{
  // bleibt leer, Programm reagiert nur auf die Funktion DatenEmpfangen
}

Mess­da­ten DHT20 an zwei Emp­fän­ger senden

Sen­der

#include "DHT20.h"

DHT20 dht;

#include "esp_now.h"
#include "WiFi.h"

// MAC-Adressen der Empfänger
uint8_t EmpfangerAdresse[2][6] = 
{
  { 0xEC, 0xDA, 0x3B, 0xBD, 0x2F, 0x14 },
  { 0x10, 0xB4, 0x1D, 0x14, 0x72, 0x00 }
};

// Datenstruktur
// muss mit allen Empfängern übereinstimmen
struct Daten_Struktur 
{
  float Temperatur;
  float Luftfeuchtigkeit; 
};

// Daten: Array mit 2 Elementen
Daten_Struktur Daten[2];

// enthält die Information über die ESPs mit denen kommuniziert werden soll
esp_now_peer_info_t EmpfangerInfo[2];

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

  // Sensor starten
  Wire.begin();
  dht.begin();

  // Stations-Modus
  WiFi.mode(WIFI_STA);

  // ESP-NOW initialisieren
  if (esp_now_init() != ESP_OK) 
  {
    Serial.println("ESP-NOW konnte nicht gestartet werden!");
    return;
  } 
  else Serial.println("ESP_NOW erfolgreich initialisiert! ");

  /*
    Informationen zu den ESPs hinzufügen (esp_now_peer_info_t)
    peer_address -> MAC-Adresse
    channel -> Kanal der Verbindung (0-13)
    encrypt = false -> keine Verschlüsselung
    Durchlauf für alle mit MAC-Adresse definierten ESPs
  */
  for (int i = 0; i < 2; i++) 
  {
    // MAC-Adresse des jeweiligen ESPs nach peer_addr kopieren
    memcpy(EmpfangerInfo[i].peer_addr, EmpfangerAdresse[i], 6);
    EmpfangerInfo[i].channel = 0;
    EmpfangerInfo[i].encrypt = false;

    // konnte die MAC-Adresse zugeordnet werden
    if (esp_now_add_peer(&EmpfangerInfo[i]) != ESP_OK) 
    {
      Serial.println("Empfänger konnte nicht hinzugefügt werden!");
      return;
    }
  } 
}

void loop() 
{
  // Daten DHT20 lesen
  dht.read();

  // Daten des DHT den Elementen des Arrays zuordnen
  Daten[0].Temperatur = dht.getTemperature();
  Daten[0].Luftfeuchtigkeit = dht.getHumidity();
  Daten[1].Temperatur = dht.getTemperature();
  Daten[1].Luftfeuchtigkeit = dht.getHumidity();

  // Nachricht an 2 Empfänger senden
  for(int i = 0; i < 2; i++)
  {
    // Daten senden und Fehlercode abfragen
    esp_err_t Fehler = esp_now_send(EmpfangerAdresse[i], (uint8_t *) &Daten[i], sizeof(Daten[i]));
    if (Fehler != ESP_OK) 
    {
      Serial.print("Fehler beim Senden an Empfänger ");
      Serial.println(i);
    }
  }
  delay(5000);
}

Emp­fän­ger LCD

#include "esp_now.h"
#include "WiFi.h"

#include "LCDIC2.h"

// 4-zeiliges LCD
LCDIC2 lcd(0x27, 20, 4);

// muss mit der Struktur beim Sender übereinstimmen
struct Daten_Struktur 
{
    float Temperatur;
    float Luftfeuchtigkeit; 
};

// Name für die definierte struct
Daten_Struktur Daten;

/*
  Funktion DatenEmpfangen 
  Parameter: 
  MACAdresse
  empfangeneDaten
  LaengeDaten
*/
void DatenEmpfangen(const uint8_t * MACAdresse, const uint8_t * empfangeneDaten, int LaengeDaten) 
{
  // struct Daten nach empfangeneDaten kopieren
  memcpy(&Daten, empfangeneDaten, sizeof(Daten));

  Serial.print("Temperatur: ");
  String Temperatur = String(Daten.Temperatur);
  Temperatur.replace(".", ",");
  Serial.println(Temperatur +"°C");

  String Luftfeuchtigkeit = String(Daten.Luftfeuchtigkeit);
  Luftfeuchtigkeit.replace(".", ",");
  Serial.print("Luftfeuchtigkeit: ");
  Serial.println(Luftfeuchtigkeit + "%");
  Serial.println("------------------------");

  lcd.setCursor(0, 0);
  lcd.print("Temperatur: ");
  lcd.setCursor(0, 1);
  lcd.print(Temperatur);
  lcd.print("\337C");

  lcd.setCursor(0, 2);
  lcd.print("Luftfeuchtigkeit: ");
  lcd.setCursor(0, 3);
  lcd.print(Luftfeuchtigkeit);
  lcd.print("%");
}
 
void setup() 
{
  // LCD starten
  lcd.begin();

  // Cursor "verstecken"
  lcd.setCursor(false);

  Serial.begin(9600);
  
  // WiFi im Stations-Modus starten
  WiFi.mode(WIFI_STA);

  // ESP-NOW initialisieren
  if (esp_now_init() != ESP_OK) 
  {
    Serial.println("ESP-NOW konnte nicht gestartet werden!");
    return;
  } 
  else Serial.println("ESP_NOW erfolgreich initialisiert! ");
  
  // Funktion DatenEmpfangen mit Rückgabewert registrieren 
  esp_now_register_recv_cb((esp_now_recv_cb_t) DatenEmpfangen);
}
 
void loop() 
{
  // bleibt leer, Programm reagiert nur auf die Funktion DatenEmpfangen
}

Emp­fän­ger OLED

#include "esp_now.h"
#include "WiFi.h"

#include "U8g2lib.h"

/*
  Typbezeichnung mit Bildschirmgröße in Pixeln
  F = full screen buffer mode 
  Hardware I2C
  Name des OLEDs
  Rotation R0 (keine)
*/
U8G2_SSD1306_128X64_NONAME_F_HW_I2C oled(U8G2_R0);

// muss mit der Struktur beim Sender übereinstimmen
struct Daten_Struktur 
{
    float Temperatur;  
    float Luftfeuchtigkeit; 
};

// Name für die definierte struct
Daten_Struktur Daten;

/*
  Funktion DatenEmpfangen 
  Parameter: 
  MACAdresse
  empfangeneDaten
  LaengeDaten
*/
void DatenEmpfangen(const uint8_t *MACAdresse, const uint8_t *empfangeneDaten, int LaengeDaten) 
{
  // struct Daten nach empfangeneDaten kopieren
  memcpy(&Daten, empfangeneDaten, sizeof(Daten));

  Serial.print("Temperatur: ");
  String Temperatur = String(Daten.Temperatur);
  Temperatur.replace(".", ",");
  Serial.println(Temperatur +"°C");

  String Luftfeuchtigkeit = String(Daten.Luftfeuchtigkeit);
  Luftfeuchtigkeit.replace(".", ",");
  Serial.print("Luftfeuchtigkeit: ");
  Serial.println(Luftfeuchtigkeit + "%");
  Serial.println("------------------------");

  oled.setCursor(1, 15);
  oled.print("Temperatur: ");

  oled.setCursor(1, 30);
  oled.print(Temperatur);
  oled.print((char)176);
  oled.print("C");
  oled.setCursor(1, 45);
  oled.print("Luftfeuchtigkeit: ");
  oled.setCursor(1, 60);
  oled.print(Luftfeuchtigkeit);
  oled.print("%");
  oled.sendBuffer();
  oled.clearBuffer();
}
 
void setup() 
{
  oled.begin();

  // Schriftart
  oled.setFont(u8g2_font_helvB12_tf);

  Serial.begin(9600);
  
  // WiFi im Stations-Modus starten
  WiFi.mode(WIFI_STA);

  // ESP-NOW initialisieren
  if (esp_now_init() != ESP_OK) 
  {
    Serial.println("ESP-NOW konnte nicht gestartet werden!");
    return;
  } 
  else Serial.println("ESP_NOW erfolgreich initialisiert! ");
  
  // Funktion DatenEmpfangen mit Rückgabewert registrieren 
  esp_now_register_recv_cb((esp_now_recv_cb_t) DatenEmpfangen);
}
 
void loop() 
{
  // bleibt leer, Programm reagiert nur auf die Funktion DatenEmpfangen
}

Mess­da­ten BME280 von zwei Sen­dern an Emp­fän­ger senden

Sen­der 0

#include "esp_now.h"
#include "WiFi.h"
#include "Adafruit_BME280.h"

#define MeeresHoehe (1013.25)

// Name des BME280
Adafruit_BME280 bme;

// MAC-Adresse des Empfängers -> muss angepasst werden
uint8_t EmpfaengerAdresse[] = { 0xEC, 0xDA, 0x3B, 0xBD, 0x2F, 0x14 };

// enthält die Information über den ESP mit dem kommuniziert werden soll
esp_now_peer_info_t EmpfangerInfo;

// ID -> Kennung des Controllers
// Temperatur/Luftfeuchtigkeit -> Daten des jeweiligen Sensors
struct Daten_Struktur 
{
  int ID;
  float Temperatur;
  float Luftfeuchtigkeit;
  float Luftdruck;
};

Daten_Struktur Nachricht;

void NachrichtGesendet(const uint8_t *EmpfaengerAdresse, esp_now_send_status_t Status) 
{
  if(Status == ESP_NOW_SEND_SUCCESS) Serial.println("Nachricht gesendet");
}

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

  // BME280 starten, bei Misserfolg Meldung anzeigen
  if (!bme.begin(0x77)) 
  {
    Serial.println("BME280 nicht verbunden");
    Serial.println("Verkabelung und/oder HEX-Adresse prüfen!");
    Serial.println("Start mit möglichen HEX-Adressen:");
    Serial.println("bme.begin(0x76);");
    Serial.println("bme.begin(0x77);");
    Serial.println("Programm wird beendet!");
    while (1);
  } 
  else Serial.println("BME280 erfolgreich gestartet!");

  WiFi.mode(WIFI_STA);

  // ESP-NOW initialisieren
  if (esp_now_init() != ESP_OK) 
  {
    Serial.println("ESP-NOW konnte nicht gestartet werden!");
    return;
  }

  // anzeigen, ob Nachricht erfolgreich gesendet wurde (cb = callback)
  esp_now_register_send_cb((esp_now_send_cb_t)NachrichtGesendet);

  /*
    Informationen zum ESP hinzufügen (esp_now_peer_info_t)
    peer_address -> MAC-Adresse
    channel -> Kanal der Verbindung (0-13)
    encrypt = false -> keine Verschlüsselung
  */
  // MAC-Adresse des ESPs nach peer_addr kopieren
  memcpy(EmpfangerInfo.peer_addr, EmpfaengerAdresse, 6);
  EmpfangerInfo.channel = 0;
  EmpfangerInfo.encrypt = false;

  // Empfänger hinzufügen
  if (esp_now_add_peer(&EmpfangerInfo) != ESP_OK) 
  {
    Serial.println("Empfänger konnte nicht hinzugefügt werden!");
    return;
  }
}

void loop() 
{
  // ID des Controllers
  Nachricht.ID = 0;

  // Daten lesen
  Nachricht.Temperatur = bme.readTemperature();
  Nachricht.Luftfeuchtigkeit = bme.readHumidity();
  Nachricht.Luftdruck = bme.readPressure() / 100.0;

  // Nachricht an Empfänger senden
  esp_err_t Fehler = esp_now_send(EmpfaengerAdresse, (uint8_t *)&Nachricht, sizeof(Nachricht));

  if (Fehler == ESP_OK) 
  {
    Serial.println("Nachricht erfolgreich gesendet!");
  } 
  else 
  {
    Serial.println("Fehler beim Senden der Nachricht!");
  }
  delay(5000);
}

Sen­der 1

#include "esp_now.h"
#include "WiFi.h"
#include "Adafruit_BME280.h"

#define MeeresHoehe (1013.25)

// Name des BME280
Adafruit_BME280 bme;

// MAC-Adresse des Empfängers -> muss angepasst werden
uint8_t EmpfaengerAdresse[] = { 0xEC, 0xDA, 0x3B, 0xBD, 0x2F, 0x14 };

// enthält die Information über den ESP mit dem kommuniziert werden soll
esp_now_peer_info_t EmpfangerInfo;

// ID -> Kennung des Controllers
// Temperatur/Luftfeuchtigkeit -> Daten des jeweiligen Sensors
struct Daten_Struktur 
{
  int ID;
  float Temperatur;
  float Luftfeuchtigkeit;
  float Luftdruck;
};

Daten_Struktur Nachricht;

void NachrichtGesendet(const uint8_t *EmpfaengerAdresse, esp_now_send_status_t Status) 
{
  if(Status == ESP_NOW_SEND_SUCCESS) Serial.println("Nachricht gesendet");
}

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

  // BME280 starten, bei Misserfolg Meldung anzeigen
  if (!bme.begin(0x76)) 
  {
    Serial.println("BME280 nicht verbunden");
    Serial.println("Verkabelung und/oder HEX-Adresse prüfen!");
    Serial.println("Start mit möglichen HEX-Adressen:");
    Serial.println("bme.begin(0x76);");
    Serial.println("bme.begin(0x77);");
    Serial.println("Programm wird beendet!");
    while (1);
  } 
  else Serial.println("BME280 erfolgreich gestartet!");

  WiFi.mode(WIFI_STA);

  // ESP-NOW initialisieren
  if (esp_now_init() != ESP_OK) 
  {
    Serial.println("ESP-NOW konnte nicht gestartet werden!");
    return;
  }

  // anzeigen, ob Nachricht erfolgreich gesendet wurde (cb = callback)
  esp_now_register_send_cb((esp_now_send_cb_t)NachrichtGesendet);

  /*
    Informationen zum ESP hinzufügen (esp_now_peer_info_t)
    peer_address -> MAC-Adresse
    channel -> Kanal der Verbindung (0-13)
    encrypt = false -> keine Verschlüsselung
  */
  // MAC-Adresse des ESPs nach peer_addr kopieren
  memcpy(EmpfangerInfo.peer_addr, EmpfaengerAdresse, 6);
  EmpfangerInfo.channel = 0;
  EmpfangerInfo.encrypt = false;

  // Empfänger hinzufügen
  if (esp_now_add_peer(&EmpfangerInfo) != ESP_OK) 
  {
    Serial.println("Empfänger konnte nicht hinzugefügt werden!");
    return;
  }
}

void loop() 
{
  // ID des Controllers
  Nachricht.ID = 1;

  // Daten lesen
  Nachricht.Temperatur = bme.readTemperature();
  Nachricht.Luftfeuchtigkeit = bme.readHumidity();
  Nachricht.Luftdruck = bme.readPressure() / 100.0;

  // Nachricht an Empfänger senden
  esp_err_t Fehler = esp_now_send(EmpfaengerAdresse, (uint8_t *)&Nachricht, sizeof(Nachricht));

  if (Fehler == ESP_OK) 
  {
    Serial.println("Nachricht erfolgreich gesendet!");
  } 
  else 
  {
    Serial.println("Fehler beim Senden der Nachricht!");
  }
  delay(5000);
}

Emp­fän­ger

#include "esp_now.h"
#include "WiFi.h"

#include "LCDIC2.h"

// 4-zeiliges LCD
LCDIC2 lcd(0x27, 20, 4);

struct Daten_Struktur 
{
  int ID;
  float Temperatur;
  float Luftfeuchtigkeit;
  float Luftdruck;
};

Daten_Struktur Sender;
Daten_Struktur Sender1;
Daten_Struktur Sender2;

Daten_Struktur AnzahlSender[2] = { Sender1, Sender2 };

void DatenEmpfangen(const uint8_t *MACAdresse, const uint8_t *EmpfangeneDaten, int LangeDaten) 
{
  // Messdaten in das Array Sender kopieren
  memcpy(&Sender, EmpfangeneDaten, sizeof(Sender));
  
  // die empfangenen Daten anhand der ID (Sender.ID)
  // den Sendern zuordnen
  AnzahlSender[Sender.ID].Temperatur = Sender.Temperatur;
  AnzahlSender[Sender.ID].Luftfeuchtigkeit = Sender.Luftfeuchtigkeit;
  AnzahlSender[Sender.ID].Luftdruck = Sender.Luftdruck;

  // in String umwandeln umd . durch , ersetzen zu können
  String AnzeigeTemperatur = String(AnzahlSender[Sender.ID].Temperatur);
  String AnzeigeLuftfeuchtigkeit = String(AnzahlSender[Sender.ID].Luftfeuchtigkeit);

  // float zu int konvertieren -> Nachkommastellen entfernen
  // String AnzeigeLuftdruck = String(int(AnzahlSender[Sender.ID].Luftdruck));

  // oder mit Nachkommastellen
  String AnzeigeLuftdruck = String(AnzahlSender[Sender.ID].Luftdruck);

  // Sensoren anhand der Sender-Nummer identifizieren 
  // und Daten anzeigen
  if (Sender.ID == 0) 
  {
    // . durch , ersetzen
    AnzeigeTemperatur.replace(".", ",");
    AnzeigeLuftdruck.replace(".", ",");
    AnzeigeLuftfeuchtigkeit.replace(".", ",");

    Serial.print("Esszimmer: ");
    Serial.println(AnzeigeTemperatur + "°C");
    Serial.println(AnzeigeLuftfeuchtigkeit + "% ");
    Serial.println(AnzeigeLuftdruck + " hPA"); 
    
    lcd.setCursor(0, 0);
    lcd.print("Esszimmer: ");
    lcd.print(AnzeigeTemperatur);
    lcd.print("\337C ");
    lcd.setCursor(0, 1);
    lcd.print(AnzeigeLuftfeuchtigkeit +"% ");
    lcd.print(AnzeigeLuftdruck + " hPA"); 
  }

  if (Sender.ID == 1) 
  {
    AnzeigeTemperatur.replace(".", ",");
    AnzeigeLuftdruck.replace(".", ",");
    AnzeigeLuftfeuchtigkeit.replace(".", ",");

    Serial.print("Wohnzimmer: ");
    AnzeigeTemperatur.replace(".", ",");
    Serial.println(AnzeigeTemperatur + "°C");
    Serial.println(AnzeigeLuftfeuchtigkeit + "%");
    Serial.println(AnzeigeLuftdruck + " hPA"); 
   
    lcd.setCursor(0, 2);
    lcd.print("Wohnzimmer: ");
    lcd.print(AnzeigeTemperatur);
    lcd.print("\337C ");
    lcd.setCursor(0, 3);
    lcd.print(AnzeigeLuftfeuchtigkeit + "% ");
    lcd.print(AnzeigeLuftdruck + " hPA"); 
  }

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

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

  // LCD starten
  lcd.begin();

  // Cursor "verstecken"
  lcd.setCursor(false);

  WiFi.mode(WIFI_STA);

  // ESP-NOW initialisieren
  if (esp_now_init() != ESP_OK) 
  {
    Serial.println("ESP-NOW konnte nicht gestartet werden!");
    return;
  } 
  else Serial.println("ESP_NOW erfolgreich initialisiert! ");

  esp_now_register_recv_cb((esp_now_recv_cb_t)DatenEmpfangen);
}

void loop() 
{
  // bleibt leer, das Programm reagiert nur auf die Funktion DatenEmpfangen
}

Letz­te Aktualisierung: 

Ter­min­ka­len­der mit ESP32 mit 2,8 Zoll TFT

Gra­fik­trei­ber ILI9341

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

// SPI-Pins TFT
#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

// Objekt tft der Bibliothek Adafruit_ILI9341 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;    

// 3 = FAT32
#define SD_FAT_TYPE 3

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

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

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

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

// Objekt u8g2Schriften
U8G2_FOR_ADAFRUIT_GFX u8g2Schriften;

// 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

// farbliche Gestaltung
// schwarz/weiß
int HintergrundFarbeDatum = SCHWARZ;
int VordergrundFarbeDatum = WEISS;
int HintergrundFarbeTermine = SCHWARZ;
int VordergrundFarbeTermine = WEISS;

// farbig
// int HintergrundFarbeDatum = SILBER;
// int VordergrundFarbeDatum = BLAU;
// int HintergrundFarbeTermine = BLAU;
// int VordergrundFarbeTermine = WEISS;

// 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 Summer 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 = Sommerzeit (dst = daylight saving time)
*/
tm Zeit;

unsigned long Zeitmessung = 0;  

// Anzahl der Datensätze
#define DatenMax 50

// Array für gelesene Zeile aus Datei Kalender.txt
String DatenLesen[DatenMax];

// nach Datum und Beschreibung getrenntes Array
String DatumEintrag[DatenMax];
String KalenderEintrag[DatenMax];

// Bezeichner für die Datei
File Datei;

// char-Array für den Dateinamen erstellen
char Dateiname[20] = "Kalender.txt";

void setup() 
{
  // 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(WiFi.SSID());
  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 starten, Farben invertieren
  tft.begin();
  tft.invertDisplay(0);

  // Rotation anpassen
  tft.setRotation(1);

  // HintergrundFarbeer Hintergrund
  tft.fillScreen(HintergrundFarbeTermine);
  tft.setTextSize(2);
  tft.setTextColor(VordergrundFarbeTermine);
  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!");
    Serial.println("Programm angehalten ...");

    // Programm anhalten
    while(1);;
  } 

  else 
  {
    Serial.println("SD-Karte gestartet ...");
    tft.print("SD-Karte gestartet!");
    tft.setCursor(1, 50);
    tft.print("auf Zeitserver warten ...");
  }

  // tft.fillScreen(HintergrundFarbe);

 // wenn die Datei existiert
  if (SD.exists(Dateiname)) 
  {
    // Datei Kalender.txt öffnen
    Serial.println("-------------------------");
    Serial.println("Zeige " + String(Dateiname));
    
    Datei.open(Dateiname, O_RDONLY);

    int Trenner;
    
    for (int i = 0; i < DatenMax; i++) 
    {
      // Zeile bis zum return ('\n') lesen
      DatenLesen[i] = Datei.readStringUntil('\n');

      // Position des Trennzeichens
      Trenner = DatenLesen[i].indexOf("/");

      // Leerzeichen entfernen
      DatenLesen[i].trim();

      // Zeile am Komma in Datum und Kalendereintrag trennnen
      DatumEintrag[i] = DatenLesen[i].substring(0, Trenner);
      KalenderEintrag[i] = DatenLesen[i].substring(Trenner + 1, DatenLesen[i].length());
        
      // Abbruch, wenn kein Datensatz nehr vorhanden
      if (DatenLesen[i] == "") break;
      Serial.println(DatumEintrag[i]);
      Serial.println(KalenderEintrag[i]);
    }
    
    // Datei schließen
    Datei.close(); 
  }

  // Datei existiert nicht
  else
  {
    Serial.println("Datei " + String(Dateiname) + " nicht gefunden!");
    Serial.println("Programm angehalten ...");

    // Programm beenden
    while(1);
  }

  // beim Start entspricht das Datum der Unixtime: 1.1.1970
  // Datum/Kalender sollen erst angezeigt werden, wenn das Datum korrekt ist
  String Jahr = String(Zeit.tm_year + 1900); 
  int Zaehler = 0;

  // String Jahr nach "1970" durchsuchen
  int Suche = Jahr.indexOf("1970");         

  Serial.println("-------------------------"); 
  Serial.println("Datum und Zeit holen (maximal 90 Sekunden)...");
  
  // solange die Suche nicht erfolgreich ist
  while (Suche != -1) 
  {
    // aktuelle Zeit holen
    time(&aktuelleZeit);

    // localtime_r -> Zeit in die lokale Zeitzone setzen
    localtime_r(&aktuelleZeit, &Zeit);
    Jahr = String(Zeit.tm_year + 1900); 
    
    // String Jahr nach "1970" durchsuchen
    Suche = Jahr.indexOf("1970");

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

    if (Zaehler >= 90)
    {
      Serial.println();
      Serial.println("Datum und Zeit konnte innerhalb von " + String(Zaehler) + " Sekunden nicht geholt werden");
      Serial.println("Programm wird beendet");

      // Programm beenden
      while(1);
    }

    Serial.print(".");
  }   

  Serial.println();

  // Datum/Zeit erfolgreich synchronisiert
  if (Suche == -1) 
  {
    Serial.println("-------------------------");
    Serial.println("Datum/Zeit erfolgreich synchronisiert ...");
    
    if (Zeit.tm_mday < 10) Serial.print("0");
    Serial.print(Zeit.tm_mday);
    Serial.print(".");

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

    // Anzahl Jahre seit 1900
    Serial.println(Zeit.tm_year + 1900);

    if (Zeit.tm_hour < 10) Serial.print("0");
    Serial.print(Zeit.tm_hour);
    Serial.print(":");
      
    if (Zeit.tm_min < 10) Serial.print("0");
    Serial.println(Zeit.tm_min);
    Serial.println("-------------------------");

    ZeigeDatum();

    // beim Start -> Kalender nach Terminen durchsuchen
    Serial.println("Kalender nach Terminen durchsuchen ...");
    KalenderDurchsuchen();
    
    // Zeit anzeigen
    tft.fillRect(1, 30, tft.width(), 45, HintergrundFarbeDatum);
    u8g2Schriften.setFont(u8g2_font_logisoso28_tf);   
    u8g2Schriften.setForegroundColor(VordergrundFarbeDatum);
    u8g2Schriften.setBackgroundColor(HintergrundFarbeDatum);
    u8g2Schriften.setCursor(1, 70);

    if (Zeit.tm_hour < 10) 
    {
      u8g2Schriften.print("0");
      Serial.print("0");
    }
    u8g2Schriften.print(Zeit.tm_hour);
    u8g2Schriften.print(":");
    Serial.print(Zeit.tm_hour);
    Serial.print(":");
      
    if (Zeit.tm_min < 10) 
    {
      u8g2Schriften.print("0");
      Serial.print("0");
    }

    u8g2Schriften.print(Zeit.tm_min);
    Serial.print(Zeit.tm_min);
    Serial.println(" Uhr");

    tft.drawLine(1, 80, tft.width(), 80, VordergrundFarbeDatum);
  }
  
  Zeitmessung = millis() + 1000; 
}

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

    if (Sekunden == 60) 
    { 
      Sekunden = 0; 
    
      // 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);

      tft.fillRect(1, 30, tft.width(), 45, HintergrundFarbeDatum);
      u8g2Schriften.setFont(u8g2_font_logisoso28_tf);   
      u8g2Schriften.setForegroundColor(VordergrundFarbeDatum);
      u8g2Schriften.setBackgroundColor(HintergrundFarbeDatum);
      u8g2Schriften.setCursor(1, 70);

      if (Zeit.tm_hour < 10) 
      {
        u8g2Schriften.print("0");
        Serial.print("0");
      }
      u8g2Schriften.print(Zeit.tm_hour);
      u8g2Schriften.print(":");
      Serial.print(Zeit.tm_hour);
      Serial.print(":");
      
      if (Zeit.tm_min < 10) 
      {
        u8g2Schriften.print("0");
        Serial.print("0");
      }

      u8g2Schriften.print(Zeit.tm_min);
      Serial.print(Zeit.tm_min);

      Serial.println(" Uhr");

      // tft.drawLine(1, 80, tft.width(), 80, VordergrundFarbe);

      // Mitternacht 
      // -> Wechsel des Datums anzeigen
      // -> Kalender durchsuchen
      if (Stunden == 0 && Minuten == 0) 
      {
          ZeigeDatum();
          KalenderDurchsuchen();
      }
    }
  }
}

void ZeigeDatum()
{
  tft.fillRect(1, 1, tft.width(), 79, HintergrundFarbeDatum);
  u8g2Schriften.setFont(u8g2_font_logisoso20_tf);   
  u8g2Schriften.setForegroundColor(VordergrundFarbeDatum);
  u8g2Schriften.setBackgroundColor(HintergrundFarbeDatum);
  
  u8g2Schriften.setCursor(1, 25);

  // Wochentag anzeigen
  switch (Zeit.tm_wday) 
  {
    case 0:
      u8g2Schriften.print("Sonntag");
      break;
    case 1:
      u8g2Schriften.print("Montag");
      break;
    case 2:
      u8g2Schriften.print("Dienstag");
      break;
    case 3:
      u8g2Schriften.print("Mittwoch");
      break;
    case 4:
      u8g2Schriften.print("Donnerstag");
      break;
    case 5:
      u8g2Schriften.print("Freitag");
      break;
    case 6:
      u8g2Schriften.print("Samstag");
      break;
  }

  u8g2Schriften.print(", ");
      
  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);

  tft.drawLine(1, 80, tft.width(), 80, VordergrundFarbeDatum);
}

void KalenderDurchsuchen()
{
  /*
    Datum = String für das aktuelle Datum
    Treffer = true wenn es einen oder mehrere Treffer beim Datum gibt
    Termin[] = zum aktuellen Datum gefundene Einträge
    Abstand = Abstand in Pixeln zwischen mehreren Einträgen
    Trenner = Position des Trennzeichens (/)
    AnzahlDaten = Anzahl aller Daten in der Datei
    AnzahlTreffer = Anzahl der zum aktuellen Datum passenden Einträge
  */
  String Datum;
  bool Treffer = false;
  String Termin[DatenMax];
  int Abstand;
  int Trenner;
  int AnzahlTreffer;
  int AnzahlDaten;
  
  // Datei lesen
  if (Datei.open(Dateiname, O_RDONLY)) 
  {
    while (Datei.available()) 
    {
       for (int i = 0; i < DatenMax; i++) 
       {
        // Zeile bis zum return ('\n') lesen
        DatenLesen[i] = Datei.readStringUntil('\n');

        // Position des Trennzeichens
        Trenner = DatenLesen[i].indexOf("/");

        // Leerzeichen entfernen
        DatenLesen[i].trim();

        // Zeile am Komma in Datum und Kalendereintrag trennnen
        DatumEintrag[i] = DatenLesen[i].substring(0, Trenner);
        KalenderEintrag[i] = DatenLesen[i].substring(Trenner + 1, DatenLesen[i].length());

        // Anzahl der Einträge feststellen
        AnzahlDaten = i;

        Serial.println(DatumEintrag[i]);
        Serial.println(KalenderEintrag[i]);

        // Abbruch, wenn kein Datensatz nehr vorhanden
        if (DatenLesen[i] == "") break;
      }
    }
  }

  // Datei schließen
  Datei.close(); 

  // Datum zusammensetzen: TT.MM.
  // bei einstelligen Tag/Monat 0 davor setzen
  if (Zeit.tm_mday < 10) Datum = "0" + String(Zeit.tm_mday);
  else Datum = String(Zeit.tm_mday);
  Datum += ".";
  
  if (Zeit.tm_mon < 10) Datum += "0" + String(Zeit.tm_mon + 1);
  else Datum += String(Zeit.tm_mon + 1);
  
  Datum += ".";
  
  AnzahlTreffer = 0;

  // Einträge nach aktuellen Datum durchsuchen
  for (int i = 0; i <= AnzahlDaten; i++)
  {
    // wenn das aktuelle Element des Arrays mit dem Datum übereinstimmt
    if (DatumEintrag[i] == Datum) 
    {
      // Übereinstimmung gefunden
      Treffer = true;
      AnzahlTreffer ++;

      // dem String KalenderEintrag das aktuelle Elent des Arrays hinzufügen
      Termin[AnzahlTreffer] = KalenderEintrag[i];
      Serial.println(Termin[AnzahlTreffer]);
    }
  }

  tft.fillRect(1, 80, tft.width(), tft.height(), HintergrundFarbeTermine);
  u8g2Schriften.setForegroundColor(VordergrundFarbeTermine);   
  u8g2Schriften.setBackgroundColor(HintergrundFarbeTermine);

  // Schriftgröße 12
  // u8g2Schriften.setFont(u8g2_font_luBS12_tf);

  // Schriftgröße 14
  u8g2Schriften.setFont(u8g2_font_helvB14_tf);

  // Schriftgröße 18
  // u8g2Schriften.setFont(u8g2_font_luRS18_tf);  
  
  // Schriftgröße 20
  // u8g2Schriften.setFont(u8g2_font_logisoso20_tf);  
  
  // Schriftgröße 24
  // u8g2Schriften.setFont(u8g2_font_helvB24_tf);  

  // wenn es einen/mehrere Treffer gab (Treffer = true)
  // Anzahl der Treffer
  Serial.println(String(AnzahlTreffer) + " Treffer");
  if (Treffer)
  {
    // Einträge anzeigen
    for(int i = 0; i <= AnzahlTreffer; i++)
    {
      u8g2Schriften.setCursor(1, 80 + Abstand);
      u8g2Schriften.print(Termin[i]);

      // je nach Schriftgröße kann der Abstand angepasst werden
      Abstand += 30;
    }
  }

  // keine Treffer
  else 
  {  
    u8g2Schriften.setCursor(1, 120);
    u8g2Schriften.print("Keine Termine heute!"); 
  }
}

Gra­fik­trei­ber ST7789

#include "WiFi.h"
#include "time.h"
#include "U8g2_for_Adafruit_GFX.h"
#include "SdFat.h"
#include "Adafruit_ST7789.h"   

// SPI-Pins TFT
#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

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

// Objekt SD der Bibliothek SdFat erstellen
SdFat SD;    

// 3 = FAT32
#define SD_FAT_TYPE 3

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

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

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

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

// Objekt u8g2Schriften
U8G2_FOR_ADAFRUIT_GFX u8g2Schriften;

// 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

// farbliche Gestaltung
// schwarz/weiß
int HintergrundFarbeDatum = SCHWARZ;
int VordergrundFarbeDatum = WEISS;
int HintergrundFarbeTermine = SCHWARZ;
int VordergrundFarbeTermine = WEISS;

// farbig
// int HintergrundFarbeDatum = SILBER;
// int VordergrundFarbeDatum = BLAU;
// int HintergrundFarbeTermine = BLAU;
// int VordergrundFarbeTermine = WEISS;

// 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 Summer 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 = Sommerzeit (dst = daylight saving time)
*/
tm Zeit;

unsigned long Zeitmessung = 0;  

// Anzahl der Datensätze
#define DatenMax 50

// Array für gelesene Zeile aus Datei Kalender.txt
String DatenLesen[DatenMax];

// nach Datum und Beschreibung getrenntes Array
String DatumEintrag[DatenMax];
String KalenderEintrag[DatenMax];

// Bezeichner für die Datei
File Datei;

// char-Array für den Dateinamen erstellen
char Dateiname[20] = "Kalender.txt";

void setup() 
{
  // 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(WiFi.SSID());
  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 starten, Farben invertieren
  tft.init(240, 320);
  tft.invertDisplay(0);

  // Rotation anpassen
  tft.setRotation(1);

  // HintergrundFarbeer Hintergrund
  tft.fillScreen(HintergrundFarbeTermine);
  tft.setTextSize(2);
  tft.setTextColor(VordergrundFarbeTermine);
  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!");
    Serial.println("Programm angehalten ...");

    // Programm anhalten
    while(1);;
  } 

  else 
  {
    Serial.println("SD-Karte gestartet ...");
    tft.print("SD-Karte gestartet!");
    tft.setCursor(1, 50);
    tft.print("auf Zeitserver warten ...");
  }

  // tft.fillScreen(HintergrundFarbe);

 // wenn die Datei existiert
  if (SD.exists(Dateiname)) 
  {
    // Datei Kalender.txt öffnen
    Serial.println("-------------------------");
    Serial.println("Zeige " + String(Dateiname));
    
    Datei.open(Dateiname, O_RDONLY);

    int Trenner;
    
    for (int i = 0; i < DatenMax; i++) 
    {
      // Zeile bis zum return ('\n') lesen
      DatenLesen[i] = Datei.readStringUntil('\n');

      // Position des Trennzeichens
      Trenner = DatenLesen[i].indexOf("/");

      // Leerzeichen entfernen
      DatenLesen[i].trim();

      // Zeile am Komma in Datum und Kalendereintrag trennnen
      DatumEintrag[i] = DatenLesen[i].substring(0, Trenner);
      KalenderEintrag[i] = DatenLesen[i].substring(Trenner + 1, DatenLesen[i].length());
        
      // Abbruch, wenn kein Datensatz nehr vorhanden
      if (DatenLesen[i] == "") break;
      Serial.println(DatumEintrag[i]);
      Serial.println(KalenderEintrag[i]);
    }
    
    // Datei schließen
    Datei.close(); 
  }

  // Datei existiert nicht
  else
  {
    Serial.println("Datei " + String(Dateiname) + " nicht gefunden!");
    Serial.println("Programm angehalten ...");

    // Programm beenden
    while(1);
  }

  // beim Start entspricht das Datum der Unixtime: 1.1.1970
  // Datum/Kalender sollen erst angezeigt werden, wenn das Datum korrekt ist
  String Jahr = String(Zeit.tm_year + 1900); 
  int Zaehler = 0;

  // String Jahr nach "1970" durchsuchen
  int Suche = Jahr.indexOf("1970");         

  Serial.println("-------------------------"); 
  Serial.println("Datum und Zeit holen (maximal 90 Sekunden)...");
  
  // solange die Suche nicht erfolgreich ist
  while (Suche != -1) 
  {
    // aktuelle Zeit holen
    time(&aktuelleZeit);

    // localtime_r -> Zeit in die lokale Zeitzone setzen
    localtime_r(&aktuelleZeit, &Zeit);
    Jahr = String(Zeit.tm_year + 1900); 
    
    // String Jahr nach "1970" durchsuchen
    Suche = Jahr.indexOf("1970");

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

    if (Zaehler >= 90)
    {
      Serial.println();
      Serial.println("Datum und Zeit konnte innerhalb von " + String(Zaehler) + " Sekunden nicht geholt werden");
      Serial.println("Programm wird beendet");

      // Programm beenden
      while(1);
    }

    Serial.print(".");
  }   

  Serial.println();

  // Datum/Zeit erfolgreich synchronisiert
  if (Suche == -1) 
  {
    Serial.println("-------------------------");
    Serial.println("Datum/Zeit erfolgreich synchronisiert ...");
    
    if (Zeit.tm_mday < 10) Serial.print("0");
    Serial.print(Zeit.tm_mday);
    Serial.print(".");

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

    // Anzahl Jahre seit 1900
    Serial.println(Zeit.tm_year + 1900);

    if (Zeit.tm_hour < 10) Serial.print("0");
    Serial.print(Zeit.tm_hour);
    Serial.print(":");
      
    if (Zeit.tm_min < 10) Serial.print("0");
    Serial.println(Zeit.tm_min);
    Serial.println("-------------------------");

    ZeigeDatum();

    // beim Start -> Kalender nach Terminen durchsuchen
    Serial.println("Kalender nach Terminen durchsuchen ...");
    KalenderDurchsuchen();
    
    // Zeit anzeigen
    tft.fillRect(1, 30, tft.width(), 45, HintergrundFarbeDatum);
    u8g2Schriften.setFont(u8g2_font_logisoso28_tf);   
    u8g2Schriften.setForegroundColor(VordergrundFarbeDatum);
    u8g2Schriften.setBackgroundColor(HintergrundFarbeDatum);
    u8g2Schriften.setCursor(1, 70);

    if (Zeit.tm_hour < 10) 
    {
      u8g2Schriften.print("0");
      Serial.print("0");
    }
    u8g2Schriften.print(Zeit.tm_hour);
    u8g2Schriften.print(":");
    Serial.print(Zeit.tm_hour);
    Serial.print(":");
      
    if (Zeit.tm_min < 10) 
    {
      u8g2Schriften.print("0");
      Serial.print("0");
    }

    u8g2Schriften.print(Zeit.tm_min);
    Serial.print(Zeit.tm_min);
    Serial.println(" Uhr");

    tft.drawLine(1, 80, tft.width(), 80, VordergrundFarbeDatum);
  }
  
  Zeitmessung = millis() + 1000; 
}

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

    if (Sekunden == 60) 
    { 
      Sekunden = 0; 
    
      // 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);

      tft.fillRect(1, 30, tft.width(), 45, HintergrundFarbeDatum);
      u8g2Schriften.setFont(u8g2_font_logisoso28_tf);   
      u8g2Schriften.setForegroundColor(VordergrundFarbeDatum);
      u8g2Schriften.setBackgroundColor(HintergrundFarbeDatum);
      u8g2Schriften.setCursor(1, 70);

      if (Zeit.tm_hour < 10) 
      {
        u8g2Schriften.print("0");
        Serial.print("0");
      }
      u8g2Schriften.print(Zeit.tm_hour);
      u8g2Schriften.print(":");
      Serial.print(Zeit.tm_hour);
      Serial.print(":");
      
      if (Zeit.tm_min < 10) 
      {
        u8g2Schriften.print("0");
        Serial.print("0");
      }

      u8g2Schriften.print(Zeit.tm_min);
      Serial.print(Zeit.tm_min);

      Serial.println(" Uhr");

      // tft.drawLine(1, 80, tft.width(), 80, VordergrundFarbe);

      // Mitternacht 
      // -> Wechsel des Datums anzeigen
      // -> Kalender durchsuchen
      if (Stunden == 0 && Minuten == 0) 
      {
          ZeigeDatum();
          KalenderDurchsuchen();
      }
    }
  }
}

void ZeigeDatum()
{
  tft.fillRect(1, 1, tft.width(), 79, HintergrundFarbeDatum);
  u8g2Schriften.setFont(u8g2_font_logisoso20_tf);   
  u8g2Schriften.setForegroundColor(VordergrundFarbeDatum);
  u8g2Schriften.setBackgroundColor(HintergrundFarbeDatum);
  
  u8g2Schriften.setCursor(1, 25);

  // Wochentag anzeigen
  switch (Zeit.tm_wday) 
  {
    case 0:
      u8g2Schriften.print("Sonntag");
      break;
    case 1:
      u8g2Schriften.print("Montag");
      break;
    case 2:
      u8g2Schriften.print("Dienstag");
      break;
    case 3:
      u8g2Schriften.print("Mittwoch");
      break;
    case 4:
      u8g2Schriften.print("Donnerstag");
      break;
    case 5:
      u8g2Schriften.print("Freitag");
      break;
    case 6:
      u8g2Schriften.print("Samstag");
      break;
  }

  u8g2Schriften.print(", ");
      
  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);

  tft.drawLine(1, 80, tft.width(), 80, VordergrundFarbeDatum);

}

void KalenderDurchsuchen()
{
  /*
    Datum = String für das aktuelle Datum
    Treffer = true wenn es einen oder mehrere Treffer beim Datum gibt
    Termin[] = zum aktuellen Datum gefundene Einträge
    Abstand = Abstand in Pixeln zwischen mehreren Einträgen
    Trenner = Position des Trennzeichens (/)
    AnzahlDaten = Anzahl aller Daten in der Datei
    AnzahlTreffer = Anzahl der zum aktuellen Datum passenden Einträge
  */
  String Datum;
  bool Treffer = false;
  String Termin[DatenMax];
  int Abstand;
  int Trenner;
  int AnzahlTreffer;
  int AnzahlDaten;
  
  // Datei lesen
  if (Datei.open(Dateiname, O_RDONLY)) 
  {
    while (Datei.available()) 
    {
       for (int i = 0; i < DatenMax; i++) 
       {
        // Zeile bis zum return ('\n') lesen
        DatenLesen[i] = Datei.readStringUntil('\n');

        // Position des Trennzeichens
        Trenner = DatenLesen[i].indexOf("/");

        // Leerzeichen entfernen
        DatenLesen[i].trim();

        // Zeile am Komma in Datum und Kalendereintrag trennnen
        DatumEintrag[i] = DatenLesen[i].substring(0, Trenner);
        KalenderEintrag[i] = DatenLesen[i].substring(Trenner + 1, DatenLesen[i].length());

        // Anzahl der Einträge feststellen
        AnzahlDaten = i;

        Serial.println(DatumEintrag[i]);
        Serial.println(KalenderEintrag[i]);

        // Abbruch, wenn kein Datensatz nehr vorhanden
        if (DatenLesen[i] == "") break;
      }
    }
  }

  // Datei schließen
  Datei.close(); 

  // Datum zusammensetzen: TT.MM.
  // bei einstelligen Tag/Monat 0 davor setzen
  if (Zeit.tm_mday < 10) Datum = "0" + String(Zeit.tm_mday);
  else Datum = String(Zeit.tm_mday);
  Datum += ".";
  
  if (Zeit.tm_mon < 10) Datum += "0" + String(Zeit.tm_mon + 1);
  else Datum += String(Zeit.tm_mon + 1);
  
  Datum += ".";
  
  AnzahlTreffer = 0;

  // Einträge nach aktuellen Datum durchsuchen
  for (int i = 0; i <= AnzahlDaten; i++)
  {
    // wenn das aktuelle Element des Arrays mit dem Datum übereinstimmt
    if (DatumEintrag[i] == Datum) 
    {
      // Übereinstimmung gefunden
      Treffer = true;
      AnzahlTreffer ++;

      // dem String KalenderEintrag das aktuelle Elent des Arrays hinzufügen
      Termin[AnzahlTreffer] = KalenderEintrag[i];
      Serial.println(Termin[AnzahlTreffer]);
    }
  }

  tft.fillRect(1, 80, tft.width(), tft.height(), HintergrundFarbeTermine);
  u8g2Schriften.setForegroundColor(VordergrundFarbeTermine);   
  u8g2Schriften.setBackgroundColor(HintergrundFarbeTermine);

  // Schriftgröße 12
  // u8g2Schriften.setFont(u8g2_font_luBS12_tf);

  // Schriftgröße 14
  u8g2Schriften.setFont(u8g2_font_helvB14_tf);

  // Schriftgröße 18
  // u8g2Schriften.setFont(u8g2_font_luRS18_tf);  
  
  // Schriftgröße 20
  // u8g2Schriften.setFont(u8g2_font_logisoso20_tf);  
  
  // Schriftgröße 24
  // u8g2Schriften.setFont(u8g2_font_helvB24_tf);  

  // wenn es einen/mehrere Treffer gab (Treffer = true)
  // Anzahl der Treffer
  Serial.println(String(AnzahlTreffer) + " Treffer");
  if (Treffer)
  {
    // Einträge anzeigen
    for(int i = 0; i <= AnzahlTreffer; i++)
    {
      u8g2Schriften.setCursor(1, 80 + Abstand);
      u8g2Schriften.print(Termin[i]);

      // je nach Schriftgröße kann der Abstand angepasst werden
      Abstand += 30;
    }
  }

  // keine Treffer
  else 
  {  
    u8g2Schriften.setCursor(1, 120);
    u8g2Schriften.print("Keine Termine heute!"); 
  }
}

Letzte Aktualisierung:

Foto­schau mit ESP32 TFT und SD-Kartenleser

mit inter­nem Kartenleser

#include "SdFat.h"
#include "Adafruit_ST7796S_kbv.h"
#include "Adafruit_ImageReader.h"

// ESP32-WROOM
#define TFT_CS        5
#define TFT_RST       4 
#define TFT_DC        2

/* 
  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_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(10)

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

// Anzeigedauer
int Intervall = 6000;

bool Beschreibung = true;

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

  // auf serielle Verbindung warten
  while (!Serial);
  delay(1000);
 
  // TFT starten
  tft.begin();
  
  tft.invertDisplay(1);

  // Rotation anpassen
  tft.setRotation(3);

  // 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);
}

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("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("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("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);
}

mit exter­nem SD-Kartenleser

#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 -> Bild ohne Beschriftung anzeigen
bool Beschreibung = true;

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);
}
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("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);

  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("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);
}

Letzte Aktualisierung:

Foto­schau mit TFT-Shield

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

// CS-Pin SD-Karte
#define SD_CS 4    

// Pins TFT
#define TFT_CS 10  
#define TFT_DC 9   

// Dateisystem SD-Karte
SdFat SD;              

// Objekt des Kartenlesers wird an das Dateisystem der SD-Karte übertragen
Adafruit_ImageReader reader(SD);

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
Adafruit_Image Bild;  

ImageReturnCode Status;

int Intervall = 2000;

void setup() 
{
  // TFT starten
  tft.begin();

  // SD-Karte starten
  SD.begin(SD_CS);

  tft.setRotation(3);  
  tft.fillScreen(0);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE);
}

void loop() 
{
  // Bild laden
  // alle Dateien befinden sich im root-Verzeichnis /
  Status = reader.loadBMP("/koeln.bmp", Bild);

  // Bild anzeigen
  // Parameter: Dateiname, tft, StartpositionX, StartpositionY
  reader.drawBMP("koeln.bmp", tft, 0, 0);
  tft.setCursor(10, 220);
  tft.print("K");

  // ö = 0x94
  tft.write(0x94);
  tft.println("ln");
  delay(Intervall);  
  tft.fillScreen(0);

  Status = reader.loadBMP("/dresden_bruecke.bmp", Bild);
  reader.drawBMP("dresden_bruecke.bmp", tft, 0, 0);
  tft.setCursor(10, 220);
  tft.println("Dresden 'Blaues Wunder'");
  delay(Intervall);
  tft.fillScreen(0);

  Status = reader.loadBMP("/overath_Bahnhof.bmp", Bild);
  reader.drawBMP("overath_Bahnhof.bmp", tft, 0, 0);
  tft.setCursor(10, 220);
  tft.println("Overath Bahnhof");
  delay(Intervall);
  tft.fillScreen(0);

  Status = reader.loadBMP("/dresden_frauenkirche.bmp", Bild);
  reader.drawBMP("dresden_frauenkirche.bmp", tft, 0, 0);
  tft.setCursor(10, 220);
  tft.println("Dresden Frauenkirche");
  delay(Intervall);
  tft.fillScreen(0);

  Status = reader.loadBMP("/braunwald.bmp", Bild);
  reader.drawBMP("braunwald.bmp", tft, 0, 0);
  tft.setCursor(10, 220);
  tft.println("Braunwald/Schweiz");
  delay(Intervall);
  tft.fillScreen(0);

  Status = reader.loadBMP("/chartres.bmp", Bild);
  reader.drawBMP("chartres.bmp", tft, 0, 0);
  tft.setCursor(10, 220);
  tft.println("Chartres Kathedrale");
  delay(Intervall);
  tft.fillScreen(0);

  Status = reader.loadBMP("/strand.bmp", Bild);
  reader.drawBMP("strand.bmp", tft, 0, 0);
  tft.setCursor(10, 220);
  tft.println("Strand Algarve");
  delay(Intervall);
  tft.fillScreen(0);

  Status = reader.loadBMP("/duenen_ibiza.bmp", Bild);
  reader.drawBMP("duenen_ibiza.bmp", tft, 0, 0);
  tft.setCursor(10, 220);
  tft.print("D");

  // ü = 0x81
  tft.write(0x81);
  tft.print("nen Ibiza");
  delay(Intervall);
  tft.fillScreen(0);

  Status = reader.loadBMP("/lindos.bmp", Bild);
  reader.drawBMP("lindos.bmp", tft, 0, 0);
  tft.setCursor(10, 220);
  tft.print("Lindos/Rhodos");
  delay(Intervall);
  tft.fillScreen(0);

  Status = reader.loadBMP("/see.bmp", Bild);
  reader.drawBMP("see.bmp", tft, 0, 0);
  tft.setCursor(10, 220);
  tft.print("See bei Innsbruck");
  delay(Intervall);
  tft.fillScreen(0);

  Status = reader.loadBMP("/uni_bonn.bmp", Bild);
  reader.drawBMP("uni_bonn.bmp", tft, 0, 0);
  tft.setCursor(10, 220);
  tft.print("Bonn Uni");
  delay(Intervall);
  tft.fillScreen(0);

  Status = reader.loadBMP("/berlin_olympia.bmp", Bild);
  reader.drawBMP("berlin_olympia.bmp", tft, 0, 0);
  tft.setCursor(10, 220);
  tft.print("Berlin Olympiastatdion");
  delay(Intervall);
  tft.fillScreen(0);
}

Letzte Aktualisierung:

Ana­lo­ge Uhr mit TFT

240×240 Pixel

#ifdef ESP8266
  #include "ESP8266WiFi.h"

#else 
  #include "WiFi.h"
#endif

#include "time.h"
#include "Adafruit_GC9A01A.h"

// Adafruit-Schriftart einbinden
#include "Fonts/FreeSans12pt7b.h"

// Wemos D1 Mini
// #define TFT_CS       D8
// #define TFT_RST      D1
// #define TFT_DC       D2

// XIAO
// #define TFT_CS       D7
// #define TFT_RST      D1
// #define TFT_DC       D2

// ESP32-C3
// #define TFT_RST      2
// #define TFT_DC       3
// #define TFT_CS       7

// ESP32-C3 Super Mini
// #define TFT_RST      2
// #define TFT_DC       3
// #define TFT_CS       7

// Arduino Nano ESP 32
// #define TFT_CS       10
// #define TFT_RST       9
// #define TFT_DC        8

// ESP32-C6
// #define TFT_CS       18
// #define TFT_RST       3                                          
// #define TFT_DC        2

// ESP32-WROOM
// #define TFT_CS        5
// #define TFT_RST       4 
// #define TFT_DC        2

// ESP32-S3
// #define TFT_CS        10
// #define TFT_RST        5
// #define TFT_DC         4

// ESP32-S3
// #define TFT_CS        10
// #define TFT_RST        5
// #define TFT_DC         4

Adafruit_GC9A01A tft(TFT_CS, TFT_DC);

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

// Variablen des TFTs (Höhe, Breite, Radius)
const int MitteHoehe = tft.height() / 2;
const int MitteBreite = tft.width() / 2;
const int Radius = tft.width() / 2;

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

// 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 = Sommerzeit (dst = daylight saving time)
*/
tm Zeit;

unsigned long Zeitmessung = 0; 

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

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

  WiFi.mode(WIFI_STA);
  
  // WiFi starten
  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);

  // beim Start entspricht das Datum der Unixtime: 1.1.1970
  // Datum/Kalender sollen erst angezeigt werden, wenn das Datum korrekt ist
  String Jahr = String(Zeit.tm_year + 1900); 
  int Zaehler = 0;

  // String Jahr nach "1970" durchsuchen
  int Suche = Jahr.indexOf("1970");         

  Serial.println("-------------------------"); 
  Serial.println("Datum und Zeit holen (maximal 90 Sekunden)...");
  
  // solange die Suche nicht erfolgreich ist
  while (Suche != -1) 
  {
    // aktuelle Zeit holen
    time(&aktuelleZeit);

    // localtime_r -> Zeit in die lokale Zeitzone setzen
    localtime_r(&aktuelleZeit, &Zeit);
    Jahr = String(Zeit.tm_year + 1900); 
    
    // String Jahr nach "1970" durchsuchen
    Suche = Jahr.indexOf("1970");

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

    if (Zaehler >= 90)
    {
      Serial.println();
      Serial.println("Datum und Zeit konnte innerhalb von " + String(Zaehler) + " Sekunden nicht geholt werden");
      Serial.println("Programm wird beendet");

      // Programm beenden
      while(1);
    }

    Serial.print(".");
  }   

  Serial.println();

  // Datum/Zeit erfolgreich synchronisiert
  if (Suche == -1) 
  {
    Serial.println("-------------------------");
    Serial.println("Datum/Zeit erfolgreich synchronisiert ...");
    
    if (Zeit.tm_mday < 10) Serial.print("0");
    Serial.print(Zeit.tm_mday);
    Serial.print(".");

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

    // Anzahl Jahre seit 1900
    Serial.println(Zeit.tm_year + 1900);

    if (Zeit.tm_hour < 10) Serial.print("0");
    Serial.print(Zeit.tm_hour);
    Serial.print(":");
      
    if (Zeit.tm_min < 10) Serial.print("0");
    Serial.println(Zeit.tm_min);
    Serial.println("-------------------------");
  }

  // Zeit in Stunden, Minuten und Sekunden
  Stunden = Zeit.tm_hour, Minuten = Zeit.tm_min, Sekunden = Zeit.tm_sec;
  
  
  tft.begin();
  tft.setRotation(0);
  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;

    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 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)
  {
    tft.setFont(&FreeSans12pt7b);
    tft.setTextColor(Zeigerfarbe);
    tft.setCursor(tft.height() / 2 - 15, 25);
    tft.print("12");
    
    tft.setCursor(10, tft.height() / 2 + 7);
    tft.print("9");
    
    tft.setCursor(220, tft.height() / 2 + 10);
    tft.print("3");
  
    tft.setCursor(tft.height() / 2 - 7, 230);
    tft.print("6");
  }

  if (DatumAnzeigen) ZeigeDatum();

  Zeitmessung = millis() + 1000; 
}

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

    if (Sekunden == 60) 
    { 
      // aktuelle 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;

      // Mitternacht 
      // -> Wechsel des Datums anzeigen
      if (Stunden == 0 && Minuten == 0) 
      {
        Serial.println("neues Datum");
        if (DatumAnzeigen) ZeigeDatum();
      }

      // Zeiger "löschen" Anzeige des Datums -> jede Minute erneuern
      if (DatumAnzeigen) ZeigeDatum();
    }

    // Datum anzeigen/nicht anzeigen
    // Datumsanzeige nur erneuern, wenn der Sekundenzeiger
    // vollständig als Strich und Kreis angezeigt wird
    if (DatumAnzeigen && !SekundenzeigerKreis)
    {
      // Anzeige des Datums nur aktualisieren,
      // wenn sich der Sekundenzeiger darüber befindet
      if (Sekunden > 20 & Sekunden < 40)
      {
        ZeigeDatum();
      }
    }

    // Vorausberechnung der x- und y-Koordinaten
    // alle 6° eine Sekunde vorwärts
    GradSekunden = Sekunden * 6;    
  
    // alle 6° eine Minute vorwärts     
    GradMinuten = Minuten * 6; 

    // alle 30° eine Stunde vorwärts
    // 30 / 3600 = 0.0833333
    // sorgt dafür, dass der Stundenzeiger entsprechend 
    // der Anzahl der Minuten weiter "wandert"
    GradStunden = Stunden * 30 + GradMinuten * 0.0833333; 
    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) 
    {
      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()
{
  tft.setFont(&FreeSans12pt7b);  
  tft.setCursor(65, 170);
  tft.setTextColor(GRUEN);
      
  // Bildschirmbereich für das Datum löschen
  tft.fillRect(60, 150, 125, 25, Kreisfarbe);
  if (Zeit.tm_mday < 10) tft.print("0");
  tft.print(Zeit.tm_mday);
  tft.print(".");

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

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

320×240 Pixel

Benö­tig­te Bibliotheken

Mess­wer­te eines Poten­tio­me­ters darstellen

TFT mit 320×240 Pixeln

#include "Adafruit_ILI9341.h"

// Schriftarten einbinden
#include "Fonts/FreeSans24pt7b.h"
#include "Fonts/FreeSans12pt7b.h"

// Wemos D1 Mini
// #define TFT_CS D8
// #define TFT_RST D1
// #define TFT_DC D2

// ESP32-WROOM
// #define TFT_CS 5
// #define TFT_RST 4 
// #define TFT_DC 2

// Farben
#define SCHWARZ    0x0000
#define WEISS      0xFFFF 

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

// GFXcanvas-Objekt erstellen: Höhe 170 Pixel, Breite 320 Pixel
GFXcanvas1 Bereich(170, 320);

// analogen Pin anpassen
int Poti = A0;

// maximalen Wert des ADC anpassen
// ESP32: 4096, ESP8266: 1024
int ADCMax = 1024;

/*
  Abstand der Markierung von der Mitte des TFTs
  der ADC liefert keine linear verlaufenden Werte
  der Abstand kann angepasst werden
*/
int AbstandMarkierung = 40;

void setup()
{
  // TFT starten
  tft.begin();

  // Rotation anpassen
  tft.setRotation(2);

  // schwarzer Hintergrund
  tft.fillScreen(SCHWARZ);
  Serial.begin(9600);
}

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

  // analogen Wert lesen
  int WertPoti = analogRead(Poti);

  Serial.println(WertPoti);

  // analogen Wert anzeigen
  Bereich.setFont(&FreeSans24pt7b); 
  Bereich.setCursor(10, 50);  
  Bereich.print(WertPoti);

  // analogen Wert auf die Höhe des TFTs übertragen
  int BalkenPoti = map(WertPoti, 0, ADCMax, 0, 320);

  /*
    bei gedrehtem Bildschirm wird der Balken von oben nach unten angezeigt
    zuerest maximalen Wert weiß füllen
    anschließend vom maximalen Wert den gemessenen Wert abziehen
    und schwarz füllen
  */
  Bereich.fillRect(130, 1, 50, 320, WEISS);
  Bereich.fillRect(130, 1, 50, 320 - BalkenPoti, SCHWARZ);

  Bereich.setCursor(70, tft.width() / 2 - AbstandMarkierung);
  Bereich.setFont(&FreeSans12pt7b); 

  // je nach Wert ADCMax Zahlen anzeigen
  if (ADCMax == 4096) Bereich.print("3000");
  else  Bereich.print("750");
  Bereich.drawLine(tft.height() / 2, tft.width() / 2 - AbstandMarkierung, 50, tft.width() / 2 - AbstandMarkierung, WEISS);

  Bereich.setCursor(70, tft.width() / 2 + 40);
  if (ADCMax == 4096) Bereich.print("2000");
  else Bereich.print("500");
  Bereich.drawLine(tft.height() / 2, tft.width() / 2 + AbstandMarkierung, 50, tft.width() / 2 + AbstandMarkierung, WEISS);

  Bereich.setCursor(70, tft.width() / 2 + AbstandMarkierung * 3);
  if (ADCMax == 4096) Bereich.print("1000");
  else Bereich.print("250");
  Bereich.drawLine(tft.height() / 2, tft.width() / 2 + AbstandMarkierung * 3, 50, tft.width() / 2 + AbstandMarkierung * 3, WEISS);

  // GFXcanvas anzeigen
  tft.drawBitmap(0, 0, Bereich.getBuffer(), Bereich.width(), Bereich.height(), WEISS, SCHWARZ);
}

TFT mit 160×128 Pixeln

#include "Adafruit_ST7735.h"

// Schriftarten einbinden
#include "Fonts/FreeSans9pt7b.h"
#include "Fonts/FreeSans12pt7b.h"

// Wemos D1 Mini
// #define TFT_CS D8
// #define TFT_RST D1
// #define TFT_DC D2

// ESP32-WROOM
// #define TFT_CS 5
// #define TFT_RST 4 
// #define TFT_DC 2

// Farben
#define SCHWARZ    0x0000
#define WEISS      0xFFFF 

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

// GFXcanvas-Objekt erstellen: Höhe 128 Pixel, Breite 160 Pixel
GFXcanvas1 Bereich(128, 160);

// analogen Pin anpassen
int Poti = A0;

// maximalen Wert des ADC anpassen
// ESP32: 4096, ESP8266: 1024
int ADCMax = 4096;

/*
  Abstand der Markierung von der Mitte des TFTs
  der ADC liefert keine lienear verlaufenden Werte
  der Abstand kann angepasst werden
*/
int AbstandMarkierung = 20;

void setup()
{
  // TFT starten
  tft.initR(INITR_BLACKTAB);

  // Rotation anpassen
  tft.setRotation(0);

  // schwarzer Hintergrund
  tft.fillScreen(SCHWARZ);
}

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

  // analogen Wert lesen
  int WertPoti = analogRead(Poti);

  // analogen Wert anzeigen
  Bereich.setFont(&FreeSans12pt7b); 
  Bereich.setCursor(10, 20);  
  Bereich.print(WertPoti);

  // analogen Wert auf die Höhe des TFTs übertragen
  int BalkenPoti = map(WertPoti, 0, ADCMax, 0, 160);

  /*
    bei gedrehtem Bildschirm wird der Balken von oben nach unten angezeigt
    zuerest maximalen Wert weiß füllen
    anschließend vom maximalen Wert den gemessenen Wert abziehen
    und schwarz füllen
  */
  Bereich.fillRect(80, 1, 30, 160, WEISS);
  Bereich.fillRect(80, 1, 30, 160 - BalkenPoti, SCHWARZ);

  Bereich.setCursor(30, tft.width() / 2 - AbstandMarkierung);
  Bereich.setFont(&FreeSans9pt7b); 

  // je nach Wert ADCMax Zahlen anzeigen
  if (ADCMax == 4096) Bereich.print("3000");
  else Bereich.print("750");
  Bereich.drawLine(tft.height() / 2, tft.width() / 2 - AbstandMarkierung, 50, tft.width() / 2 - AbstandMarkierung, WEISS);

  Bereich.setCursor(30, tft.width() / 2 + AbstandMarkierung);

  if (ADCMax == 4096) Bereich.print("2000");
  else Bereich.print("500");
  Bereich.drawLine(tft.height() / 2, tft.width() / 2 + AbstandMarkierung, 50, tft.width() / 2 + AbstandMarkierung, WEISS);

  Bereich.setCursor(30, tft.width() / 2 + AbstandMarkierung * 3);

  if (ADCMax == 4096) Bereich.print("1000");
  else Bereich.print("250");
  Bereich.drawLine(tft.height() / 2, tft.width() / 2 + AbstandMarkierung * 3, 50, tft.width() / 2 + AbstandMarkierung * 3, WEISS);

  // GFXcanvas anzeigen
  tft.drawBitmap(0, 0, Bereich.getBuffer(), Bereich.width(), Bereich.height(), WEISS, SCHWARZ);
}

Letzte Aktualisierung: