[gelöst] Wetterstation mit Uhr

Hallo zusammen,

ich bin relativ neu im Bereich der Programmierung und versuche mich daher mit “Suchen” und “Finden” durch meine Projekte zu hangeln. Ich habe zwar schon einiges zu dem Thema gelesen aber da ich die Programmiersprache nur bedingt verstehe bräuchte ich nun doch etwas Hilfe. Mein aktuelles Projekt ist wie der Name schon sagt eine Wetterstation mit seperater Uhr.

Zur Hardware:

  • 1 Arduino Uno
  • 1 DS3231 RTC
  • 1 BME280
  • 1 1,8 Zoll TFT Display
  • 1 7 Segment Display

Die Idee:
Ich will auf dem 1,8 Zoll Display die Temperatur, den Luftdruck und die Luftfeuchtigkeit angezeigt bekommen und paralell auf der Segmentanzeige die Uhrzeit.

Vorgehensweise:
Da ich das erste mal mit den oben aufgeführten Komponenten gearbeitet habe, habe ich als erstes die Beispielsketches aus den Bibliotheken von Adafruit genommen und diese einzeln zum laufen gebracht und angepasst bis ich hjatte was mir gefällt. Hat super funktioniert. Als dies erledigt war habe ich mir gedacht, dass ich beide Sketches zusammen führen müsste damit beides läuft. Dies habe ich getan.

Problem:
Seit dem zusammenführen der beiden Sketches blinken die Messwerte (Temperatur, Luftdruck und Luftfeuchtigkeit) alle 2s kurz. Ich vermute, dass das etwas mit der aktualsierung zu tun hat. Als der Sketch “bme280test” aber noch allein lief hat es funktioniert. Könnte sich bitte jemand meinen Sketch ansehen und mir nene Tip geben wo ich flasch abgebogen bin?

Danke schonmal für die Hilfe.

#include <TFT.h>
#include <SPI.h>
#include <Seeed_BME280.h> 
#include <Wire.h> 
#include "RTClib.h"
#include <TM1637Display.h>

BME280 bme280;

 #define cs   10
 #define dc   9
 #define rst  8
 #define CLK 2
 #define DIO 3

  TFT TFTscreen = TFT(cs, dc, rst);
  RTC_DS3231 rtc;
  TM1637Display display = TM1637Display(CLK, DIO);


char TempPrintout[6];
char DruckPrintout[6];
char FeuchtPrintout[3];

void setup() {
   Serial.begin(9600);
   delay(3000);
   if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1); }
  if (rtc.lostPower()) {
    Serial.println("RTC lost power, lets set the time!");
    // The following line sets the RTC to the date & time this sketch was compiled:
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); }

  // Set the display brightness (0-7):
  display.setBrightness(5);
  // Clear the display:
  display.clear();
   TFTscreen.begin();
 
   TFTscreen.background(0, 0, 0);
   TFTscreen.stroke(255,255,255);
   TFTscreen.setTextSize(1);
   TFTscreen.text("Temperatur",10,10);
   TFTscreen.text("Luftdruck",10,50);
   TFTscreen.text("Luftfeuchtigkeit",10,90);
   
   TFTscreen.setTextSize(0.3);
   TFTscreen.text("o",83,23);
   
   TFTscreen.setTextSize(2);
   TFTscreen.text("C",90,25);
   TFTscreen.text("hPa",90,65);   
   TFTscreen.text("%",90,105);
   
   Serial.begin(9600); // Einstellen der Baudrate
   if(!bme280.init()) // Wenn keine Daten vom BME abgefragt werden können...
   
        {
          Serial.println("FEHLER!"); // ...dann soll eine Fehlermeldung ausgegeben werden.
        }
}

void loop() {
  DateTime now = rtc.now();
  int displaytime = (now.hour() * 100) + now.minute();
  Serial.println(displaytime);
  display.showNumberDecEx(displaytime, 0b11100000, true);
  
  float Pascal =bme280.getPressure();
  float hPa = Pascal/100;
  
  String Temp = String(bme280.getTemperature());
  Temp.toCharArray(TempPrintout, 6);

  String Druck = String(hPa);
  Druck.toCharArray(DruckPrintout, 6);
  
  String Feuchte = String(bme280.getHumidity());
  Feuchte.toCharArray(FeuchtPrintout, 3);

  if(bme280.getTemperature()>26)
  {TFTscreen.stroke(0,0,255);}
  else if(bme280.getTemperature()<20)
  {    TFTscreen.stroke(255,0,0); }
  else
  {  TFTscreen.stroke(255,255,255); }
  
  TFTscreen.setTextSize(2);
  TFTscreen.text(TempPrintout, 10, 25);
  TFTscreen.stroke(255,255,255);
  TFTscreen.text(DruckPrintout, 10, 65);
  TFTscreen.text(FeuchtPrintout, 10, 105);
 
delay(1000);

  display.showNumberDec(displaytime, true);

delay(1000);

  TFTscreen.stroke(0,0,0);
  TFTscreen.text(TempPrintout, 10, 25);
  TFTscreen.text(DruckPrintout, 10, 65);
  TFTscreen.text(FeuchtPrintout, 10, 105);
}

du druckst deine Texte im Loop zweimal

warum machst du das am Ende von Loop noch mal?

