Im ersten Teil dieses Projekts haben wir die Daten von den Sensoren und der Uhr erhalten und sie als Schriftzeichen auf den Displays dargestellt. Im zweiten Teil des Vintage-Barometers werden wir die Variablen und Methoden implementieren, die notwendig sind, um die Ablesungen der Luftfeuchtigkeit, der Temperatur, des atmosphärischen Drucks und Uhrzeit auf Zifferblättern mit Skalen darzustellen.

Die Skala, die den Wert des atmosphärischen Drucks anzeigt, ist kreisförmig. Die Druckwertpunkte mit Zahlenwert sind dicke blaue Punkte. Die Zwischenpunkte sind wesentlich kleiner, schwarz und ohne Werte. Der Name der dargestellten Größe und die Maßeinheit sind angegeben. Der Zeiger endet in einer Pfeilspitze und markiert den vom Modul BMP180 abgelesenen Druckwert.

Das Zifferblatt, das die Stunden und Minuten anzeigt, besteht aus zwei konzentrischen Kreisen, wobei ein Kreis die Stundenmarkierungen mit blauen Punkten und der andere Kreis die Minuten mit kleineren schwarzen Punkten anzeigt. Es ist das typische Zifferblatt mit Stunden in römischen Ziffern. Die Stunden und Minuten werden mit Zeigern markiert, die in Pfeilspitzen enden.

Die Temperatur- und Luftfeuchtigkeitsskala besteht aus zwei nicht konzentrischen Kreisen. Die Werteskalen sind Bögen dieser Kreise und liegen einander gegenüber. Auf diesen Bögen sind die Wertmarkierungen als Zahlen und die Wertlegenden in Rot für die Temperatur und in Blau für die Luftfeuchtigkeit dargestellt. Die Größen sind ebenfalls am oberen Rand der Skala und die Maßeinheit am unteren Rand der Skala angegeben. Die vom Sensor ermittelten Werte sind auch hier durch Pfeile gekennzeichnet.
Damit die Nadel den genauen Wert anzeigt, muss sie in dem Winkel positioniert werden, in dem die Spitze auf den Wert zeigt. Leider gibt es in den Bibliotheken des Bildschirms keine Methode, die Winkel darstellt. Also müssen wir eine Möglichkeit finden, um den Wert der Sensoren zu konvertieren und ihn im Umfang des Kreises mit Grad Radiant darzustellen. Für diese Konvertierung werden wir Operationen mit dem Sinus und Kosinus der Winkel verwenden. Damit werden wir die Koordinaten berechnen, in denen die Spitze der Nadel auf dem Bildschirm platziert werden muss.

Ein Bogenmaß ist das Maß eines zentralen Winkels eines Kreises, dessen Bogenlänge gleich seinem Radius ist. Andererseits ist der Wert von 1 Grad eines Kreises gleich 0,0174533 im Bogenmaß. Wie Sie in der Zeichnung sehen können, kann der orangefarbene Punkt des Kreises mit Hilfe von Kosinus und Sinus berechnet werden. Dieser Punkt wird eine Koordinate auf dem Bildschirm sein.
In diesem zweiten Teil werden die Kreise der Bildschirme erstellt, wobei drei Methoden verwendet werden, um die Figuren darzustellen, aus denen sich jede Anzeige der Größe zusammensetzt. Mit einer Methode wird ein Umfang oder ein Bogen mit der Werteskala dargestellt, mit einer anderen Methode wird ein kleiner Kreis dargestellt, der den Drehpunkt der Nadel darstellt. Diese beiden Methoden werden von der setup()**-Methode aus aufgerufen und eine dritte Methode stellt eine Nadel dar, die aus einer Linie und einem Dreieck am Ende besteht. Diese letzte Methode wird von der loop()**-Methode aus aufgerufen, die kontinuierlich ausgeführt wird. Die Hardware, die Software und das Komponentenschema sind die gleichen wie in Teil 1. Nur der Sketch ist ein anderer.
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_graphics.ino
Schaltung und Beschreibung der verwendeten Module

