4. Projekt Raumklima-Anzeige mit RTC, DHT11 

Temperatur, Luftfeuchte, Helligkeit, Uhrzeit und Datum

4.1 Eine DS1307-RTC und DHT11 Wetterstation mit Realtime-Clock Uhrzeit und Datum sowie Raumtemperatur und Luftfeuchtigkeit auf TC1602 und ST7735 1,8" TFT

Basierend auf Übung 3.3 (beide Displays) wird hier ein DTH11 Temperatur & Luftfeuchte-Sensor und eine DS1307 RTC Real Time Clock ergänzt. Die Werte werden über den Serial Monitor und beiden Displays ausgegeben.

Hier der Programmcode:
#include <Adafruit_GFX.h>      // Adafruit graphics Bibliothek
#include <Adafruit_ST7735.h>   // Adafruit ST7735 TFT Bibliothek
#include <SPI.h>               // Für Hardware-SPI
#include "RTClib.h"            // Adafruit RTC library
#include <LiquidCrystal.h>     // LCD-Bibliothek
#include <DHT.h>               // DHT11 Bibliothek
#include <Wire.h>

// -------------------- DHT11 --------------------
#define DHTPIN   2   //A11 beim Platinenprototyp V01 derzeit
#define DHTTYPE  DHT11
DHT dht(DHTPIN, DHTTYPE);

// -------------------- LCD 16x2 ----------------
// Arduino Mega: Pins 14–19 sind die digitalen Aliasse von A0–A5
LiquidCrystal lcd(14, 15, 16, 17, 18, 19);   
//(A0, A1, A2, A3, A4, A5); beim Platinenprototyp V01 derzeit 



// -------------------- TFT ST7735 (SPI) --------
// Arduino Mega SPI-Pins:
// MOSI = 51, MISO = 50, SCK = 52
// SS (Slave-Select) = 53
#define TFT_RST   4     // Reset-Pin des TFT  //A7  beim Platinenprototyp V01 derzeit 

#define TFT_CS    3      // Chip-Select               //A6  beim Platinenprototyp V01 derzeit 

#define TFT_DC    5     // Data/Command      //A8  beim Platinenprototyp V01 derzeit 



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

// -------------------- RTC DS1307 --------------
RTC_DS1307 rtc;
DateTime now;

// -------------------- Prototypen --------------
void TEMP_HUM_display();
void RTC_display();

// ------------------------------------------------
// SETUP
// ------------------------------------------------
void setup() {
  // Serielle Schnittstelle
  Serial.begin(9600);

  // DHT starten
  dht.begin();

  // LCD initialisieren
  lcd.begin(16, 2);
  lcd.clear();

  // SS-Pin des SPI als Ausgang setzen, damit der Mega sicher Master bleibt
  pinMode(53, OUTPUT);
  digitalWrite(53, HIGH);

  // RTC initialisieren
  if (!rtc.begin()) {
    Serial.println("RTC nicht gefunden!");
  }

  // Achtung: Diese Zeile setzt bei jedem Reset die Uhrzeit neu auf die Compile-Zeit.
  // Für den finalen Betrieb auskommentieren, sobald die RTC einmal korrekt gestellt wurde.
  // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

  // TFT initialisieren
  tft.initR(INITR_BLACKTAB);
  tft.fillScreen(ST7735_WHITE);

  // Zwei horizontale Trennlinien wie in deinem Original
  tft.drawFastHLine(0, 44,  tft.width(), ST7735_BLUE);
  tft.drawFastHLine(0, 102, tft.width(), ST7735_BLUE);

}

// ------------------------------------------------
// TEMP & HUM Anzeige (mit Änderungserkennung)
// ------------------------------------------------
void TEMP_HUM_display() {
  static float lastTemp = NAN;
  static float lastHum  = NAN;

  float hum = dht.readHumidity();
  float temp = dht.readTemperature();

  // Fehlerbehandlung
  if (isnan(hum) || isnan(temp)) {
    Serial.println("Fehler beim Lesen des DHT11");
    return;
  }

  // Nur aktualisieren, wenn sich Werte merklich geändert haben
  if ( (isnan(lastTemp) || fabs(temp - lastTemp) > 0.1) ||
       (isnan(lastHum)  || fabs(hum  - lastHum)  > 0.5) ) {

    // --- TFT ---
    tft.setTextSize(2);
    tft.setTextColor(ST7735_BLUE, ST7735_WHITE);

    // Temperatur-Bereich sauber löschen und neu zeichnen
    // Bereich grob: x=22..140, y=49..73
    tft.fillRect(22, 49, 110, 26, ST7735_WHITE);
    tft.setCursor(22, 53);
    tft.print(temp, 1);     // 1 Nachkommastelle

    tft.setCursor(99, 53);
    tft.print("C");
    tft.setCursor(87, 49);
    tft.print("o");

    // Luftfeuchte-Bereich löschen
    // Bereich grob: x=22..140, y=76..100
    tft.fillRect(22, 76, 110, 26, ST7735_WHITE);
    tft.setCursor(22, 80);
    tft.print(hum, 1);
    tft.setCursor(87, 80);
    tft.print("%");

    // --- Seriell ---
    Serial.print("Luftfeuchtigkeit: ");
    Serial.print(hum);
    Serial.println(" %");

    Serial.print("Temperatur: ");
    Serial.print(temp);
    Serial.println(" Grad Celsius");

    // --- LCD ---
    // Temperatur (Zeile 0, Spalten 0–7)
    lcd.setCursor(0, 0);
    lcd.print("        ");      // alten Bereich löschen
    lcd.setCursor(0, 0);
    lcd.print(temp, 1);
    lcd.setCursor(5, 0);
    lcd.print((char)223);       // Grad-Symbol
    lcd.print("C");

    // Luftfeuchte (Zeile 1, Spalten 0–7)
    lcd.setCursor(0, 1);
    lcd.print("        ");
    lcd.setCursor(0, 1);
    lcd.print(hum, 1);
    lcd.setCursor(6, 1);
    lcd.print("%");

    lastTemp = temp;
    lastHum  = hum;
  }
}

