Früher gab es in einigen Häusern kleine Wetterstationen, die in Form von Kugeln die Luftfeuchtigkeit, den Luftdruck und die Temperatur für das betreffende Gebiet anzeigten. Diese Kugeln wurden in Tafeln eingerahmt und an den Wänden aufgehängt. Mit der Zeit und der technischen Entwicklung gerieten diese Instrumente in Vergessenheit, da die Nachrichtensendungen und das Internet meteorologische Informationen für das ganze Land boten.
Mit diesem Projekt werden wir dieses praktische Instrument wiederbeleben, indem wir eine elektronische Wetterstation im Vintage-Stil herstellen. Es handelt sich um eine Wetterstation vom Typ Springfield mit Holzimitation. Dieses Wetterinstrument ist vertikal und wird vier Zifferblätter haben. Die obere Anzeige zeigt die aktuelle Uhrzeit an, die zweite bietet ein mögliches Bild des Himmelszustands entsprechend dem Luftdruck, dem Tag und Datum und dem Mondstand. Die dritte zeigt die Temperatur in Grad Celsius und den Prozentsatz der Luftfeuchtigkeit an und die vierte und letzte den Luftdruck in hPa. Ähnlich wie bei den alten analogen Instrumenten werden die Werte mit Zeigern dargestellt.

Für die Zifferblätter werden runde 1,28-Zoll-TFT-Displays vom Typ GC901 eingesetzt. Das vielseitige Modul DHT-22 wird zur Messung von Temperatur und Luftfeuchtigkeit und das Modul GY-68 BMP180 zur Messung des atmosphärischen Drucks verwendet. Das RTC-Modul DS3231 wird verwendet, um die aktuelle Stunde und Minuten, sowie das aktuelle Datum zu erhalten. Diese Module werden mit dem MB102-Netzteil für Breadboards gespeist, da man die Ausgänge auf 5 VDC und 3,3 VDC konfigurieren kann, wobei letzteres für die Stromversorgung der Module verwendet wird.
Dieses Projekt wurde in drei Teile gegliedert, um einen einfachen Überblick über den Fortschritt zu erhalten, von der Erfassung der Sensorwerte über die Erstellung der „Kugeln“ mit den Werten bis hin zum abschließenden Projekt mit den vier Displays.
Im ersten Teil werden die Sensoren und der Mikrocontroller AZ-ATmega328 verwendet, um die Werte zu erhalten und sie auf den Bildschirmen anzuzeigen. Im zweiten Teil wird die Darstellung dieser Methoden auf die Anzeige mit den Messbereichen geändert und im dritten Teil wird der Mikrocontroller auf einen ESP-32 Dev Kit C geändert, sowie ein neuer Bildschirm hinzugefügt, der den Zustand des Himmels, das Datum, den Wochentag und den Zustand des Mondes je nach Tag des Jahres anzeigt. Der Mikrocontroller muss wegen des Speichers geändert werden. Der Sketch übersteigt die Speicherkapazität des AZ-ATmega328. Außerdem kann der Nutzer neue Funktionen in das Projekt implementieren.
Verwendete Hardware
- 1 Mikrocontroller Board AZ-ATmega328-Board mit USB-Kabel
- 3 GC9A01 1,28 Zoll Rundes LCD-TFT-Display
- 1 DHT22 AM2302 Temperatursensor und Luftfeuchtigkeitssensor mit Platine und Kabel kompatibel
- 1 GY-68 BMP180 Barometrischer Luftdruck und Temperatur Sensor
- 1 Real Time Clock RTC DS3231 I2C Echtzeituhr
- 1 SYB-1660 Lötfreies Breadboard Protoboard | Breadboard-Kit | Tie-Point 1660 ZY-204 | 4 Strombahnen
- 1 MB102 Breadboard Netzteil Adapter Power Supply Modul 3.3V/5V
- Jumper Wire Kabel 40 STK. je 20 cm M2M Male to Male
Benötigte Software, Bibliotheken und Sketch
- Arduino-IDE
- Wire-Bibliothek (Wire.h, diese Bibliothek ist in der Arduino IDE enthalten)
- SPI-Bibliothek (SPI.h, diese Bibliothek ist in der Arduino IDE enthalten)
- Adafruit GFX-Bibliothek (über den Boardverwalter, Adafruit_GFX.h)
- Adafruit GC9A01A-Bibliothek (über den Boardverwalter, Arduino Adafruit_GC9A01A.h)
- BMP180-Bibliothek (Download der Bibliothek von AZ-Delivery)
- RTClib.h-Bibliothek (Adrafruit/RTClib.h)
- DHT.h-Bibliothek (Adafruit/DHT-sensor-library)
- vintage_weather_ATmega328_characters.ino
Schaltung und Beschreibung der verwendeten Module