Analyse des Sketches
Wir beginnen mit der Analyse des Programmcodes. Als erstes müssen, wie im ersten Teil, die notwendigen Bibliotheken in den Abschnitt zur Definition der globalen Variablen aufgenommen werden, um die verwendeten Module nutzen zu können. In diesen Bibliotheken befinden sich die für die Messungen notwendigen Konfigurationen und Methoden. Einige Absätze werden aus Teil 1 wiederholt.
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);
Für die Kreiselemente werden vier Grundfarben verwendet: Schwarz, Blau, Rot und Weiß, wobei ihre Namen und ihr numerischer Wert in der Codierung rgb565 festgelegt werden. Der Wert jeder Farbe kann unter http://rinkydinkelectronics.com/calc_rgb565.php Rifiuto werden.
#define BLACK 0x0000
#define BLAU 0x001F
#define RED 0xF800
#define WHITE 0xFFFFFF
Nachdem die zu verwendenden Farben definiert wurden, werden zwei wichtige Variablen bzw. Konstanten definiert, um die Koordinaten der Werte auf der Werteskala und die Position der Nadel zur Anzeige des Wertes zu berechnen. Eine Variable mit dem Namen pi, die den mathematischen Wert Pi enthält. Außerdem eine Konstante mit dem Namen deg_to_rad. Sie enthält den Wert in Radiant, den 1 Grad eines beliebigen Umfangs hat.
#define deg_to_rad 0.0174532925
float pi= 3.1415926535;
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;
Bevor wir mit dem Sketch fortfahren, schauen wir uns die Koordinaten des GC9A01-Bildschirms an. Das Display ist rund, aber es wichtig zu wissen, dass sich der Punkt mit den Koordinaten X = 0 und Y = 0 in der oberen linken Ecke des rosa Quadrats im folgenden Bild befindet. D.h. der reale Bildschirm wäre ein kreisförmiger Ausschnitt eines quadratischen Bildschirms mit einer Auflösung von 240 px * 240 px.

