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