Retro Barometer mit runden Displays - Teil 3 - AZ-Delivery

Im dritten Teil des Barometer-Projekts wird der AZ-ATmega328-Mikrocontroller durch ein ESP-32 Dev Kit C V4 ersetzt und ein weiteres Display wird hinzugefügt, das den Zustand des Himmels je nach Luftdruck mit drei Bildern anzeigt: Regen, Sonne und Wolken mit Sonne, der Wochentag und das Datum, sowie die Mondphase.

Ein Großteil des Codes, der in Teil 2 des Projekts analysiert wurde, ist weiterhin gültig, da die drei anderen Displays immer noch dieselben Daten anzeigen. Wenn man ein weiteres Display hinzufügt und den Mikrocontroller ändert, muss man Code mit neuen Variablen hinzufügen und die Verbindungsports zum neuen Mikrocontroller ändern.

Zum Abschluss des Projekts wird die gesamte Baugruppe in einen Kasten aus Holzbrettern im Vintage-Look eingebaut, in dem sich oben das Ziffernblatt der Uhr befindet, darunter das Ziffernblatt mit den Datumsangaben, das dritte Ziffernblatt zeigt die Daten der Temperatur und der Luftfeuchtigkeit in der Umgebung an und das vierte und letzte Ziffernblatt den Luftdruck. Beginnen wir mit der Hardware für diesen Teil.

Verwendete Hardware

Benötigte Software, Bibliotheken und Sketch

Schaltung und Beschreibung der verwendeten Module

Download Schaltplan

Zeichnung der Bauteile

Download Zeichnung

Die Elektrik wird vom Breadboard auf die Lochrasterplatinen übertragen und in das Gehäuse eingesetzt.

Analyse des Sketches

Wenn Sie bisher keinen ESP Mikrocontroller mit der Arduino IDE verwendet haben, müssen Sie den ESP Core und eventuell auch Treiber installieren.

Diese Anleitung kann Ihnen dabei helfen.

Sobald alles installiert ist, können Sie im Menü unter “Board” einen ESP-32 auswählen.

In diesem dritten Teil des Projekts werden keine weiteren Bibliotheken eingebunden. Die in Teil 2 verwendeten reichen aus.

Die Verbindungen von den Mikrocontroller-Pins zu den TFT-Display-Pins sind nicht die gleichen, so dass die numerischen Werte in den Variablendefinitionen geändert werden müssen. Es werden zwei Codezeilen hinzugefügt, eine zur Definition einer neuen Variable für das zusätzliche Display mit #define tft_cs_calendar 27 und eine Variable für die Verbindung zum RST-Pin der Displays mit #define tft_rst 26.

#define tft_dc 16

#define tft_cs_pressure 33

#define tft_cs_clock 25

#define tft_cs_temperature 32

#define tft_cs_calendar 27

#define tft_rst 26

 

Für den neuen Bildschirm muss ein Objekt erstellt werden. Die neue Codezeile wird am Ende der Objekterstellung für die Bildschirme mit Adafruit_GC9A01A tft_calendar (tft_cs_calendar, tft_dc) hinzugefügt.

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

Adafruit_GC9A01A tft_calendar (tft_cs_calendar, tft_dc);

 

Zu den vier Grundfarben für die Elemente der Displays, die in Teil 2 verwendet wurden, fügen wir eine weitere Farbe hinzu, nämlich Grau. Wir fügen die Zeile #define GREY 0x4A49 nach den Zeilen, die die vier bereits oben definierten Farben definieren, hinzu. Der Wert wird im Code rgb565 festlegt. Der Wert jeder Farbe kann unter http://rinkydinkelectronics.com/calc_rgb565.php eingesehen werden.

#define BLACK      0x0000

#define BLUE       0x001F

#define RED        0xF800

#define WHITE      0xFFFF

#define GREY       0x4A49

 

An den beiden wesentlichen Variablen zur Berechnung der Koordinaten der Werte auf der Werteskala und der Position des Zeigers zur Anzeige des Wertes wird nichts geändert.

#define deg_to_rad 0.0174532925

float  pi = 3.1415926535;

 