Die Werteskala sowohl für die Luftfeuchtigkeit als auch für die Temperatur wird als Kreisbogen gezeichnet, wobei der Mittelpunkt des Luftfeuchtigkeitskreises die Koordinaten X = 89 und Y = 150 hat, während der Mittelpunkt des Kreises für die Temperaturskala die Koordinaten X = 149 und Y = 150 hat. Es wird nur der Kreisbogen gezeichnet, der notwendig ist, um die erforderliche Skala zu anzuzeigen. In der Abbildung können Sie sehen, wie die beschriebenen Kreise angeordnet sind.
Fahren wir mit dem Sketch fort. Wir definieren die Variablen für die Werteskala und die Nadelmarkierung der Temperatur. Für die anschließende Erstellung des Bogens der Temperaturskala werden die Variablen center_x_temperature und center_y_temperature vom Typ int erstellt, die die Werte der Koordinaten des Mittelpunkts des zu verwendenden Umfangs sind.
int center_x_temperature = 149;
int center_y_temperature = 150;
Das vollständige Bild der Nadel besteht aus einer Linie, die in der Mitte des Umfangs beginnt und mit einer Pfeilspitze in Form eines Dreiecks endet. Um die neue Position der Nadel darzustellen, muss zunächst der vorherige Zustand der Nadel mit der Hintergrundfarbe des Bildschirms neu gezeichnet werden. Daher werden Variablen vom Typ float definiert, die die alten Koordinaten und die neuen Koordinaten enthalten, die sich aus den neuen Werten ergeben.
float pivot_x_temperature, pivot_y_temperature, pivot_x_temperature_old, pivot_temperature_y_old;
Für die Anzeige der Werte des DHT22-Sensors werden ebenso Variablen definiert.
float p1_x_temperature, p1_y_temperature, p2_x_temperature, p2_y_temperature, p3_x_temperature, p3_y_temperature;
float p1_x_old_temperature, p1_y_old_temperature, p2_x_old_temperature, p2_y_old_temperature, p3_x_old_temperature, p3_y_old_temperature;
In den nächsten beiden Zeilen werden die Variablen arc_x_temperature und arc_y_temperature vom Typ float definiert, die die Koordinaten der Bogenzeichnung mit der Skala der Temperaturwerte enthalten.
float arc_x_temperature;
float arc_y_temperature;
Die Variable needleAngle_temperature vom Typ float wird die Position der Temperatur in Grad enthalten. Das ist der Winkel zwischen dem Wert der Temperaturen der Werteskala und der Temperatur, die die Nadel markieren soll.
float needleAngle_temperature = 0;
Die letzten beiden für die Temperatur definierten Variablen sind temperature vom Typ float, in der der vom DHT22-Sensor erfasste Wert gespeichert wird und needle_setter_temperature, ebenfalls vom Typ float, in der die von der Nadel einzustellende Temperatur gespeichert wird.
float temperature;
float needle_setter_temperature;
Für die Feuchtigkeitsdaten werden dieselben Variablen wie in den vorhergehenden Zeilen definiert, aber mit der Endung humidity.
int center_x_humidity = 89;
int center_y_humidity = 150;
float pivot_x_humidity, pivot_y_humidity, pivot_x_humidity_old, pivot_humidity_y_old;
float p4_x_humidity, p4_y_humidity, p5_x_humidity, p5_y_humidity, p6_x_humidity, p6_y_humidity;
float p4_x_old_humidity, p4_y_old_humidity, p5_x_old_humidity, p5_y_old_humidity, p6_x_old_humidity, p6_y_old_humidity;
float arc_x_humidity;
float arc_y_humidity;
float needleAngle_humidity = 0;
float humidity;
float needle_setter_humidity;
In der letzten Zeile der Definitionen für die Temperatur- und Luftfeuchtigkeitsanzeige wird die Variable radius_temperature vom Typ int definiert, mit der der Radius der Kreise festgelegt wird, die die Bögen mit der Skala der Temperatur- und Luftfeuchtigkeitswerte enthalten werden. Der Wert des Radius‘ beträgt 100 Pixel.
int radius_temperature = 100;
Die Definition der Variablen für das Barometermodul BMP180 beginnt mit der Implementierung eines Objekts für den Sensor. In diesem Fall muss nur der Name bmp180 angegeben werden. Die Variable pressu vom Typ float wird ebenfalls definiert, um den Wert des Sensors zu speichern.
BMP180 bmp180;
float pressu;
Die Werteskala für den BMP180-Sensor ist ein einziger Kreis, dessen Mittelpunkt die Mitte des 240 x 240 Pixel großen Bildschirms ist, also bei den Koordinaten X = 120 und Y = 120.
int center_x_pressure = 120;
int center_y_pressure = 120;
Es werden auch Variablen vom Typ float definiert, um die alten und neuen Koordinaten des Nadeldrehpunkts und um die Werte der Koordinaten der Position des Dreiecks der Pfeilspitze zu speichern, die den Wert des atmosphärischen Drucks markieren.
float pivot_x_pressure, pivot_y_pressure, pivot_x_old_pressure, pivot_y_old_pressure;
float p1_x_pressure, p1_y_pressure, p2_x_pressure, p2_y_pressure, p3_x_pressure, p3_y_pressure;
float p1_x_old_pressure, p1_y_old_pressure, p2_x_old_pressure, p2_y_old_pressure, p3_x_old_pressure, p3_y_old_pressure;
Die Werteskala wird numerische Punkte für die Druckwerte und Legenden enthalten. Um diese Punkte auf dem Bildschirm darzustellen, werden zwei Variablen für die Koordinaten definiert. Für den Umfang der Werteskala definieren wir eine Variable mit dem Radius.
float arc_x_pressure;
float arc_y_pressure;
int radius_pressure = 65;
Um den Druckwert im Bogenmaß zu speichern und ihn in Punkten auf der Werteskala darstellen zu können, wird die Variable needleAngle_pressure definiert. Außerdem wird eine Variable needle_setter_pressure definiert, um den Wert des Drucks zu speichern, den die Nadel markieren wird.
float needleAngle_pressure = 0;
float needle_setter_pressure;
Die Variable pressure_scale wird für die Druckwerte in der Werteskala definiert und um die Skala auf dem Bildschirm darstellen zu können. Die letzte Variable für diesen Abschnitt, die definiert werden muss, ist pressure_module_calibration. Sie wird den Unterschied widerspiegeln, der zwischen dem Messwert des BMP180-Moduls und dem Messwert eines kalibrierten Sensors bestehen kann.
int pressure_scale;
int pressure_module_calibration = 140;
Nun müssen nur noch die Variablen implementiert werden, die für die Verwaltung der Daten des RTC DS3231-Moduls benötigt werden, um die Stunden und Minuten auf dem Bildschirm anzuzeigen. Zunächst wird ein Objekt namens rtc des RTC DS3231-Moduls implementiert, um die Stunden- und Minutendaten zu erfassen. In diesem zweiten Teil werden die Wochentage nicht angezeigt, aber das daysOfTheWeek-Array, das bereits in Teil 1 erstellt wurde, wird belassen. Dieses Array wird in Teil 3 erneut verwendet.
RTC_DS3231 rtc;
char daysOfTheWeek[7][12] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
Es wird eine Variable zum Speichern der Stundendaten und zwei weitere Variablen zum Speichern der aktualisierten Minutendaten, sowie der vorherigen Minutendaten erstellt.
float time_h;
float time_m;
float time_m_old;
Das Ziffernblatt besteht aus zwei konzentrischen Kreisen und zwei Zeigern, ein Zeiger für die Stunden und einer für die Minuten. Der Mittelpunkt dieser Kreise wird erneut die Mitte des Bildschirms sein, also sind auch hier die Koordinaten für den Mittelpunkt der Kreise X = 120 und Y = 120 Pixel.
int center_x_clock = 120;
int center_y_clock = 120;
Die folgenden Variablen werden für die alten und neuen Koordinaten des Drehpunkts der Nadeln erstellt, um den kleinen Kreis des Drehpunkts zu zeichnen. Wenn er nicht neu gezeichnet wird, bleibt die Markierung der vorherigen Nadelposition leer, dies wird in Teil 3 verwendet.
float pivot_x_clock, pivot_y_clock, pivot_x_old_clock, pivot_y_old_clock;
Wie auch für die vorangegangenen Bildschirme müssen Variablen für die Spitzen der beiden Zeiger (Stunden und Minuten) definiert werden.
float p1_x_clock, p1_y_clock, p2_x_clock, p2_y_clock, p3_x_clock, p3_y_clock;
float p1_x_old_clock, p1_y_old_clock, p2_x_old_clock, p2_y_old_clock, p3_x_old_clock, p3_y_old_clock;
float p4_x_clock, p4_y_clock, p5_x_clock, p5_y_clock, p6_x_clock, p6_y_clock;
float p4_x_old_clock, p4_y_old_clock, p5_x_old_clock, p5_y_old_clock, p6_x_old_clock, p6_y_old_clock;
Außerdem werden zwei Variablen definiert, um die Koordinaten der Position der Minuten und Stunden auf dem Ziffernblatt, sowie den Radius des Umfangs der Werteskala zu speichern.
float arc_x_clock;
float arc_y_clock;
int radius_clock = 72;
In den folgenden Variablen werden Stunden und Minuten im Bogenmaß, die Werte der Stunden und Minuten für die Markierung auf dem Zifferblatt sowie die Daten der Stunden- und Minutenzeiger gespeichert.
float needleAngle_hours_clock = 0;
float needleAngle_minutes_clock = 0;
float hours_dial;
float minutes_dial;
float needle_setter_hours_clock;
float needle_setter_minutes_clock;
Nun muss die Methode setup()** implementiert werden. Das erste, was in dieser Methode gemacht wird, ist die Initialisierung des seriellen Monitors und das Senden einer Initialisierungsnachricht für Bildschirme und Sensoren.
Serial.begin(9600);
Serial.println("Initialization of the set of sensors and displays.");
Der erste Bildschirm, der mit der Methode begin()** des erstellten Objekts initialisiert wird, ist derjenige, der die Temperatur- und Luftfeuchtigkeitsdaten anzeigt. Die Drehung des Displays wird mit der Methode setRotation(0)** konfiguriert. Der Bildschirmhintergrund ist weiß und wird mit der Methode fillScreen(WHITE)** festgelegt.
tft_temperature.begin();
tft_temperature.setRotation(0);
tft_temperature.fillScreen(WHITE);
Mit den folgenden zwei Codezeilen werden die Koordinaten des Drehpunktes der Temperaturnadel angegeben. Diese Koordinaten sind identisch mit dem Mittelpunkt des Kreises, der die Skala der Temperaturwerte enthalten wird.
pivot_x_temperature = center_x_temperature;
pivot_y_temperature = center_y_temperature;
Zu Beginn sind die alten auch die neuen Werte für die Koordinaten.
p1_x_old_temperature = center_x_temperature; p1_y_old_temperature = center_y_temperature;
p2_x_old_temperature = center_x_temperature; p2_y_old_temperature = center_y_temperature;
p3_x_old_temperature = center_x_temperature; p3_y_old_temperature = center_y_temperature;
Für die Anzeige der Luftfeuchtigkeit genau das gleiche.
pivot_x_humidity = center_x_humidity;
pivot_y_humidity = center_y_humidity;
p4_x_old_humidity = center_x_humidity; p4_y_old_humidity = center_y_humidity;
p5_x_old_humidity = center_x_humidity; p5_y_old_humidity = center_y_humidity;
p6_x_old_humidity = center_x_humidity; p6_y_old_humidity = center_y_humidity;
Um die Skalen der Temperatur- und Luftfeuchtigkeitswerte auf dem Bildschirm anzuzeigen, wird die Methode create_dial_temperature() aufgerufen, zur Anzeige des Drehpunkts der Temperaturnadel die Methode draw_pivot_temperatue() und mit draw_pivot_humidity() die Methode zur Anzeige des Drehpunkts des Luftfeuchtigkeitszeigers.
create_dial_temperature();
draw_pivot_temperature();
draw_pivot_humidity();
Die Methode create_dial_temperature() enthält die Anzeige der Skala der Temperatur- und Luftfeuchtigkeit. Ich zeige hier die Erstellung der Temperaturskala. Die Erstellung der Luftfeuchtigkeit enthält ähnliche Schritte.
Das erste, was ausgeführt wird, ist for (temperature=-20; temperature<40.1; temperature+=10), dies ist eine for-Schleife, um kleine rote Kreise darzustellen, die bei -20 Grad Celsius beginnen und bei 40 Grad Celsius enden. Die Schrittweite beträgt 10, d.h. alle 10 Grad soll ein roter Kreis gezeichnet werden. Innerhalb der Schleife, wird als erstes die Zeile needleAngle_temperature = ( temperature * deg_to_rad * 1) - 2.7 ausgeführt. Dadurch wird der Wert der übergebenen Temperatur in Grad Bogenmaß in den Umfang der Temperaturskala umgewandelt. Dazu wird die Temperatur (temperature) mit dem Wert von 1 Grad in Bogenmaß (deg_to_rad) und mit dem Abstand (1) zwischen den Kreisen multipliziert. Der Wert von -2,7 wird für die Positionierung des ersten Wertes auf dem Umfang der Skala verwendet. Die folgende Abbildung zeigt einen Kreis mit den Umrechnungswerten von Grad in Bogenmaß. Um den Wert von -20 Grad Celsius auf der Temperaturskala des Bildschirms zu positionieren, muss 2,7 Grad Bogenmaß von 0 abgezogen werden. Die Richtung der Addition auf dem Bildschirm verläuft im Uhrzeigersinn.