TFTscreen.stroke(0,0,0);
TFTscreen.text(TempPrintout, 10, 25);
TFTscreen.text(DruckPrintout, 10, 65);
TFTscreen.text(FeuchtPrintout, 10, 105);

marcelbastler:
ich bin relativ neu im Bereich der Programmierung und versuche mich daher mit "Suchen" und "Finden" durch meine Projekte zu hangeln.

Du hast die Codetags für die Formatierung Deines Beitrages gefunden - da ist nicht trial & error..

zu dem, was noiasca schon schrub:

  delay (1000);
  display.showNumberDec (displaytime, true);
  delay (1000);

davon abgesehen, das delay nur zu Versuchszwecken verwendet werden sollte, wäre es angebracht sich zu entscheiden, ob die Wartezeit insgesamt vor oder nach der Ausgabe erfolgen soll...

delay als solches im laufeden Code ist nicht hilfreich. Wie das umgangen werden kann, ist in dem CodeBeispiel "Blink without delay" erklärt. Notfalls hier nochmal fragen...

Danke erstmal für die Hilfe.

noiasca:
du druckst deine Texte im Loop zweimal

warum machst du das am Ende von Loop noch mal?

TFTscreen.stroke(0,0,0);
TFTscreen.text(TempPrintout, 10, 25);
TFTscreen.text(DruckPrintout, 10, 65);
TFTscreen.text(FeuchtPrintout, 10, 105);

Warum ich das tue ist schnell erklärt. Es steht in dem Beispiel der Libary
https://www.arduino.cc/en/Tutorial/LibraryExamples/TFTDisplayText

my_xy_projekt:

  delay (1000);

display.showNumberDec (displaytime, true);
  delay (1000);




davon abgesehen, das delay nur zu Versuchszwecken verwendet werden sollte, wäre es angebracht sich zu entscheiden, ob die Wartezeit insgesamt vor oder nach der Ausgabe erfolgen soll...

delay als solches im laufeden Code ist nicht hilfreich. Wie das umgangen werden kann, ist in dem CodeBeispiel "Blink without delay" erklärt. Notfalls hier nochmal fragen...

Die habe ich aus dem Beispielsketch von Adafruit. Warum das so ist weiß ich leider nicht.

/* Arduino example code to display a 24 hour time format clock on a TM1637 4 digit 7 segment display with a DS32321 RTC. More info: www.makerguides.com */

// Include the libraries:
#include "RTClib.h"
#include <TM1637Display.h>

// Define the connections pins:
#define CLK 2
#define DIO 3

// Create rtc and display object:
RTC_DS3231 rtc;
TM1637Display display = TM1637Display(CLK, DIO);