Die Definitionen aller Variablen und des DHT22-Sensorobjekts sind die gleichen wie in Teil 2, nur die Nummer des Pins des ESP32-Mikrocontrollers, an den der Datenpin des DHT22-Moduls angeschlossen wird, muss geändert werden. Die Änderung wird in der Zeile #define dht_pin 4 vorgenommen. Der neue Pin ist die Nr. 4. Alles andere bleibt wie gehabt.

#define dht_pin 4

#define dht_type DHT22

DHT dht(dht_pin, dht_type);

float humi;

float temp;

 

int center_x_temperature = 149;

int center_y_temperature = 150;

 

int center_x_humidity = 89;

int center_y_humidity = 150;

 

float pivot_x_temperature, pivot_y_temperature, pivot_x_temperature_old, pivot_temperature_y_old;

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;

float arc_x_temperature;

float arc_y_temperature;

float needleAngle_temperature = 0;

float temperature;

float needle_setter_temperature;

 

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;

 

int radius_temperature = 100;

 

Die Variablendefinitionen für das Barometermodul BMP180 und die Objektimplementierung für das Modul sind unverändert, die Variablennamen und -werte sind dieselben.

BMP180 bmp180;

float pressu;

int center_x_pressure = 120;

int center_y_pressure = 120;

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;

float arc_x_pressure;

float arc_y_pressure;

int radius_pressure = 65;

float needleAngle_pressure = 0;

float needle_setter_pressure;

int pressure_scale;

int pressure_module_calibration = 140;

 

Da ein neuer Bildschirm hinzugefügt wurde, der den Wochentag, das Datum und die Mondphase anzeigt, muss ein neues Array definiert und die Daten des Arrays "Wochentage" müssen geändert werden. Da der Wochentag und das Datum auf dem Bildschirm in derselben Zeile angezeigt werden, ist es aufgrund des Pixelabstands nicht möglich, die Namen der Wochentage mit allen Buchstaben in der Zeile anzuzeigen. Daher werden sie abgekürzt und die neue Codezeile lautet char daysOfTheWeek[7][9] = {"Sun.", "Mon.", "Tues.", "Wed.", "Thurs.", "Fri.", "Sat."}. Mit der Zeile int daysInMonth[] = {0, 31, 28, 31, 31, 30, 31, 31, 30, 30, 31, 31, 31, 31, 31, 30, 31, 30, 31, 30, 31} wird auch ein neues Array hinzugefügt, das die Anzahl der Tage enthält, die jeder Monat des Jahres hat und später für die Darstellung der Mondphase verwendet wird.

RTC_DS3231 rtc;

char daysOfTheWeek[7][9] = {"Sun.", "Mon.", "Tues.", "Wed.", "Thurs.", "Fri.", "Sat."}

 