for (temperature=-20; temperature<40.1; temperature+=10) {
needleAngle_temperature = (temperature * deg_to_rad * 1) – 2.7;
}
Wie in der folgenden Abbildung zu sehen ist, müssen wir zur Umrechnung des Bogenmaßes des Kreisumfangs in Bildschirmkoordinaten die Berechnungen mit dem Kosinus durchführen, um die Koordinate auf der X-Achse zu berechnen, und mit dem Sinus für die Y-Koordinate.
Die folgende Abbildung zeigt noch einmal, wie zur Umrechnung des Bogenmaßes des Kreisumfangs in Bildschirmkoordinaten durchgeführt wird. Für die Berechnung der X-Koordinate wird der Kosinus und für die Y-Koordinate der Sinus verwendet.

Mit der Zeile arc_x_temperature = (pivot_x_temperature + ((radius_temperature + 4) * cos(needleAngle_temperature)) wird die Koordinate in Pixel auf der X-Achse des Bildschirms berechnet. Die 4 Pixel, die zum Radius des Umfangs hinzugefügt werden, dienen dazu, den Punkt weg zu bewegen und nicht jedes Mal, wenn sich der Temperaturwert ändert, einen Aufruf der Methode zur Darstellung der Skala durchführen zu müssen. Die Zeile arc_y_temperature = (pivot_y_temperature + ((radius_temperature + 4) * sin(needleAngle_temperature))) wird zur Berechnung der Pixelkoordinate der Y-Achse des Bildschirms verwendet.
arc_x_temperature = (pivot_x_temperature + ((radius_temperature + 4) * cos(needleAngle_temperature)));
arc_y_temperature = (pivot_y_temperature + ((radius_temperature + 4) * sin(needleAngle_temperature)));
Nachdem die X- und Y-Koordinaten des vom Zähler der for-Schleife übergebenen Temperaturwerts berechnet wurden, wird an den X- und Y-Koordinaten, ein roter 2-Pixel-Kreis angezeigt.
tft_temperature.fillCircle (arc_x_temperature, arc_y_temperature, 2, RED);
Beim Verlassen der for-Schleife, wird die Skalenwert-Legende mit tft_temperature.print** ("TEMP"**)** hinzugefügt, die Textfarbe mit tft_temperature.setTextColor** (RED), mit tft_temperature.setTextSize** (2) die Schriftgröße auf 2 und an den mit tft_temperature.setCursor** (64, 16) angegebenen Koordinaten gesetzt. Die Legenden für die Werte der einzelnen Punkte auf der Temperaturskala werden ebenfalls in roter Farbe, Schriftgröße 2 und an den für jeden Wert angegebenen Koordinaten hinzugefügt.
Für das hochgestellte Symbol "o" für Grad Celsius wird ein kleiner roter Kreis von 2 Pixeln und ein konzentrischer Kreis von 1 Pixel in der Hintergrundfarbe des Bildschirms eingefügt.
tft_temperature.setTextColor (RED);
tft_temperature.setTextSize (2);
tft_temperature.setCursor (64, 16);
tft_temperature.print ("TEMP");
tft_temperature.setTextColor (RED);
tft_temperature.setTextSize (2);
tft_temperature.setCursor (80, 38);
tft_temperature.print ("40");
. . . . .
. . . . .
. . . . .
tft_temperature.setTextColor (RED);
tft_temperature.setTextSize (2);
tft_temperature.setCursor (29, 159);
tft_temperature.print ("C");
tft_temperature.fillCircle (24, 161, 2, RED);
tft_temperature.fillCircle (24, 161, 1, WHITE);
Innerhalb der Methode create_dial_temperature() befindet sich auch der Code, der für die Anzeige der Feuchtigkeitsskala auf demselben Display erforderlich ist. Die Schritte dazu sind genau gleich.
Wenn die Werteskalen angezeigt wurden, werden die Drehpunkte der Temperatur- und Luftfeuchtigkeitsmarkierungsnadeln durch Aufruf der Methoden draw_pivot_temperature() und draw_pivot_humidity() aufgerufen. In diesen Methoden besteht die einzige Codezeile darin, einen roten oder blauen Kreis mit einer Größe von 8 Pixeln in der Mitte des jeweiligen Kreisumfangs anzuzeigen.
tft_temperature.fillCircle (pivot_x_temperature, pivot_y_temperature, 8, RED);
tft_temperature.fillCircle (pivot_x_humidity, pivot_y_humidity, 8, RED);
Zu diesem Zeitpunkt sind die Temperatur- und Luftfeuchtigkeitskugel bereits initialisiert und die Werteskalen für diese beiden Größen werden angezeigt. Der nächste Code der setup()**-Methode ist die Initialisierung des Luftdruckdisplays. Die Schritte sind die gleichen, wie auch die Initialisierung des Displays für die Stunde und Minuten. Die Werteskala wird zuerst erstellt und dann der Drehpunktkreis der Nadel.
Sobald die drei Displays initialisiert sind, werden die drei Module, die die Daten liefern, initialisiert. Das erste Modul, das initialisiert wird, 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 dieses Sensors. Es wird vom seriellen Monitor mit Serial.println(**"BMP180 init"**)** gemeldet, dass dieses Modul initialisiert wird. Mittels einer Bedingung wird geprüft, ob dieses Modul die richtige Adresse hat. Das Argument der Bedingung wird negiert, d.h. wenn die Adresse dieses Moduls nicht die in der Bibliothek gespeicherte ist, wird sie erfüllt. Das Innere der Anweisung wird ausgeführt. So kann der Fehler bei der Initialisierung des Moduls gemeldet werden.
bmp180.init();
Serial.println("BMP180 init");
if (!bmp180.hasValidID()) {
Serial.println("Error - please check the BMP180 board!");
}
Das dritte und letzte Modul ist das RTC DS3231-Uhrenmodul. Dies geschieht über die Methode begin()** des für dieses Modul erstellten Objekts. Die nächsten beiden Zeilen dienen der Konfiguration des aktuellen Datums und der Uhrzeit. Die Anweisung rtc.adjust**(**DateTime**(F(**DATE**), F(**TIME**))** ruft die Datums- und Zeitdaten 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, 12, 23, 33, 0))** entfernen. In den Argumenten müssen Sie die Werte Jahr, Monat, Tag, Stunde, Minuten und Sekunden manuell eingeben.
rtc.begin();
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// rtc.adjust(DateTime(2024, 9, 12, 23, 33, 0));
Damit ist die setup()**-Methode beendet und die loop()**-Methode, die ständig ausgeführt wird, wird ausgeführt. Als erstes wird die now()**-Methode des DS3231-Modulobjekts aufgerufen. Um die aktuelle Uhrzeit zu erhalten, wird die Funktion now.**hour**()** verwendet, deren Wert in der Variablen time_ h gespeichert wird. Die Funktion now.**minute**()** wird verwendet, um die aktuellen Minuten zu erhalten und wird in der am Anfang des Sketches definierten Variablen time_m gespeichert.
DateTime now =rtc.now();
time_h = now.hour();
time_m = now.minute();
Damit der Stundenzeiger die richtige Stundenposition auf dem Zifferblatt hat, müssen die verstrichenen Minuten zur Stunde addiert werden. Das Zifferblatt hat die Markierungen für die 60 Minuten, so dass zu jede Minute, der Minutenzeiger eine Position vorrückt. Damit der Stundenzeiger 60 Positionen in einer Stunde vorrückt, müssen die Minuten durch 60 geteilt werden. So werden 60 Positionen von einer Stunde zur nächsten vorgerückt.
time_h = time_h + (time_m/60);
Die Daten für Stunden und Minuten sollen im Serial Monitor angezeigt werden.
Serial.println(time_h);
Serial.println(time_m);
Die Bildschirme aktualisieren ihre Daten jede Minute, da sich die Werte der BMP180- und DHT22-Sensoren in dieser kurzen Zeitspanne nicht wesentlich ändern. Außerdem machen wir uns die Tatsache zunutze, dass der Minutenzeiger der Uhr jede Minute seine Position ändern muss. Wenn dies der Fall ist, wird das Innere der geschweiften Klammern ausgeführt und die Methode refresh_screens() aufgerufen, in der die Bildschirmdaten aktualisiert werden. Wenn sich die Minutenvariable hingegen nicht geändert hat, kehren wir zum Anfang der Methode loop()** zurück, da else() leer ist (der else-Zweig der Anweisung kann auch weggelassen werden).
if (time_m != time_m_old) {
refresh_screens();
} else { }
Beim Aufruf der Methode refresh_screens() wird zusammenfassend das Auslesen des Sensorwertes ausgeführt, der Wert in der entsprechenden Variablen gespeichert, sowie in die Variable kopiert, die für die Anzeige der Zeiger zuständig ist. Dann wird die entsprechende Methode zur Änderung der Position des Zeigers aufgerufen. Um die Daten auf dem Temperatur- und Luftfeuchtigkeitsbildschirm zu aktualisieren, muss zunächst die Temperatur mit der Methode readTemperature() des Sensorobjekts ausgelesen und in der Variablen temp gespeichert werden. Der Wert wird vom Serial Monitor angezeigt. Um die Luftfeuchtigkeit auszulesen, wird die Methode readHumidity()** aufgerufen und ihr Wert in der Variablen humi gespeichert, deren Wert ebenfalls vom Serial Monitor gemeldet wird. Wenn die Variablen keinen Wert speichern, meldet der serielle Monitor den Ausfall des Sensors.
Serial.print("Temperature ºC --> ");
Serial.println(temp);
humi = dht.readHumidity();
Serial.print("Humidyty % --> ");
Serial.println(humi);
if (isnan(humi) || isnan(temp)) {
Serial.println("DHT sensor read failure !!!");
}
Nach dem Auslesen und Speichern der Temperatur- und Luftfeuchtigkeitswerte wird der Wert der Variablen temp und humi in den Variablen needle_setter_temperature und needle_setter_humidity gespeichert. Diese Variablen werden in den Methoden zur Positionierung der Nadel unter Angabe ihrer Werte verwendet. Zu diesem Zweck werden die Methoden needle_temperature() und needle_humidity() aufgerufen.
needle_setter_temperature = temp;
needle_setter_humidity = humi;
needle_temperature();
needle_humidity();
Für die Aktualisierung der Daten auf den Luftdruck- und Uhrenanzeigen sind die Schritte die gleichen. Es ist zu beachten, dass es nur einen Unterschied der Variablen der Minutenzeigerdaten gibt. Das Ziffernblatt hat die Darstellung von 12 Stunden und 60 Minuten. Für die korrekte Darstellung der Werte müssen diese zwischen 0 und 12 liegen, also müssen die übergebenen Minuten auf der Grundlage der beiden vorherigen Werte umgerechnet werden. Deshalb wird der Wert der Minuten mit 0.2 multipliziert in der Zeile needle_setter_minutes_clock = time_m * 0.2. So wird der reale Wert der Minuten an die Position angepasst, die der Zeiger markieren wird. Z.B. werden die 30 Minuten in der 6-Uhr-Position und die 45 Minuten in der 9-Uhr-Position markiert.
In der letzten Zeile der Methode refresh_screens() wird der aktuelle Wert der Variablen time_m in der Variablen time_m_old gespeichert, um die Minutenprüfung in der if-else-Bedingung der Methode loop()** durchzuführen.
Wenn die Methode needle_temperature() aufgerufen wird, um die Zeigerposition mit den neuen Temperaturdaten zu aktualisieren, wird zunächst der aktuelle Zustand des Zeigers mit der weißen Hintergrundfarbe des Bildschirms neu gezeichnet, also "gelöscht". Dann wird der Zeiger wieder rot dargestellt, um den neuen Wert zu markieren.
Mit den folgenden Zeilen werden die Linie und die Spitze des Zeigers neu in weiß gezeichnet.
tft_temperature.drawLine (pivot_x_temperature, pivot_y_temperature, p1_x_old_temperature, p1_y_old_temperature, WHITE);
tft_temperature.fillTriangle (p1_x_old_temperature, p1_y_old_temperature, p2_x_old_temperature, p2_y_old_temperature, p3_x_old_temperature, p3_y_old_temperature, WHITE);
Mit den gespeicherten Temperaturdaten muss die Position des Bogenwertes dieser Temperatur auf dem auf der Werteskala gezeichneten Bogen berechnet werden. Diese Berechnung wird in der folgenden Zeile durchgeführt.
needleAngle_temperature = (needle_setter_temperature * deg_to_rad * 1) - 2.7;