void setup() {
  // Begin serial communication at a baud rate of 9600:
  Serial.begin(9600);
  // Wait for console opening:
  delay(3000);

  // Check if RTC is connected correctly:
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  // Check if the RTC lost power and if so, set the time:
  if (rtc.lostPower()) {
    Serial.println("RTC lost power, lets set the time!");
    // The following line sets the RTC to the date & time this sketch was compiled:
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    //rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }

  // Set the display brightness (0-7):
  display.setBrightness(5);
  // Clear the display:
  display.clear();
}

void loop() {
  // Get current date and time:
  DateTime now = rtc.now();

  // Create time format to display:
  int displaytime = (now.hour() * 100) + now.minute();

  // Print displaytime to the Serial Monitor:
  Serial.println(displaytime);

  // Display the current time in 24 hour format with leading zeros enabled and a center colon:
  display.showNumberDecEx(displaytime, 0b11100000, true);

  // Remove the following lines of code if you want a static instead of a blinking center colon:
  delay(1000);

  display.showNumberDec(displaytime, true); // Prints displaytime without center colon.

  //delay(1000);
}

Wie ich eingangs schon erwähnte verstehe ich einige Teile des Sketches nicht und habe nur zwei funktionierende zusamenkopiert.

marcelbastler:
Danke erstmal für die Hilfe.

Bitte! Gerne!

Warum ich das tue ist schnell erklärt. Es steht in dem Beispiel der Libary
Die habe ich aus dem Beispielsketch von Adafruit. Warum das so ist weiß ich leider nicht.

/* Arduino example code 

// Remove the following lines of code if you want a static instead of a blinking center colon:
  delay(1000);
  display.showNumberDec(displaytime, true); // Prints displaytime without center colon.
  //delay(1000);
}



Wie ich eingangs schon erwähnte verstehe ich einige Teile des Sketches nicht und habe nur zwei funktionierende zusamenkopiert.

Alles gut - ich muss schon sagen, adafruit ist da etwas Kreativ mit den delays…

Allerdings ist das eben auch nur ein Beispielcode.
Du wirst nicht umhinkommen, Dich mit den Lib’s auseinanderzusetzen um den Code zu verstehen, der Dir zur Verfügung gestellt wurde.

Um das abzukürzen lies meine Kommentare - vielleicht ergibt sich ja was…

if (bme280.getTemperature() > 26)   // Wenn die temperatur > 26°C
  {
    TFTscreen.stroke (0, 0, 255); // soll stroke 0,0,255
  }
  else
    if (bme280.getTemperature() < 20) // Wenn die temperatur < 20°C
    {
      TFTscreen.stroke (255, 0, 0); soll stroke 255,0,0,
    }
    else
    {
      TFTscreen.stroke (255, 255, 255); // Und wenn alles nicht, dann stroke 255,255,255
    }
  TFTscreen.setTextSize (2);
  TFTscreen.text (TempPrintout, 10, 25);
  TFTscreen.stroke (255, 255, 255); // egal was vorher war: hier wird stroke IMMER 255,255,255
  TFTscreen.text (DruckPrintout, 10, 65);
  TFTscreen.text (FeuchtPrintout, 10, 105);
  delay (1000);
  display.showNumberDec (displaytime, true);
  delay (1000);
  TFTscreen.stroke (0, 0, 0); // und hier wird stroke IMMER 0,0,0 - womit das blinken sein sollte
  TFTscreen.text (TempPrintout, 10, 25);
  TFTscreen.text (DruckPrintout, 10, 65);
  TFTscreen.text (FeuchtPrintout, 10, 105);
}

Du hast mit deinen Kommentare recht. Genau das was du geschrieben hast ist der Gedanke dahinter. Die If Anweisungen waren nur ne Spielerei von mir.

die letzte stroke Anweisung soll die alten Werte löschen damit die neuen geschrieben werden können. So wie es im Beispiel der Libary steht. Das hat auch mal funktioniert. Ich habe jetzt den Sketch zurückgesetzt und betreib nur das TFT Display und den bme280. ABer leider funktioniert es auch dann nicht.

Wie könnte ich das sonst lösen? Ich muss am Ende vom Loop die Werte "entfernen" das ich danach neu schreiben kann.

Ich habe mir jetzt mal die Funktion "blink without delay" angesehen. Jetzt bin ich aber langsam komplett konfus.

  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

Wenn ich das richtig verstehe prüft die If Schleife, ob die vergangene Zeit größer oder gleich ist als der fetsgelegt intervall. Wenn das nicht ist läuft der loop einfach weiter.
Wenn ich das auf mein Problem umsetze habe ich aber das Problem, dass der loop ja nicht laufen soll sindern warten soll.
Hier mein Beispiel:

void loop() {
  String Temp = String(bme280.getTemperature());
  Temp.toCharArray(TempPrintout, 6);

  TFTscreen.stroke(255,255,255); //setzt die Schriftfarbe auf Weiß
  TFTscreen.text(TempPrintout, 10, 25); //schreibt den Temperaturwert auf das Display

  unsigned long currentMillis = millis(); // Aktuelle Zeit wird in currentMillis gespeichert

  if (currentMillis - previousMillis > interval) { // Falls mehr als 1000 ms vergangen sind
     previousMillis = currentMillis; // Zeitpunkt der letzten Schaltung wird festgehalten 
  TFTscreen.stroke(0,0,0); //setzt die Schriftfarbe auf Schwarz
  TFTscreen.text(TempPrintout, 10, 25); //Schreibt eine Wert damit die Schriftfarbe wirksam wird
  }
}

Bei diesem Beispiel passiert aber folgendes. Solang der Warteintervall nicht erreicht ist, überschreibt der Loop andauernd der Wert auf dem Display. Es muss doch aber der Wert auf dem DIsplay gelöscht werden bevor eine neuer Wert geschrieben werden kann.

marcelbastler:
Bei diesem Beispiel passiert aber folgendes. Solang der Warteintervall nicht erreicht ist, überschreibt der Loop andauernd der Wert auf dem Display. Es muss doch aber der Wert auf dem DIsplay gelöscht werden bevor eine neuer Wert geschrieben werden kann.

Ich glaube Du hast das nicht ganz verstanden.
Schau mal den Code an.

   unsigned long previousMillis = 0;
  const unsigned long sekundenintervall = 1000;
void setup()
{
  
}
void loop()
{
  if ((millis() - previousMillis) > (sekundenintervall / 2)) // halbes Intervall
  {
    // Mache hier den Tick für die Uhr
  }
  if (millis() - previousMillis > sekundenintervall)   // Falls mehr als 1000 ms vergangen sind
  {
    previousMillis=millis();
    // HIER kommt rein, was Du im Sekundentakt machen willst
  }
  // Ab hier kommt alles andere hin, was ohne Einwirkung von sekundenintervall ist
}

Ok. Das habe ich verstanden. Das funktionert auch. Das Problem mit dem kurzen schwarz wedren der ANzeige besteht weiterhin. Ich denke, dass es an dem TFTscreen.stroke liegt.

Aus meiner Sicht stellen sich jetzt zwei Möglichkeiten:

  1. ich nutze das kurze flackern um den Wert zu wechseln und zeige dei Werte nacheinander an oder
  2. ich kann den TFT Bildschirm irgendwie anders überschreiben.

Zu 1.
Wie kann ich eine zeitliche Ablaufsteuerung ohne delay realisieren? In deinem Beispiel wird die Anzeige im Sekundentakt aktualisiert.

   Temperatur(255); /getrennt siehe unten im Post

     if (millis() - previousMillis > sekundenintervall)   // Falls mehr als 2000 ms vergangen sind
  {
    previousMillis=millis();
    Temperatur(0);
    // HIER kommt rein, was Du im Sekundentakt machen willst
  }

Wie sieht eine zeitliche Ablaufsteuerung aus, bei der ich folgende Schritte nacheinander durchführen will:

  1. Temperatur anzeigen (5 Sekunden)
  2. Anzeige leeren und Luftdruck anzeigen (5 Sekunden)
  3. Anzeige leeren und Luftfeuchtigkeit anzeigen (5 Sekunden)

Ich habe die Temperatur getrennt

void Temperatur(int Farbe){
  TFTscreen.stroke(Farbe,Farbe,Farbe); 
  TFTscreen.setTextSize(4);
  TFTscreen.text(TempPrintout, 40, 60); //Schreibt eine Wert damit die Schriftfarbe wirksam wird
  TFTscreen.setTextSize(2);
  TFTscreen.text("Temperatur", 20, 30);
  TFTscreen.setTextSize(0.3);
  TFTscreen.text("o",93,58);
  TFTscreen.setTextSize(4);
  TFTscreen.text("C",100,60);
  }

Also ich muss euch sagen das meine Frustration mittlerweile keine Grenzen mehr kennt. Ich habe heute den ganzen Tag versucht das Ding zum laufen zu bekommen und jedes mal sind die Probleme größer geworden.

Hier ist der Sketch an dem ich jetzt verzweifelt bin.

#include <TFT.h>
#include <SPI.h>
#include <Seeed_BME280.h> 
#include <Wire.h> 
#include "RTClib.h"
#include <TM1637Display.h>

BME280 bme280;

 #define cs   10
 #define dc   9
 #define rst  8
 #define CLK 2
 #define DIO 3

TFT TFTscreen = TFT(cs, dc, rst);
RTC_DS3231 rtc;
TM1637Display display = TM1637Display(CLK, DIO);

char TempPrintout[3];
char DruckPrintout[6];
char FeuchtPrintout[3];

   unsigned long previousMillis = 0;
   const unsigned long sekundenintervall = 1000;
   const unsigned long anzeigedauerTemp = 4000;
   const unsigned long anzeigedauerFeucht = anzeigedauerTemp*2;
   const unsigned long anzeigedauerDruck = anzeigedauerTemp*3;


void setup() {
   TFTscreen.begin();
 
   TFTscreen.background(0, 0, 0);
   TFTscreen.stroke(255,255,255);
   
   Serial.begin(9600); // Einstellen der Baudrate
   if(!bme280.init()) // Wenn keine Daten vom BME abgefragt werden können...
   
        {
          TFTscreen.text("FEHLER!",10,25); // ...dann soll eine Fehlermeldung ausgegeben werden.
        }
  display.setBrightness(5);
  display.clear();

}

void loop() {
  DateTime now = rtc.now();

 // Variablen deklarieren
  int displaytime = (now.hour() * 100) + now.minute();
  float Pascal = bme280.getPressure();
  float hPa = Pascal/100;
  String Druck = String(hPa);
  
  String Temp = String(bme280.getTemperature());
  Temp.toCharArray(TempPrintout, 3);
  String Feuchte = String(bme280.getHumidity());
  Feuchte.toCharArray(FeuchtPrintout, 3);
  Druck.toCharArray(DruckPrintout,6);

  if ((millis() - previousMillis > sekundenintervall)&(millis() - previousMillis < sekundenintervall*2)){ 
    display.showNumberDecEx(displaytime, 0b11100000, true);
    }
  if (millis() - previousMillis > sekundenintervall*2){
    display.showNumberDec(displaytime, true);
  }

  if (millis() - previousMillis < anzeigedauerTemp){ // die ersten x Sekunden wird die Temperatur angezeigt
    Temperatur(255);
    }
    
  if ((millis() - previousMillis > anzeigedauerTemp) &(millis() - previousMillis < anzeigedauerTemp+1000)) { //nach x Sekunden wird der TFT Screen geleert
    Temperatur(0);
    }
  
  if ((millis() - previousMillis > anzeigedauerTemp+1000) &(millis() - previousMillis < anzeigedauerFeucht)){ // danach wird bis zur 2 fachen Anzeigedauer angezeigt 
    Luftfeuchtigkeit(255);
    }
  
 if ((millis() - previousMillis > anzeigedauerFeucht)&(millis() - previousMillis < anzeigedauerFeucht+1000)) { // Anzeige leeren
    Luftfeuchtigkeit(0);
    }

if ((millis() - previousMillis > anzeigedauerFeucht+1000) &(millis() - previousMillis < anzeigedauerDruck)){ // danach wird bis zur 3 fachen Anzeigdauer angezeigt
    Luftdruck(255);
    }
if ((millis() - previousMillis > anzeigedauerDruck)&(millis() - previousMillis < anzeigedauerDruck+1000)){
    Luftdruck(0);
    }
if (millis() - previousMillis > anzeigedauerDruck+1000){
    previousMillis=millis();
    }
}

void Temperatur(int Farbe){
  TFTscreen.stroke(Farbe,Farbe,Farbe); 
  TFTscreen.setTextSize(4);
  TFTscreen.text(TempPrintout, 40, 60); //Schreibt eine Wert damit die Schriftfarbe wirksam wird
  TFTscreen.setTextSize(2);
  TFTscreen.text("Temperatur", 20, 30);
  TFTscreen.setTextSize(0.3);
  TFTscreen.text("o",93,58);
  TFTscreen.setTextSize(4);
  TFTscreen.text("C",100,60);
  }

 void Luftfeuchtigkeit(int Farbe){
  TFTscreen.stroke(Farbe,Farbe,Farbe); 
  TFTscreen.setTextSize(4);
  TFTscreen.text(FeuchtPrintout, 40, 80); //Schreibt eine Wert damit die Schriftfarbe wirksam wird
  TFTscreen.setTextSize(2);
  TFTscreen.text("Luft-",50,30);
  TFTscreen.text("feuchtigkeit", 10, 50);
  TFTscreen.setTextSize(4);
  TFTscreen.text("%",100,80);
 }

 void Luftdruck(int Farbe){
  TFTscreen.stroke(Farbe,Farbe,Farbe); 
  TFTscreen.setTextSize(3);
  TFTscreen.text(DruckPrintout, 10, 60); //Schreibt eine Wert damit die Schriftfarbe wirksam wird
  TFTscreen.setTextSize(2);
  TFTscreen.text("Luftdruck", 20, 30);
  TFTscreen.setTextSize(3);
  TFTscreen.text("hPa",110,60);
  
 }

Es ergeben sich folgende Probleme:

  • Da die Schleifen immer durchlaufen werden, schreibt der Sketch auch immer Werte auf das Display. Wenn sich diese aber ändern werden beim löschen nicht alle Bildpunkte gelöscht. Dadurch bleiben immer Textreste auf dem Display zurück die erst beim neuen Start des Loops gelöscht werden.
  • Die Uhr zeigt zwar die Zeit an. Jedoch blinken die beiden Punkte in der Mitte nicht mehr da diese ja im Sekundentakt aus und angeschaltet werden müssen.

Ich habe langsam keine Ahnung mehr was ich noch machen soll. So langsam glaube ich, es geht ohne delay doch nicht.
:sob:

Das geht ohne delay() - daran glaube ich ganz fest.

Wenn Du für die Werte eine nicht-proportionale Schrift oder eine proportionale mit der Zusatzeigenschaft "alle Ziffern gleich breit" verwendest und die Hintergrundpixel mitschreibst, sollte es keine Restpixel geben.

Hilfsweise: TFT zieht doch die Adafruit-GFX an. Da gibt es eine Methode getTextBounds(). Damit kannst Du die Größe des alten Textes bestimmen, das Hintergrund-Rechteck löschen und dann den neuen Text drüberbraten.

wno158:
Das geht ohne delay() - daran glaube ich ganz fest.

Aber wie?

wno158:
Wenn Du für die Werte eine nicht-proportionale Schrift oder eine proportionale mit der Zusatzeigenschaft "alle Ziffern gleich breit" verwendest und die Hintergrundpixel mitschreibst, sollte es keine Restpixel geben.

Das sagt mir alles nix. Hast du ein Beispiel oder eine Libary in der ich das sehen kann?

wno158:
Hilfsweise: TFT zieht doch die Adafruit-GFX an. Da gibt es eine Methode getTextBounds(). Damit kannst Du die Größe des alten Textes bestimmen, das Hintergrund-Rechteck löschen und dann den neuen Text drüberbraten.

Sagt mir leider auch nichts. Wie geht das oder wo kann ich das nachlesen?

marcelbastler:
Wie sieht eine zeitliche Ablaufsteuerung aus, bei der ich folgende Schritte nacheinander durchführen will:

  1. Temperatur anzeigen (5 Sekunden)
  2. Anzeige leeren und Luftdruck anzeigen (5 Sekunden)
  3. Anzeige leeren und Luftfeuchtigkeit anzeigen (5 Sekunden)

Hinweis vorab:
Ich habe alles online geschrieben - die Sketches sind hier kompiliert, aber ich hab zwischendurch die Tastatur zweimal verloren. Ich würd mich freuen, wenns feedback gibt....
Ok, ich hab mal Dein nächstes Post absichtlich ignoriert.
Du verstrickst Dich in die Ausgabe, ohne das Du die vorher notwendige Schrittkette sicher abhandelst.
Eigentlich willst Du drei Schritte - jeder Schritt sogar mit gleichbleibendem Timing.

Dazu komm zurück auf Anfang und las den TFT mal ganz aussen vor!

Also Plan machen:
Du willst, das sich alle 5 Sekunden eine neue Ausgabe ergibt.
Du hast als Zeitbasis:
a) den Arduino mit millis()
b) eine externe Quelle (RTC)
Die Frage ist, wie genau soll die Ausgabe sein?
Antwort: Scheiss egal! Ob nach 5sek und 4/10sek oder 4sek und 9/10sek ein Wechsel der Ausgabe erfolgt interressiert keinen....

Also was brauchst?
Den Arduino und auf dessen Zeitbasis legst Du fest, welcher Schritt durchlaufen wird.
Es wird nichts externes angeschlossen! Das spart unnötiges Schreibseln und beendet Frustration!
Deine Schrittbasis ist 5000ms.
Dann sieht das Grundgerüst erstmal so aus:

// Forumsketch(1) https://forum.arduino.cc/index.php?topic=713953.0
const unsigned long intervall = 5000;
unsigned long lastmillis = 0;

void setup()
{
  Serial.begin (115200);
  Serial.println (F ("Start.."));
}

void loop()
{
  if (millis() - lastmillis >= intervall)
  {
    Serial.println (F ("Hier wird alle 5 Sekunden eine Ausgabe ausgelöst"));
    lastmillis = millis();
  }
}

Wenn das funktioniert, wird versucht eine Schrittkette zu bauen.
Grundsätzlich: Es muss möglich sein das jederzeit zu kürzen oder zu erweitern.
Gesucht wird jetzt für drei Schritte.
Dazu ginge die Festlegung einer Variablen mit einem Wert und dann via if zu fragen, ob der Wert dem entspricht was daraus werden soll:
Sieht dann so aus:

// Forumsketch(2) https://forum.arduino.cc/index.php?topic=713953.0
const unsigned long intervall = 5000;
unsigned long lastmillis = 0;
unsigned int schritt = 0;

void setup()
{
  Serial.begin (115200);
  Serial.println (F ("Start.."));
}

void loop()
{
  if (millis() - lastmillis >= intervall)
  {
    Serial.println (F ("Hier wird alle 5 Sekunden eine Ausgabe ausgelöst"));
    lastmillis = millis();
    schritt++;
    if (schritt == 1)
    {
      Serial.println (F ("Jetzt wird Schritt 1 ausgeführt"));
    }
    if (schritt == 2)
    {
      Serial.println (F ("Jetzt wird Schritt 2 ausgeführt"));
    }
    if (schritt == 3)
    {
      Serial.println (F ("Jetzt wird Schritt 3 ausgeführt"));
      schritt = 0; // War hier der letzte Schritt? - Dann Wert zurücksetzen
    }
  }
}

Wenn ich Dir das vorschlage, dann haut mich vermutlich eine nicht unbedeutende Menge...
Hintergrund ist, das zur Ermittlung JEDE Bedingung einzeln geprüft müsste.
Sowas geht einfacher mit switch/case Es wird ein Wert übergeben anhand derem verzweigt wird.
Das sieht dann so aus:

// Forumsketch(3) https://forum.arduino.cc/index.php?topic=713953.0
const unsigned long intervall = 5000;
unsigned long lastmillis = 0;
unsigned int schritt = 0;

void setup()
{
  Serial.begin (115200);
  Serial.println (F ("Start.."));
}

void loop()
{
  if (millis() - lastmillis >= intervall)
  {
    Serial.println (F ("Hier wird alle 5 Sekunden eine Ausgabe ausgelöst"));
    lastmillis = millis();
    schritt++;
    switch (schritt)
    {
      case 1:
        Serial.println (F ("Jetzt wird Schritt 1 ausgeführt"));
        break;
      case 2:
        Serial.println (F ("Jetzt wird Schritt 2 ausgeführt"));
        break;
      case 3:
        Serial.println (F ("Jetzt wird Schritt 3 ausgeführt"));
        schritt = 0; // War hier der letzte Schritt? - Dann Wert zurücksetzen
        break;
    }
  }
}

Noch nicht optimal. Wegen der numerischen cases streiten sich die Geister. Aber Du fängst an - also bleibst erstmal dabei.
Wichtiger ist jetzt die Behandlung der Variable Schritt.
Du weisst nicht, wann die Kette zu Ende ist - kommt ein Schritt dazu, musst Du schritt=0 an eine andere Stelle im Code setzen. Auch dafür gibt es x+1 Möglichkeiten. :wink: Zudem wäre es fatal, wenn Du wieder einen Schritt rausnimmst und das nicht merkst.
Dafür bietet switch/case das Auswerten via: default:
Das macht nichts anderes, als "wenn kein Wert in den cases zum Beenden führt, kommt das hier zur Anwendung"

Das sieht dann so aus:

// Forumsketch(4) https://forum.arduino.cc/index.php?topic=713953.0
const unsigned long intervall = 5000;
unsigned long lastmillis = 0;
unsigned int schritt = 0;

void setup()
{
  Serial.begin (115200);
  Serial.println (F ("Start.."));
}

void loop()
{
  if (millis() - lastmillis >= intervall)
  {
    Serial.println (F ("Hier wird alle 5 Sekunden eine Ausgabe ausgelöst"));
    lastmillis = millis();
    schritt++;
    switch (schritt)
    {
      case 1:
        Serial.println (F ("Jetzt wird Schritt 1 ausgeführt"));
        break;
      case 2:
        Serial.println (F ("Jetzt wird Schritt 2 ausgeführt"));
        break;
      case 3:
        Serial.println (F ("Jetzt wird Schritt 3 ausgeführt"));
        break;
      default:
        Serial.println (F ("Der Wert war nicht im case vorgesehen"));
        schritt = 0; // Wert war nicht vorgesehen - Dann Wert zurücksetzen
        break;
    }
  }
}

Wenn Du den Sketch laufen lässt, bleibt der letzte Wert (also 3) aber länger stehen als gewollt.
Darüber hinaus würde, bei einem fehlenden case 2:, die kette wieder bei 1 beginnen.
Jetzt gibt es auch wieder mehrere Varianten um das zu lösen:
Du könntest am Anfang also hier:
lastmillis = millis();
schritt++;
switch (schritt)
prüfen ob Schritt grösser als der von Dir maximal vorgegebene ist - dann dort wieder anfangen.
Das sehe dann so aus:

// Forumsketch(5) https://forum.arduino.cc/index.php?topic=713953.0
const unsigned long intervall = 5000;
unsigned long lastmillis = 0;
unsigned int schritt = 0;
const unsigned int maxschritt = 3; // Hier die Festlegung, wieviele Schritte gewollt sind

void setup()
{
  Serial.begin (115200);
  Serial.println (F ("Start.."));
}

void loop()
{
  if (millis() - lastmillis >= intervall)
  {
    Serial.println (F ("Hier wird alle 5 Sekunden eine Ausgabe ausgelöst"));
    lastmillis = millis();
    if (schritt >= maxschritt)
    {
      Serial.print (F ("Maximale Anzahl der Schritte erreicht -letzter Schritt war:"));
      Serial.println (schritt);
      schritt = 0;
    }
    schritt++;
    switch (schritt)
    {
      case 1:
        Serial.println (F ("Jetzt wird Schritt 1 ausgeführt"));
        break;
      case 2:
        Serial.println (F ("Jetzt wird Schritt 2 ausgeführt"));
        break;
      case 3:
        Serial.println (F ("Jetzt wird Schritt 3 ausgeführt"));
        break;
      default:
        Serial.println (F ("Der Wert war nicht im case vorgesehen"));
        break;
    }
  }
}

Wenn Du den Sketch am Laufen hast, probiere aus, was passiert, wenn Du case 2: komplett löschst!

Probiere JEDEN! Sketch aus.
schau Dir an, was Du wann auf dem seriellen Monitor ausgegeben bekommst.
Schalte dazu die Zeitanzeige ein - Las den/die Sketch/e ruhig eine Minute laufen.

Wenn Du das Prinzip verstanden hast und nur dann(!) kannst Du mit EINER Idee weiter machen.
Nicht alles auf Einmal.

Zum Glück warnt die Forensoftware. Mein Beitrag ist obsolet.
Um das Display kümmern wir uns, wenn Du den exzellenten Beitrag von my_xy_projekt (++) abgearbeitet hast.

wno158:
Um das Display kümmern wir uns,

Sicher?
Das überlas ich Dir :wink: Ich hab in die lib geschaut und mich abgewendet - Rein vom Aufwand her, war es mir mehr wert grundlegendes anzusprechen.

wenn Du den exzellenten Beitrag von my_xy_projekt (++) abgearbeitet hast.

THX! - dann wars doch richtig.

Super für die Umfangreiche Anleitung. Es funktionieren alle Sketches perfekt.
Ich glaube ich habe es geblickt. In dem von dir gezeigte Fall ist die Zeit wurscht da der Fall hochgezählt wird. In dem jeweiligen Fall passiert dann die Aktion.

Könnte ich jetzt parallel eine 2. Schleife laufen lassen?

// Forumsketch(2) https://forum.arduino.cc/index.php?topic=713953.0
const unsigned long intervallWetter = 500;
const unsigned long intervallZeit = 100;
unsigned long lastmillis = 0;
unsigned int schrittWetter = 0;
unsigned int schrittZeit =0;

void setup()
{
  Serial.begin (115200);
  Serial.println (F ("Start.."));
}

void loop()
{
  Serial.println (F ("loopBegin 1"));
  if (millis() - lastmillis >= intervallWetter)
  {
    Serial.println (F ("Hier wird alle 5 Sekunden eine WetterAusgabe ausgelöst"));
    lastmillis = millis();
    schrittWetter++;
    switch (schrittWetter)
    {
      case 1:
        Serial.println (F ("Jetzt wird Schritt 1 Wetter ausgeführt"));
        break;
      case 2:
        Serial.println (F ("Jetzt wird Schritt 2 Wetter ausgeführt"));
        break;
      case 3:
        Serial.println (F ("Jetzt wird Schritt 3 Wetter ausgeführt"));
        schrittWetter = 0; // War hier der letzte Schritt? - Dann Wert zurücksetzen
        break;
    }
  }

Serial.println (F ("loopBegin 2"));
  if (millis() - lastmillis >= intervallZeit)
  {
    Serial.println (F ("Hier wird alle 5 Sekunden eine ZeitAusgabe ausgelöst"));
    //lastmillis = millis();
    schrittZeit++;
    switch (schrittZeit)
    {
      case 1:
        Serial.println (F ("Jetzt wird Schritt 1 Zeit ausgeführt"));
        break;
      case 2:
        Serial.println (F ("Jetzt wird Schritt 2 Zeit ausgeführt"));
        schrittZeit = 0; // War hier der letzte Schritt? - Dann Wert zurücksetzen
        break;
    }
  }
}

Radio Eriwan antwortet: Im Prinzip ja, aber...

ad 1) Bitte die seriellen Ausgaben an die Realität angleichen (das sind jetzt nicht mehr fünf Sekunden)
ad 2) Du hast im zweiten Teil was auskommentiert. Überlege mal, ob da angesichts der unterschiedlichen Zeitbasen für Wetter (500) und Zeit (100) nicht doch was gebraucht werden könnte.

marcelbastler:
Super für die Umfangreiche Anleitung. Es funktionieren alle Sketches perfekt.

Ok. Danke - Ziel erreicht.

Könnte ich jetzt parallel eine 2. Schleife laufen lassen?

Nein. Ok - das ist gemein, aber richtig.
void loop()
ist eine Schleife.
Du kannst kein weiteres loop() parallel laufen lassen.
Es ist sicher Wortklauberei - aber in Zukunft wirst Du nicht mehr newbie sein. Dann sind solche Begrifflichkeiten tötlich...
Das was Du vor hast, geht.
Vorher eine Bitte: Du siehst oben in meinen (und auch vielen anderer User) Codeschnipseln den Hinweis auf die Verwendung "// Forumsketch(2)" Es wäre günstig, wenn Du die Zeile abänderst auf "// basiert auf [...] sonst passt das nicht in den Suchalgo...

Du hast den Sketch auch darüber hinaus verändert - damit passen einige Kommentare nicht mehr zu den Funktionen.
const unsigned long intervallWetter = 500;
wird bei Dir zu:
Serial.println (F ("Hier wird alle 5 Sekunden eine WetterAusgabe ausgelöst"));

das ich Dir da rein geschrieben habe, was passiert war Absicht.
Wenn Du Kommentare schreibst, gewöhne Dir an NIEMALS(!) feste Werte einzutragen.
Der könnte so aussehen:
"Hier wird auf Basis intervallWetter eine WetterAusgabe ausgelöst"
Damit stimmt der immer - egal welches Intervall eingestellt.

Das mit dem
Serial.println (F ("loopBegin 1"));
ist unglücklich - ich weiss, das es bei mir so ähnlich noch im Ausgangspost drin war - da gehört aber noch eine Funktion dazu. Die Zeile ist versehentlich drin geblieben und sorgt jetzt für Verwirrung.

Prinzipiell ist Dein Ansatz richtig.
Ich würde aber basierend auf dem letzten Sketch von mir aufbauen - da dort die Behandlung von maxschritt mit drin ist - dann natürlich bei Dir ebenfalls für beide Werte.

Ich glaube jetzt habe ich es.

// basiert auf [Forumsketch(2) https://forum.arduino.cc/index.php?topic=713953.0]
// Konstanten für die Wetterdaten
const unsigned long intervallWetter = 5000; // Länge des Intervalls
const unsigned int maxschrittWetter = 3; // Hier die Festlegung, wieviele Schritte gewollt sind
unsigned long Wettermillis=0;
unsigned int schrittWetter = 0;

// Konstanten für Zeitdaten
const unsigned long intervallZeit = 1000; // Länge des Intervalls
const unsigned int maxschrittZeit = 2; // Hier die Festlegung, wieviele Schritte gewollt sind
unsigned long Zeitmillis = 0;
unsigned int schrittZeit =0;

void setup()
{
  Serial.begin (115200);
  Serial.println (F ("Start.."));
}

void loop()
{
  if (millis() - Zeitmillis >= intervallZeit) //Zeit Ausgabeschleife
  {
    Serial.println (F ("Hier wird jede Sekunde eine ZeitAusgabe ausgelöst"));
    Zeitmillis = millis();
    if (schrittZeit >= maxschrittZeit)
    {
      Serial.print (F ("Maximale Anzahl der Zeit Schritte erreicht -letzter Schritt war:"));
      Serial.println (schrittZeit);
      schrittZeit = 0;
    }
    schrittZeit++;
    switch (schrittZeit)
    {
      case 1:
        Serial.println (F ("Jetzt wird Schritt 1 Zeit ausgeführt"));
        break;
      case 2:
        Serial.println (F ("Jetzt wird Schritt 2 Zeit ausgeführt"));
        schrittZeit=0;
        break;
    }
  }
  
  if (millis() - Wettermillis >= intervallWetter) //Wetterdaten Ausgabeschleife
  {
    Serial.println (F ("Hier wird alle 5 Sekunden eine WetterAusgabe ausgelöst"));
    Wettermillis = millis();
    if (schrittWetter >= maxschrittWetter)
    {
      Serial.print (F ("Maximale Anzahl der Schritte Wetter erreicht -letzter Schritt war:"));
      Serial.println (schrittWetter);
      schrittWetter = 0;
    }
    schrittWetter++;
    switch (schrittWetter)
    {
      case 1:
        Serial.println (F ("Jetzt wird Schritt 1 Wetter ausgeführt"));
        break;
      case 2:
        Serial.println (F ("Jetzt wird Schritt 2 Wetter ausgeführt"));
        break;
      case 3:
        Serial.println (F ("Jetzt wird Schritt 3 Wetter ausgeführt"));
        schrittWetter = 0; // War hier der letzte Schritt? - Dann Wert zurücksetzen
        break;
    }
  }

}

Ich habe die Zeitdaten komplett getrennt. So könnte es denke ich funktionieren.

Jetzt könnte ich mich an das Ausgabeproblem machen.

marcelbastler:
Ich glaube jetzt habe ich es.

Jetzt könnte ich mich an das Ausgabeproblem machen.

Nein. Nein.

Du verrennst Dich.
Schlaf drüber!
Mach weiter mit etwas Abstand zu Deiner bisherigen Vorgehensweise. Verstehe, was geschrieben steht.