Zur Ermittlung der Temperatur- und Luftfeuchtigkeitswerte wurde das Modul DHT22 AM2302 verwendet, dessen OUT-Signal-Pin mit dem Pin D9 des Mikrocontrollers verbunden wird. Zur Messung des atmosphärischen Drucks wird das Barometermodul BMP180 verwendet und um die aktuelle Uhrzeit und das Datum zu erhalten, wird das RTC-Modul DS3231 Real Time Clock eingesetzt. Diese beiden Module kommunizieren mit dem Mikrocontroller über den I2C-Bus. Die dazugehörigen SDA- und SCL-Pins der Module sind mit den Pins A4 und A5 des AZ-ATmega328-Mikrocontrollers verbunden. Die Tatsache, dass die beiden Module mit denselben Pins verbunden sind, stellt kein Problem dar, da jedes Modul eine eindeutige Adresse hat, auf die der Mikrocontroller zugreifen kann. In diesem Fall sind diese Adressen (BMP180: 0x77 und DS3231: 0x68) in den Bibliotheken definiert, die am Anfang des Sketches implementiert werden.
Für die Visualisierung der Messwerte der vorherigen Module werden mehrere 1.28 Zoll GC9A01 verwendet, die mit dem Mikrocontroller über den SPI-Bus kommunizieren. Um den Bildschirm auszuwählen, auf dem jeder Messwert der Module angezeigt werden soll, müssen die CS-Pins (Chip Select) jedes Bildschirms mit einem eigenen Pin des Mikrocontrollers verbunden werden. Die anderen Pins der Bildschirme RST (Reset), DC (Daten), SDA (Mosi), SCL (Clock) werden mit denselben Pins des Mikrocontrollers verbunden.
Die Konfiguration der Ausgangsspannung des MB102-Netzteils mit Hilfe der Jumper muss beachtet werden. Die Pins OFF und 3,3V werden so gejumpert, dass am Ausgang für die Module eine Ausgangsspannung von 3,3VDC anliegt.
Beschreibung der Funktionsweise des Projekts und Sketch der ersten Phase
Sobald die Module initialisiert sind, senden sie kontinuierlich die erhaltenen Messungen an den Mikrocontroller, der sie mit alphanumerischen Zeichen auf den Bildschirmen anzeigt. Um den Bildschirm auszuwählen, auf dem jeder Wert der Module angezeigt wird, muss er über den Pin des Mikrocontrollers ausgewählt werden.
Das erste, was immer zu Beginn eines Sketches für ein beliebiges Projekt getan werden sollte, ist die Aufnahme der notwendigen Bibliotheken in den Abschnitt der Definition der globalen Variablen, um in der Lage zu sein, die verwendeten Module zu verwenden.
Die erste hinzuzufügende Bibliothek ist < Wire.h>, diese Bibliothek ermöglicht die Kommunikation zwischen Geräten über den I2C-Bus, der vom Barometermodul BMP180 und der DS3231-Uhr verwendet wird. Die nächste hinzuzufügende Bibliothek ist "SPI.h". Diese Bibliothek ermöglicht die Kommunikation mit Geräten mit SPI-Pins, wie z. B. TFT-Bildschirmen, wobei der Mikrocontroller das Master-Gerät ist. Die nächste Bibliothek ist "Adafruit_GFX.h". Dies ist die Haupt-Grafikbibliothek für Displays. Sie stellt die notwendigen Methoden zum Zeichnen von primitiven Grafiken (Punkte, Linien, Kreise, etc.) zur Verfügung. Die vierte hinzugefügte Bibliothek ist "Adafruit_GC9A01A.h". Sie bietet die notwendige Konfiguration und Unterstützung für den GC9A01A Display-Treiber. Die Bibliotheken < BMP180.h>, die für die Arbeit mit dem Barometermodul benötigt wird, "RTClib.h" für das Uhrenmodul und <DHT.h> für das DHT22 Temperatur- und Feuchtigkeitsmodul folgen danach.
#include <Wire.h>
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_GC9A01A.h"
#include <BMP180.h>
#include "RTClib.h"
#include <DHT.h>
Die nächsten vier Zeilen sind Konstanten, die verwendet werden, um die TFT-Display-Objekte zu implementieren. Es werden die Nummern des Mikrocontroller-Pins, über den die Daten an die Displays gesendet werden mit tft_dc 7 und tft_cs_pressure 10 definiert, tft_cs_clock 2 und tft_cs_temperature 3 definieren die Mikrocontroller-Pins für die Auswahl des Bildschirms, auf dem die Informationen der einzelnen Sensoren angezeigt werden sollen. Defines sind Präprozessorbefehle, dessen Werte zu Beginn des Kompilierungsprozesses im Quellcode ersetzt werden, wo der Name eingetragen wurde.
#define tft_dc 7
#define tft_cs_pressure 10
#define tft_cs_clock 2
#define tft_cs_temperature 3
Nun muss für jeden Bildschirm ein Objekt erstellt werden, um mit ihnen arbeiten zu können. Dazu wird ein Name deklariert und als Argumente werden die Pins des Mikrocontrollers, an den der Bildschirm angeschlossen ist. Die Namen der Konstanten, die wir zuvor definiert haben, werden hier eingetragen.
Adafruit_GC9A01A tft_pressure(tft_cs_pressure, tft_dc);
Adafruit_GC9A01A tft_clock (tft_cs_clock, tft_dc);
Adafruit_GC9A01A tft_temperature (tft_cs_temperature, tft_dc);
Um Temperatur- und Feuchtigkeitsdaten vom DHT22-Modul zu empfangen, muss ein Sensorobjekt implementiert und die notwendigen Variablen definiert werden. Der erste Schritt besteht darin, eine Konstante zu definieren, die den Mikrocontroller-Pin angibt, an den der Datenpin des Moduls angeschlossen wird, sowie eine weitere Konstante, die das Sensormodell angibt. Dann wird ein Modulobjekt mit dem Namen dht implementiert, als Parameter müssen der Mikrocontroller-Pin, an den der Signalpin angeschlossen wurde und das Sensormodell angegeben werden. Diese Parameter werden durch die definierten Konstanten wiedergegeben.
#define dht_pin 9
#define dht_type DHT22
DHT dht(dht_pin, dht_type);
Nach der Erstellung des Modulobjekts müssen Variablen zur Speicherung der Daten definiert werden. Um sie auf dem Bildschirm anzeigen zu können, müssen sie zunächst in Zeichenketten umgewandelt werden. So werden zwei Variablen definiert, um die vom Sensor gelesenen Temperatur- und Luftfeuchtigkeitsdaten zu speichern, deren Namen einfach zu verstehen sind.
float humi;
float temp;
Um die Umwandlung der numerischen Werte der Messwerte in Zeichenketten für die Anzeige auf dem Bildschirm zu speichern, werden zwei Arrays definiert, die Zeichen (char) enthalten müssen. Ein Array für jeden Sensor. Diese Arrays müssen mit einer Länge von fünf Zeichen definiert werden, um die Messwerte zu speichern.
char humidity[5];
char temperature[5];
Für das barometrische Modul BMP180 müssen ähnliche Schritte durchgeführt werden. Zuerst wird ein Objekt für den Sensor implementiert. In diesem Fall muss nur ein Name angegeben werden. Es wird bmp180 genannt. Es muss auch eine Variable definiert werden, um den Wert zu speichern und ein Array, um die Umwandlung des numerischen Wertes in eine Zeichenkette zu speichern. In diesem Fall muss sie eine Länge von 6 Zeichen haben.
BMP180 bmp180;
float pressu;
char pressure[6];
Es bleibt nur noch ein Objekt zu implementieren und die Variablen zu definieren, um die Daten des RTC DS3231-Moduls zu verwalten und den Wochentag, die Stunde und die Minuten anzuzeigen. Als erstes muss ein Objekt des Moduls DS3231 mit dem Namen rtc implementiert werden. Um die Wochentage auf dem Bildschirm anzuzeigen, muss ein zweidimensionales Array mit Zeichen (char) definiert werden, das sieben Zeilen (eine für jeden Wochentag) und eine Länge von 12 Zeichen für den Namen des Tages haben muss.
RTC_DS3231 rtc;
char daysOfTheWeek[7][12] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
Die aktuelle Stunde und die Minuten werden in zwei Variablen gespeichert. Auch hier müssen zwei Arrays (char) definiert werden, die die Zeichen der Stunde und der Minuten enthalten, die auf dem TFT-Bildschirm angezeigt werden sollen. Diese Arrays müssen eine Länge von 2 Zeichen haben.
int time_h;
int time_m;
char time_hours[2];
char time_minutes[2];
Nach der Einbindung der erforderlichen Bibliotheken, der Definition der Variablen und der Implementierung der Modulobjekte, müssen diese Module initialisiert und ihre Anfangsbedingungen festgelegt werden, was in der Methode setup() geschieht. Als erstes muss der Serial Monitor initialisiert werden, um die Informationen über mögliche Fehler und Meldungen sowohl bei der Initialisierung der Module, als auch bei der Ausführung des Sketches anzuzeigen.
Serial.begin(9600);
Dann werden die TFT-Bildschirme mit der begin-Methode des Objekts jedes Bildschirms initialisiert und die yield()-Methode wird aufgerufen. Diese Methode wird verwendet, um die nächste Zeile des Codes auszuführen, während die vorherigen Zeilen ausgeführt werden.
tft_pressure.begin();
tft_clock.begin();
tft_temperature.begin();
yield();
Beim Anlegen der Spannung an den Mikrocontroller oder beim Zurücksetzen des Mikrocontrollers müssen die Anfangsbedingung eingestellt werden. Die Hintergrundfarbe des Displays wird eingestellt und die Namen und Maßeinheiten werden ausgegeben. Der erste Bildschirm, der programmiert werden muss, ist derjenige, der die Luftfeuchtigkeit und die Temperatur anzeigen wird. Als erstes wird die Hintergrundfarbe des Bildschirms mit tft_temperature.fillScreen(GC9A01A_BLACK) auf schwarz gesetzt und die notwendigen Methoden ausgeführt, um den Text "Humidity %" (Luftfeuchtigkeit) anzuzeigen. Der Cursor wird mit tft_temperature.setCursor(50, 70) gesetzt, die Textfarbe auf Blau mit tft_temperature.setTextColor(GC9A01A_BLUE), die Textgröße auf 2 mit tft_temperature.setTextSize(2) und der Text mit tft_temperature.println("Humidity %") ausgegeben. Anschließend wird noch die Methode yield() ausgeführt.
tft_temperature.fillScreen(GC9A01A_BLACK);
tft_temperature.setCursor(50, 70);
tft_temperature.setTextColor(GC9A01A_BLUE);
tft_temperature.setTextSize(2);
tft_temperature.println("Humidity %");
yield();
Gleiches geschieht dann mit “Temperature Celsius” (Temperatur), “Pressure hPa” (Druck), “Date” (Datum) und “Time” (Uhrzeit) in den nachfolgenden Zeilen. Sie können die Farben und die jeweilige Position hier anpassen.
Sobald die Anfangskonfiguration jedes Bildschirms definiert ist, müssen die drei Module, die die Daten liefern, initialisiert werden. Das erste ist das DHT22-Sensormodul. Rufen Sie einfach die Methode begin() des für diesen Sensor definierten Objekts auf.
dht.begin();
Der zweite Sensor ist das Barometermodul BMP180 mit dem Aufruf der init()-Methode des bmp180-Objekts. Es wird vom seriellen Monitor mit Serial.println("BMP180 init") gemeldet, dass dieses Modul initialisiert wird, wenn der Schritt erfolgreich durchgeführt wurde.
bmp180.init();
Serial.println("BMP180 init");
if (!bmp180.hasValidID()) {
Serial.println("Error - please check the BMP180 board!");
}
Das letzte Modul ist das RTC DS3231-Uhrenmodul. Es wird mit der Methode begin() initialisiert. Die nächsten beiden Zeilen dienen der Konfiguration des aktuellen Datums und der Uhrzeit. Die Methode rtc.adjust(DateTime(F(__DATE__), F(__TIME__)) ruft die Daten ab, die das Modul in seinem Speicher abgelegt hat. Wenn Sie das Datum oder die Uhrzeit anpassen möchten, müssen Sie die vorherige Zeile auskommentieren und den Kommentar zur Zeile rtc.adjust(DateTime(2024, 9, 3, 0, 0, 33, 0)) entfernen. Dort können Sie die Werte für Jahr, Monat, Tag, Stunde, Minute und Sekunde manuell in die Argumente eingeben.
rtc.begin();
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// rtc.adjust(DateTime(2024, 9, 1, 0, 33, 0));
Damit ist die Definition und Analyse der Methode setup() abgeschlossen. Es folgt die Methode loop(), die kontinuierlich ausgeführt wird. In dieser Methode werden zunächst die Temperatur und die Luftfeuchtigkeit mit den Methoden readTemperature() und readHumidity() des für das DHT-Modul erstellten Objekts ausgelesen. Anschließend werden sie in den definierten Variablen gespeichert und es wird geprüft, ob diese beiden Variablen Daten enthalten. Wenn nicht, wird der Fehler beim Ablesen der Sensoren über den seriellen Monitor gemeldet.
temp = dht.readTemperature();
humi = dht.readHumidity();
if (isnan(humi) || isnan(temp)) {
Serial.println("DHT sensor reading failure !!!!");
}
Danach wird mit der Methode getPressure() der vom Barometer BMP180 gemessene Wert des atmosphärischen Drucks ermittelt und in der bereits definierten Variablen pressu gespeichert.
pressu = bmp180.getPressure();
Die letzten zu ermittelnden Werte sind die Datums- und Zeitwerte des DS3231-RTC-Moduls, für die die now()-Methode des DS3231-Modulobjekts verwendet wird. Um die aktuelle Uhrzeit zu erhalten, werden die Funktionen now.hour() und now.minute() aufgerufen und ihre Werte in den Variablen time_ h und time_m für Stunde und Minute gespeichert.
DateTime now =rtc.now();
time_h = now.hour();
time_m = now.minute();
Wenn alle Werte ermittelt und gespeichert wurden, müssen sie auf den entsprechenden Bildschirmen angezeigt werden. Die ersten Werte sind Temperatur und Luftfeuchtigkeit auf dem Bildschirm mit der Bezeichnung tft_temperature. Um die Daten korrekt anzeigen zu können, müssen die alten Daten auf dem Bildschirm zunächst "gelöscht" werden, d.h. die Daten werden in der Hintergrundfarbe des Bildschirms angezeigt und die neuesten Daten in der entsprechenden Farbe. Um die alten Daten zu löschen, zeigt man sie wieder an, aber mit der Farbe, die als Hintergrund des Bildschirms konfiguriert ist. Im Fall des Bildschirms für Temperatur und Luftfeuchtigkeit ist der Hintergrund schwarz, also werden zuerst die Werte der Koordinaten konfiguriert, der Text wird in schwarz konfiguriert, die Größe des Textes wird 2 sein und die Zeichen des Arrays mit dem Text des umgewandelten Wertes werden ausgegeben, die yield()-Methode wird auch hinzugefügt. Mit dieser „Täuschung“ wird der Inhalt des Displays gelöscht.
tft_temperature.setCursor(90, 100);
tft_temperature.setTextColor(GC9A01A_BLACK);
tft_temperature.setTextSize(2);
tft_temperature.println(humidity);
yield();
Um den neuen Wert auf dem Bildschirm darzustellen, wird er zunächst durch Auslesen des Moduls mit readHumidity() ermittelt. Er wird in der am Anfang des Sketches definierten Variablen humi vom Typ float gespeichert. Der Zahlenwert wird in einen String umgewandelt und in der Variablen convert_humi vom Typ String mit String convert_humi = String(humi) gespeichert und mit convert_humi.toCharArray(humidity, 5) in ein Zeichenarray umgewandelt. Anschließend wird der Cursor mit der Methode setCursor() an den Koordinaten X = 90 und Y = 100 positioniert, die blau darzustellenden Zeichen mit setTextColor() konfiguriert, die Schriftgröße mit setTextSize(2) auf 2 gesetzt und schließlich die darzustellenden Zeichen des Arrays humidity ausgegeben.
String convert_humi = String(humi);
convert_humi.toCharArray(humidity, 5);
tft_temperature.setCursor(90, 100);
tft_temperature.setTextColor(GC9A01A_BLUE);
tft_temperature.setTextSize(2);
tft_temperature.println(humidity);
yield();
Um die Werte der Temperatur, des Luftdrucks und der aktuellen Uhrzeit samt Wochentag anzuzeigen, müssen die gleichen Schritte durchgeführt werden. Im Quellcode sind die Schritte beschrieben.

Ausblick
Damit ist das Ziel des ersten Teils dieses Projekts erreicht und wir sehen die Sensordaten auf den Displays. Es soll am Ende aber wie ein altes, analoges Barometer aussehen. Darum kümmern wir uns im zweiten Teil.