Wenn die Position des Temperaturwerts im Bogenmaß auf dem Umfang berechnet wurde, müssen die Koordinaten der Nadel auf dem Bildschirm berechnet und in ihren Variablen gespeichert werden. Um die Nadel darzustellen, müssen Sie die Koordinaten des Drehpunkts kennen (pivot_x_temperature und pivot_y_temperature), der Spitze des Zeigers (p1_x_temperature und p1_y_temperature), des linken Scheitelpunkts des Dreiecks an der Spitze des Zeigers (p2_x_temperature und p2_y_temperature) und des rechten Scheitelpunkts (p3_x_temperature und p3_y_temperature). Die die Koordinaten werden mit Sinus und Cosinus berechnet, wie bei der Darstellung der Werteskala beschrieben.
p1_x_temperature = (pivot_x_temperature + ((radius_temperature - 1) * cos(needleAngle_temperature)));
p1_y_temperature = (pivot_y_temperature + ((radius_temperature - 1) * sin(needleAngle_temperature)));
p2_x_temperature = (pivot_x_temperature + ((radius_temperature - 16) * cos(needleAngle_temperature - 0.05)));
p2_y_temperature = (pivot_y_temperature + ((radius_temperature - 16) * sin(needleAngle_temperature - 0.05)));
p3_x_temperature = (pivot_x_temperature + ((radius_temperature - 16) * cos(needleAngle_temperature + 0.05)));
p3_y_temperature = (pivot_y_temperature + ((radius_temperature - 16) * sin(needleAngle_temperature + 0.05)));
Die Daten werden in den entsprechenden Variablen und zusätzlich für die alten Koordinaten (z. B. p1_x_old_temperature) gespeichert, wenn der Zeiger „gelöscht“ werden muss.
p1_x_old_temperature = p1_x_temperature; p1_y_old_temperature = p1_y_temperature;
p2_x_old_temperature = p2_x_temperature; p2_y_old_temperature = p2_y_temperature;
p3_x_old_temperature = p3_x_temperature; p3_y_old_temperature = p3_y_temperature;
Um die Nadel in der neuen Position darzustellen und den neuen Wert auf der Werteskala zu markieren, wird zunächst eine rote Linie vom Drehpunkt bis zur Pfeilspitze dargestellt.
tft_temperature.drawLine (pivot_x_temperature, pivot_y_temperature, p1_x_temperature, p1_y_temperature, RED);
Dann wird ein rotes Dreieck als Spitze des Pfeils gezeichnet.
tft_temperature.fillTriangle (p1_x_temperature, p1_y_temperature, p2_x_temperature, p2_y_temperature, p3_x_temperature, p3_y_temperature, RED);
tft_temperature.fillTriangle (p1_x_temperature, p1_y_temperature, p2_x_temperature, p2_y_temperature, p3_x_temperature, p3_y_temperature, RED);
Die Vorgehensweise bei der Darstellung der Zeiger der anderen Größen ist ähnlich wie oben gezeigt. Der Code ist im Sketch mit Kommentaren beschrieben.


Ausblick
In Teil 3 dieses Projekts soll ein vierter Bildschirm hinzugefügt werden, auf dem der Wochentag, das Datum, der Zustand des Himmels je nach Luftdruck und die Mondphase angezeigt werden.
Bleiben Sie dran!
2 commenti
Andreas Wolter
@Martin: das sieht sehr gut aus. Dein Link ist nicht korrekt. Ich habe deine Seite besucht und den korrekten Verweis gefunden:
https://github.com/Mosei1984/Wetterstation2/tree/main
Falls das Projekt hier als Grundlage diente, könntest du den Beitrag bei dir verlinken? Für den Autoren und seine Arbeit. Ich schreibe deine Verlinkung mit in den Beitrag.
Grüße,
Andreas Wolter
AZ-Delivery Blog
Martin
Hallo ich habe einen Stepper hinzugefügt der 2 Figuren antreibt wie bei einem wetterhäuschen , https://github.com/Mosei1984/Wetter-Station/tree/main/wetterstation2