// ------------------------------------------------
// RTC Anzeige (mit Änderungserkennung)
// ------------------------------------------------
void RTC_display() {
  static uint8_t prevSecond = 60;
  static uint8_t prevDay    = 0;
  static uint8_t prevMonth  = 0;
  static uint16_t prevYear  = 0;
  static uint8_t prevDow    = 7;  // ungültig zum Start

  char buffer[11];

  // ---------------- Uhrzeit (nur bei Sekundenänderung) ----------------
  if (now.second() != prevSecond) {
    prevSecond = now.second();

    // Zeit-String erstellen
    sprintf(buffer, "%02u:%02u:%02u", now.hour(), now.minute(), now.second());

    // TFT: Zeitbereich löschen (z.B. oben mittig)
    tft.fillRect(0, 8, 160, 24, ST7735_WHITE);
    tft.setTextSize(2);
    tft.setTextColor(ST7735_RED, ST7735_WHITE);
    tft.setCursor(16, 16);
    tft.print(buffer);

    // LCD: Zeit rechts oben (z.B. Spalte 11)
    lcd.setCursor(10, 0);
    lcd.print("     ");
    lcd.setCursor(10, 0);
    lcd.print(buffer);
    lcd.setCursor(15, 0); 
    lcd.print(" ");     
  }

  // ---------------- Datum (nur bei Änderung) ----------------
  if (now.day()   != prevDay  ||
      now.month() != prevMonth ||
      now.year()  != prevYear) {

    prevDay   = now.day();
    prevMonth = now.month();
    prevYear  = now.year();

    sprintf(buffer, "%02u.%02u.%04u", now.day(), now.month(), now.year());

    // TFT: Datum-Bereich löschen
    tft.fillRect(0, 104, 160, 24, ST7735_WHITE);
    tft.setTextSize(2);
    tft.setTextColor(ST7735_BLACK, ST7735_WHITE);
    tft.setCursor(3, 112);
    tft.print(buffer);

    // LCD: Datum rechts unten
    lcd.setCursor(10, 1);
    lcd.print("     ");
    lcd.setCursor(10, 1);
    lcd.print(buffer);
  }

  // ---------------- Wochentag (nur bei Änderung) ----------------
  if (now.dayOfTheWeek() != prevDow) {
    prevDow = now.dayOfTheWeek();

    // Wochentags-Namen
    const char dow_matrix[7][10] = {
      "SONNTAG",
      "MONTAG",
      "DIENSTAG",
      "MITTWOCH",
      "DONNERST.",
      "FREITAG",
      "SAMSTAG"
    };

    // x-Positionen für schön mittig (leicht angepasst)
    const byte x_pos[7] = {18, 24, 18, 6, 8, 24, 12};

    // Bereich für Wochentag löschen (untere Zeile)
    tft.fillRect(0, 132, 160, 24, ST7735_WHITE);
    tft.setTextSize(2);
    tft.setTextColor(ST7735_BLACK, ST7735_WHITE);
    tft.setCursor(17, 138);
    tft.print(dow_matrix[prevDow]);
  }
}

// ------------------------------------------------
// LOOP
// ------------------------------------------------
void loop() {
  static unsigned long lastRTCUpdate = 0;
  static unsigned long lastDHTUpdate = 0;
  unsigned long nowMillis = millis();

  // RTC (Zeit/Datum/Tag) z.B. alle 200 ms aktualisieren
  if (nowMillis - lastRTCUpdate >= 200) {
    now = rtc.now();       // aktuelle Zeit vom RTC-Chip holen
    RTC_display();
    lastRTCUpdate = nowMillis;
  }

  // Temp/Feuchte z.B. alle 2 Sekunden lesen/anzeigen
  if (nowMillis - lastDHTUpdate >= 2000) {
    TEMP_HUM_display();
    lastDHTUpdate = nowMillis;
  }
}