int daysInMonth[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

 

Bei den Variablen des Moduls RTC DS3231 bleiben die drei in Teil 2 definierten Variablen zur Speicherung der Stunden und Minuten unverändert, aber es werden neue Variablen vom Typ int hinzugefügt, um den Tag (date_d), den Monat (date_m) und das aktuelle Jahr (date_y) zu speichern, sowie die vergangenen Tage mit past_days und die vergangenen Tage seit dem 1. Januar 2024 mit der Variablen total_past_days. iese zuletzt definierten Variablen werden auch bei der Berechnung der Mondphase verwendet.

float time_h;

float time_m;

float time_m_old;

 

int date_d;

int date_m;

int date_y;

int past_days;

int total_past_days;

 

Die Variablen für die Darstellung der Uhr auf dem Ziffernblatt sind die gleichen wie in Teil 2, es ändert sich nichts.

int center_x_clock = 120;

int center_y_clock = 120;

float pivot_x_clock, pivot_y_clock, pivot_x_old_clock, pivot_y_old_clock;

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;

float arc_x_clock;

float arc_y_clock;

int radius_clock = 72;

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;   

 

Es werden drei neue Variablen für die Darstellung des Datums auf dem vierten Bildschirm hinzugefügt. Es handelt sich um Arrays, die die Zeichen enthalten, die auf dem Bildschirm angezeigt werden sollen. Die Namen der Arrays sind einfach zuzuordnen.

char actual_day[2];

char actual_month[2];

char actual_year[4];

 

Im Variablendefinitionsblock werden vier Variablen deklariert, die bei der Berechnung der auf dem Bildschirm anzuzeigenden Mondphase verwendet werden. Die Variable new_moon_period = 29.5 speichert die Anzahl der Tage zwischen den Neumonden, wobei diese Anzahl von Tagen immer gleich ist. Die nächste Variable, first_day_new_moon_2024 = 10, speichert die Anzahl der Tage seit dem 1. Januar 2024 für den ersten Neumond des Jahres. In der Variablen next_day_new_moon wird die Anzahl der Tage gespeichert, die vom letzten Neumond bis zum nächsten Neumond vergehen und in der Variablen past_day_new_moon wird die Anzahl der seit dem letzten Neumond verstrichenen Tage gespeichert.

float new_moon_period = 29.5;

float first_day_new_moon_2024 = 10;

float next_day_new_moon;

float past_day_new_moon;

 

Weiter geht es mit der Methode setup(). Das erste, was in dieser Methode gemacht wird, ist die Initialisierung der seriellen Schnittstelle für die Ausgabe auf dem seriellen Monitor und das Senden der Initialisierungsnachricht für Bildschirme und Sensoren.

Serial.begin(115200);

Serial.println("Initialization of the set of sensors and displays.");   

 

Danach folgt die Konfiguration der Mikrocontroller-Pins, an die die Display-Pins und das DHT22-Modul angeschlossen sind. Die Pins, an die die TFT-Display-Pins angeschlossen sind, müssen als Ausgang konfiguriert werden, während der Pin, an den das DHT22-Modul angeschlossen ist, als Eingang konfiguriert wird.

pinMode(tft_dc, OUTPUT);

pinMode(tft_cs_pressure, OUTPUT);

pinMode(tft_cs_clock, OUTPUT);

pinMode(tft_cs_temperature, OUTPUT);

pinMode(tft_cs_calendar, OUTPUT);

pinMode(dht_pin, INPUT);  

 

Der erste Bildschirm wird durch die Methode begin() des erstellten Objekts initialisiert, das die Temperatur- und Luftfeuchtigkeitsdaten anzeigt. An der Initialisierung der Variablen dieses Bildschirms hat sich im Vergleich zu Teil 2 ebenfalls nichts geändert.

tft_temperature.begin();

tft_temperature.setRotation(0);

tft_temperature.fillScreen(WHITE);

pivot_x_temperature = center_x_temperature;

pivot_y_temperature = center_y_temperature;

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;

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;

create_dial_temperature();

draw_pivot_temperature();

draw_pivot_humidity();

 

Die Aufrufe der Methoden create_dial_temperature() , draw_pivot_temperature() und draw_pivot_humidity() sind für die Darstellung der Skalen der Temperatur- und Luftfeuchtigkeitswerte, sowie der Kreise, in denen sich die Zeiger bewegen, um die Werte des DHT22-Moduls zu markieren. Sie wurden bereits in Teil 2 analysiert und sind genau dieselben.

 Zu diesem Zeitpunkt sind die Bildschirme für Temperatur und Luftfeuchtigkeit bereits initialisiert und die Werteskalen für diese beiden Größen werden angezeigt. Die nächsten Bildschirme, die initialisiert werden müssen, sind die für den Luftdruckwert und die Uhr. Auch das bleibt wie in Teil 2 unverändert.

Der vierte Bildschirm wird keine Skala darstellen, sondern nur zwei Bilder und eine Zeile mit Zeichen. Zunächst wird die Methode begin() des tft_calendar-Objekts aufgerufen, der Bildschirm wird nicht gedreht und der Bildschirmhintergrund wird auf schwarz gesetzt.

tft_calendar.begin();

tft_calendar.setRotation (0);

tft_calendar.fillScreen (BLACK);

 

Nach der Initialisierung der vier Bildschirme werden die drei Sensormodule wie in Teil 2 initialisiert.

dht.begin();

 
bmp180.init();

Serial.println("BMP180 init");

if (!bmp180.hasValidID()) {

         Serial.println("Error - please check the BMP180 board!");

}

 

rtc.begin();

rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

// rtc.adjust(DateTime(2024, 9, 1, 0, 33, 0));

 

Nun geht es weiter mit der loop()-Methode, die kontinuierlich ausgeführt wird. Der Code dieser Methode ist auch genau derselbe wie in Teil 2 des Projekts.

DateTime now =rtc.now();

time_h = now.hour();

time_m = now.minute();

time_h = time_h + (time_m/60);

Serial.println(time_h);

Serial.println(time_m);

 

if (time_m != time_m_old) {

         refresh_screens();

} else { }  

 

Wenn die Methode refresh_screens() aufgerufen wird, liest sie die Größenwerte von den Sensoren, speichert den Wert in den entsprechenden Variablen, kopiert die Datenwerte in die Variablen für die Zeiger und ruft die entsprechenden Methoden auf, um die Positionen der Zeiger zu ändern. Der Code für diese drei Bildschirme ist derselbe wie in Teil 2, lediglich ein Aufruf der Methode draw_pivot jedes Bildschirms wurde eingefügt, um die Darstellung des Kreises der Rotationsachse der Nadeln zu aktualisieren und das Fehlen von Farben in Teilen zu vermeiden, wenn die Zeiger ihre Position ändern.

Der vierte Bildschirm zeigt durch ein Bild den Zustand des Himmels entsprechend dem atmosphärischen Druck, den Wochentag und das Datum mit Zeichen und die Mondphase mit einem Bild.

Als erstes wird die now()-Methode des DS3231-Modulobjekts aufgerufen. Damit werden die Informationen über die aktuelle Uhrzeit und das aktuelle Datum abgerufen, um sie dann auf dem Bildschirm anzuzeigen. Um den aktuellen Tag zu erhalten, wird die Funktion now.day() verwendet und ihr Wert in der Variablen date_ d gespeichert, die Funktion now.month() wird verwendet, um den aktuellen Monat zu erhalten und in der Variablen date_m gespeichert. Die Funktion now.year() gibt das aktuelle Jahr zurück, dass in der Variablen date_y gespeichert wird.

DateTime now =rtc.now();

 

date_d = now.day();

date_m = now.month();

date_y = now.year();

 

Der Hintergrund dieses Bildschirms ist schwarz, da sowohl die Bilder als auch die Zeichen in Weiß dargestellt werden. Die Hintergrundfarbe des Bildschirms wird mit der folgenden Zeile konfiguriert.

tft_calendar.fillScreen(BLACK);

Die nächsten vier Zeilen konfigurieren die Legende am oberen Rand des Bildschirms. Mit der Funktion setTextColor (WHITE) wird die weiße Farbe des Textes eingestellt, mit der Funktion setTextSize (2) wird die Textgröße auf 2 gesetzt, der Text wird an den mit setCursor (93, 4) eingestellten Koordinaten angezeigt und der anzuzeigende Text wird mit der Funktion print ("TODAY") ausgegeben.

tft_calendar.setTextColor (WHITE);

tft_calendar.setTextSize (2);

tft_calendar.setCursor (93, 4);

tft_calendar.print ("TODAY");

 

Um den Wochentag zu erhalten, ruft die Funktion println(daysOfTheWeek[now.dayOfTheWeek()]) den Wochentag in dem Array auf, in dem die Abkürzungen der Wochentage gespeichert sind. Das Modul hat die Wochentage als Zahlen konfiguriert, z. B. ist Sonntag der Tag 0 der Woche. Wenn der Aufruf erfolgt, wird die passende Nummer als Index für das Array zurückgegeben und der Text auf dem Bildschirm angezeigt. Die Koordinaten werden wieder mit der Funktion setCursor (20, 112), die Farbe des Textes mit der Funktion setTextColor (WHITE) und die Größe des Textes mit der Funktion setTextSize (2) festgelegt.

tft_calendar.setCursor(20, 112);

tft_calendar.setTextColor(WHITE);

tft_calendar.setTextSize(2);

tft_calendar.println(daysOfTheWeek[now.dayOfTheWeek()]);

 

Für die Trennung zwischen Wochentag und Datum wird ein Komma verwendet, die Funktionen für die Darstellung auf dem Bildschirm sind ähnlich wie die oben.

tft_calendar.setTextColor (WHITE);

tft_calendar.setTextSize (2);

tft_calendar.setCursor (97, 114);

tft_calendar.print (",");

 

Die Informationen der ersten neun Tage des Monats und der ersten neun Monate des Jahres, die das Modul RTC DS3231 sendet, haben nur eine Ziffer, während die restlichen Tage und Monate zwei Ziffern haben. Würden sie auf dem Bildschirm so dargestellt, wie sie ausgelesen werden, würden sie an der ersten von zwei Positionen stehen, wobei ein Leerraum bis zum Bindestrich der Trennung zwischen Tagen und Monaten bleiben würde. Die Zahl wird in Text umgewandelt und dieser in eine Zeichenkette. Dieser Zeichenkette wird eine 0 als Zeichen vorangestellt (verkettet). Somit hat der Text dann zwei Zeichen und die Darstellung auf dem Bildschirm ist korrekt.

Wenn der Wert der Variablen kleiner als 10 ist, wird als erstes der numerische Wert mit String(date_d) in Text umgewandelt und dieser Text wird in der Variablen convert_day gespeichert, die vom Typ text String ist. An die vorherige Variable wird das Zeichen 0 (Null) vor dem gespeicherten Text angehängt, dies geschieht mit der Codezeile convert_day = '0' + convert_day, womit wir bereits eine Zeichenkette von 2 Zeichen haben. Der Inhalt der Variablen wird in einem Array vom Typ Zeichen mit 3 Elementen und dem Namen actual_day mit der Zeile convert_day.toCharArray(actual_day, 3) gespeichert. Nun müssen nur noch die Daten auf dem Bildschirm angezeigt und die notwendigen Funktionen implementiert werden, um den Cursor mit setCursor(112, 112) an den richtigen Koordinaten zu platzieren, die Textfarbe mit setTextColor(WHITE) auszuwählen, die Schriftgröße mit tft_calendar.setTextSize(2) auf 2 zu setzen und schließlich den Inhalt des Zeichenarrays mit println(actual_day) anzuzeigen, wodurch der aktuelle Tag auf dem Bildschirm dargestellt wird.

if (date_d < 10) {

         String convert_day = String(date_d);

         convert_day = '0' + convert_day;

         convert_day.toCharArray(actual_day, 3);

         tft_calendar.setCursor(112, 112);

         tft_calendar.setTextColor(WHITE);

         tft_calendar.setTextSize(2);

         tft_calendar.println(actual_day);

}

 

Ist die Zahl hingegen größer oder gleich 10, wird der else-Block ausgeführt. Hier wurde nur die Zeile entfernt, in der ein Zeichen an die Variable angehängt wird, die den an text übergebenen Wert enthält.

Diese Passage könnte noch vereinfacht werden, indem nur die Verkettung mit der ‘0’ in eine if-Anweisung geschrieben wird.

else {

         String convert_day = String(date_d);

         convert_day.toCharArray(actual_day, 3);

         tft_calendar.setCursor(112, 112);

         tft_calendar.setTextColor(WHITE);

         tft_calendar.setTextSize(2);

         tft_calendar.println(actual_day);

}

 

Für die Trennung zwischen den Tagen, Monaten und dem Jahr habe ich zwei kleine Striche als Bindestrich gewählt, damit sie besser sichtbar sind als ein einzelner Strich oder das Zeichen ‘-‘. In den Argumenten müssen die Koordinaten für den Anfang und das Ende der Zeile und die Farbe der Zeile übergeben werden.

tft_calendar.drawLine (139, 118, 144, 118, WHITE);

tft_calendar.drawLine (139, 119, 144, 119, WHITE);

Um den aktuellen Monat auf dem Bildschirm anzuzeigen, sind die Funktionen dieselben wie für die Anzeige der Tage, es müssen nur die Variablennamen geändert werden, um auf die Monate und die Koordinaten des Bildschirms zu verweisen, an denen der Text angezeigt werden soll. Ein Bindestrich wird auch auf dem Bildschirm angezeigt, um die Monate des Jahres zu trennen.

if (date_m < 10) {

         String convert_month = String(date_m);

         convert_month = '0' + convert_month;

         convert_month.toCharArray(actual_month, 3);

         tft_calendar.setCursor(150, 112);

         tft_calendar.setTextColor(WHITE);

         tft_calendar.setTextSize(2);

         tft_calendar.println(actual_month);

} else {

         String convert_month = String(date_m);

         convert_month.toCharArray(actual_month, 3);

         tft_calendar.setCursor(150, 112);

         tft_calendar.setTextColor(WHITE);

         tft_calendar.setTextSize(2);

         tft_calendar.println(actual_month);

}

 

tft_calendar.drawLine (177, 118, 182, 118, WHITE);

tft_calendar.drawLine (177, 119, 182, 119, WHITE);

 

Um die Jahreszahl auf dem Bildschirm anzuzeigen, gibt es kein Problem mit der Anzahl der Zeichen, da es immer 4 sein werden. Die Funktionen für die Ausgabe sind die gleichen wie die der zuvor beschriebenen. Es werden nur die Namen der Variablen, des Arrays und der Ausgabekoordinaten geändert.

String convert_year = String(date_y);

convert_year.toCharArray(actual_year, 5);

tft_calendar.setCursor(188, 112);

tft_calendar.setTextColor(WHITE);

tft_calendar.setTextSize(2);

tft_calendar.println(actual_year);

 

Um das Bild der Mondphase darzustellen, nutzen wir einen grauen Kreis für den Neumond, einen weißen für den Vollmond und für die zunehmende und abnehmende Phase zwei übereinanderliegende Kreise, einen weißen zuerst und einen schwarzen danach, so dass der schwarze Kreis die Überschneidung mit dem weißen Kreis "auslöscht". Außerdem werden vier Bilder jeder zunehmenden und abnehmenden Phase verwendet. Wie Sie sich vielleicht erinnern, beträgt die Zeitspanne zwischen den Neumonden 29,5 Tage, der erste Neumond des Jahres 2024 fand am 10. Januar statt, also am zehnten Tag des Jahres und wenn wir die Gesamtzahl der Tage kennen, die seit dem ersten Neumond vergangen sind, können wir den Stand der Mondphase berechnen.

Um die seit dem 1. Januar 2024 verstrichenen Tage zu berechnen, wurde ein Aufruf der Methode days_from_2024(date_y, date_m, date_d) erstellt, der den aktuellen Tag, den Monat und das Jahr als Parameter erhält und die Anzahl der verstrichenen Tage zurückgibt, die in der Variablen total_past_days vom Typ int gespeichert werden. Der Wert der Variablen wird vom Serial Monitor angezeigt.

int total_past_days = days_from_2024(date_y, date_m, date_d);

Serial.print("Days since January 1, 2024: ");

Serial.println(total_past_days); 

Beim Aufruf der Methode int days_from_2024(int date_y, int date_m, int date_d) für die Berechnung der insgesamt verstrichenen Tage werden das aktuelle Jahr, der Monat und der Tag empfangen. Dann wird die erste Bedingung ausgeführt, wenn das Jahr gleich oder größer als 2024 ist. Wenn dies der Fall ist, wird das Jahr 2024 vom aktuellen Jahr subtrahiert, das Ergebnis wiederum in der Jahresvariablen mit date_y -= 2024 gespeichert und vom Serial Monitor angezeigt.

int days_from_2024(int date_y, int date_m, int date_d) {

         if (date_y >= 2024) {

                 date_y -= 2024;

                 Serial.print("Past years: ");

                 Serial.println(date_y);

  }

Die empfangenen Tage werden in der Variablen past_days = date_d gespeichert, ihr Wert wird auch vom Serial Monitor angezeigt.

past_days = date_d;

Serial.print("Days gone: ");

Serial.println(past_days);

 

Um die Anzahl der vergangenen Tage der Monate zu berechnen, wird eine Schleife implementiert, die die Anzahl der Tage jedes vergangenen Monats zählt, wobei der Zähler als Maximalwert den Monat vor dem aktuellen hat  c < date_m. Die gezählten Tage jedes Monats werden zur Variablen past_days hinzugefügt. Das Array daysInMonth[c] enthält die Anzahl der Tage, die jeder Monat hat, der Zähler c, der übergeben wird, ist der Index für den Monat im Array. Die Position 0 hat den Wert von 0 Tagen. Da der erste Monat des Jahres die Nummer 1 hat, beginnt der Zähler mit der Position 1 des Arrays.

for (byte c = 1; c < date_m; c = c + 1) {

         past_days = past_days + daysInMonth[c];

         Serial.print("Days gone by months: ");

         Serial.println(past_days);

}

 

Falls das aktuelle Jahr ein Schaltjahr ist, muss für den Monat Februar ein zusätzlicher Tag hinzugefügt werden. Das passiert unter den Bedingungen, dass der aktuelle Monat größer ist als der Monat 2 des Jahres, außerdem muss auch der Rest 0 sein, wenn man das Jahr durch 4 teilt. Dann wird ein Tag zur Variablen past_days hinzugefügt.

if (date_m > 2 && date_y % 4 == 0) {

         past_days = past_days + 1;

         Serial.print("Days passed by leap year: ");

         Serial.println(past_days);

} 

 

Bisher haben wir die Anzahl der Tage berechnet, die im aktuellen Jahr vergangen sind, jetzt müssen wir die Anzahl der Tage berechnen, die seit dem 1. Januar 2024 vergangen sind. Dazu addieren wir zu der Anzahl der Tage, die im aktuellen Jahr vergangen sind (past_days), die Anzahl der Tage jedes Jahres seit 2024 (365 * date_y), wir addieren einen weiteren Tag für jedes Schaltjahr, das seit 2024 vergangen ist ((date_y + 3) / 4) und mit der -1 ziehen wir den aktuellen Tag ab. Die Gesamtzahl der Tage wird in der Variablen past_days gespeichert.

return past_days = past_days + (365 * date_y) + (date_y + 3) / 4 - 1;

Serial.print("Total days spent: ");

Serial.println(past_days); 

 

Die Anzahl der gesamten Tage wird mit return past_days an den Aufruf aus der Zeile int total_past_days = days_from_2024(date_y, date_m, date_d) zurückgegeben.

Der vollständige Code der Methode zur Berechnung der Anzahl der vergangenen Tage lautet:

int days_from_2024(int date_y, int date_m, int date_d) {

         if (date_y >= 2024) {

                 date_y -= 2024;

                 Serial.print("Past years: ");

                 Serial.println(date_y);

         }

         past_days = date_d;

         Serial.print("Days gone: ");

         Serial.println(past_days);

 

         for (byte c = 1; c < date_m; c = c + 1) {

                 past_days = past_days + daysInMonth[c];

                 Serial.print("Days gone by months: ");

                 Serial.println(past_days);

         }

         if (date_m > 2 && date_y % 4 == 0) {

                 past_days = past_days + 1;

                 Serial.print("Days passed by leap year: ");

                 Serial.println(past_days);

         }

 

         return past_days = past_days + (365 * date_y) + (date_y + 3) / 4 - 1;

         Serial.print("Total days spent: ");

         Serial.println(past_days);

}

 

Mit der Anzahl der Tage seit dem 1. Januar 2024 wird die aktuelle Mondphase berechnet, indem der erste Neumondtag des Jahres 2024 in der Variablen next_day_new_moon gespeichert wird.

next_day_new_moon = first_day_new_moon_2024;

 

Um zu wissen, in welchem Zeitraum von 29,5 Tagen man sich befindet, wird eine while-Schleife implementiert. Solange die Variable total_past_days einen größeren Wert als die Variable next_day_new_moon hat, bedeutet dies, dass man sich nicht im Zeitraum von 29,5 Tagen der aktuellen Mondphase befindet, der Wert der Variablen new_moon_period wird zu dieser letzten Variablen addiert und der Vergleich wird erneut durchgeführt, bis sein Wert größer ist als der Wert der Variablen total_past_days.

while (total_past_days > next_day_new_moon) {

         next_day_new_moon += new_moon_period;

         Serial.print("Next day moon: ");

         Serial.println(next_day_new_moon);

}

 

Wenn die Schleife verlassen wird, weil der Wert der Variablen next_day_new_moon größer ist, wird der Wert der Variablen total_past_days subtrahiert. Das Ergebnis der Subtraktion ist die Anzahl der Tage, die seit dem letzten Neumond vergangen sind. Der Wert wird in der Variablen state_moon gespeichert.

float state_moon = next_day_new_moon - total_past_days;

 

Um ein Bild der Mondphase auf dem Bildschirm darzustellen, werden Bedingungen an die Variable state_moon geknüpft. Wenn der Wert der Variablen zwischen den angegebenen Werten liegt, wird die if-Anweisung ausgeführt. Es wird außerdem ein weißer Kreis dargestellt mit einem Radius von 30 Pixeln an den Koordinaten X = 120 und Y = 180.

if (state_moon <= 15.5 && state_moon >= 14.5) {

         Serial.println("Today is a full moon.");

         tft_calendar.fillCircle (120, 180, 30, WHITE);

}

 

Für die zu- und abnehmende Mondphasen werden zuerst ein weißer Kreis und dann ein schwarzer Kreis dargestellt, wobei der letztere schwarze Kreis seinen Schnittfläche mit dem weißen Kreis einnimmt, so dass dem weißen Kreis diese Fläche mit dem schwarzen Kreis fehlt und das Bild des Mondzustands angezeigt wird.

if (state_moon <= 28.4 && state_moon > 25.2) {                                                                          

        Serial.println("Today is the crescent moon.");

        tft_calendar.fillCircle (120, 180, 30,WHITE);

        tft_calendar.fillCircle (103, 180, 35, BLACK);

}

 

Jetzt bleibt nur noch die Darstellung des möglichen Zustands des Himmels in Abhängigkeit vom Luftdruck. Zur Darstellung der Symbole für Regen, Wolke mit Sonne und Sonne wurden vier Methoden definiert, die mit Linien die Symbole darstellen.

Wenn der vom Sensor gemessene Druck zwischen den Werten einer dieser Bedingungen liegt, wird deren if-Anweisung ausgeführt und die darin enthaltene(n) Methode(n) aufgerufen.  

if (pressu < 1000) {

         cloud();

         rain();

}

if (pressu >=1000 && pressu <= 1020) {

         cloud();

         sun_in_cloud();

}

if (pressu > 1020) {

         sun();

}

 

Damit ist der Code der refresh_screens()-Methode fertig und das Barometer ist voll funktionsfähig. Die Daten auf dem Bildschirm werden jede Minute aktualisiert und Sie können ablesen, ob Sie einen Regenschirm oder einen Hut mitnehmen sollten.

Sketch Download

Da das Projekt im Jahr 2024 enstanden ist, sollten Sie die Jahreszahl im Quellcode anpassen.

Sollte das Video nicht angezeigt werden, überprüfen Sie bitte die Cookie-Einstellungen Ihres Webbrowsers.

Wir hoffen, dass Ihnen dieses Barometer gefällt. Sie können dieses Projekt gerne an Ihre Bedürfnisse anpassen und wir freuen uns auf Ihre Kommentare.

Nachtrag

Der User Martin hat nach Veröffentlichung von Teil 2 bereits Änderungen vorgenommen und Motoren für zwei sich bewegende Figuren hinzugefügt. Zu finden ist das Projekt auf Github.

 

DisplaysEsp-32Projekte für anfängerSensoren

2 Kommentare

Achim

Achim

Hallo,
als Softwareentwickler der schon mit dem y2k-Bug zu kämpfen hatte ist mir aufgefallen, dass die Schaltjahresberechnung unvollständig ist.
Die gregorianische Schalttagsregelung besteht aus folgenden drei einzelnen Regeln:
1. Die durch 4 ganzzahlig teilbaren Jahre sind, abgesehen von den folgenden Ausnahmen, Schaltjahre.
2. Säkularjahre, also die Jahre, die ein Jahrhundert abschließen (z. B. 1800, 1900, 2100 und 2200), sind, abgesehen von der folgenden Ausnahme, keine Schaltjahre.
3. Die durch 400 ganzzahlig teilbaren Säkularjahre, zum Beispiel das Jahr 2000, sind jedoch Schaltjahre.

Viele Grüße

Achim

Ezio Cogoli

Ezio Cogoli

Bel progetto e non troppo complicato nell’esecuzione, complimenti.

Kommentar hinterlassen

Alle Kommentare werden von einem Moderator vor der Veröffentlichung überprüft

Empfohlene Blogbeiträge

  1. ESP32 jetzt über den Boardverwalter installieren - AZ-Delivery
  2. Internet-Radio mit dem ESP32 - UPDATE - AZ-Delivery
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1 - AZ-Delivery
  4. ESP32 - das Multitalent - AZ-Delivery