Problem mit millis

Ich habe mir ein Sketch zusammen geraubt.
Es werden Temperatur und Luftfeuchte mit DHT22 ausgelesen und ich messe eine Spannung.
Später soll noch Strom gemessen werden.
Nun will ich mit “Millis” die Temperatur und Luftfeuchte nur alle 60 Sekunden auslesen.
Die Spannung und später der Strom sollen aber jede Änderung sofort anzeigen.
Leider wirkt sich aber die Verzögerung auch auf die Spannungsmessung aus.
Ich hänge mal den Sketch hier an. Vielleicht kann ja mal einer drüber schauen und mir meinen Fehler zeigen.

/
*https://www.arduinoforum.de/arduino-Thread-Tutorial-Temperatur-Luftfeuchte-messen-und-auf-      LCD-ausgeben
   https://github.com/adafruit/DHT-sensor-library (Achtung aus der Libray muss DHT_U.cpp und DHT_U.h
   entfernt werden.
*/

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
#include <DHT.h>

int analogInput = A1;                        // Spannung wird aus PIN A1 ausgelesen
float vout = 0.0;
float vin = 0.0;
float R1 = 100000.0;                         // Widerstandswert R1 (100K) 
float R2 = 10000.0;                          // Widerstandswert R2 (10K) 
int value = 0;

#define DHTPIN A0                            // DHT Sensor wird aus PIN A0 ausgelesen
#define DHTTYPE DHT22                    // DHT Type wird auf DHT22 festgelegt
DHT dht22(DHTPIN, DHTTYPE);           // DHTPIN und DHTTYE in dht22 definiert
unsigned long previousMillis = 0;          // speichert wie viele Sekunden seit der letzten Änderung vergangen sind
unsigned long interval = 5000;             // Interval zwischen zwei Änderungen



void setup()
{
  pinMode(analogInput, INPUT);
  Serial.begin(9600);                                // Serielle Ausgabe beginnen mit: 9600 baud
  lcd.begin(20, 4);                                   // LCD festlegen
  Serial.println("DHT22 Serielle Ausgabe");   // Begrüßung beim Aufruf vom seriellen Monitor
  dht22.begin();                                     // Auslesen des DHT22 beginnt

}

void loop()
{
  value = analogRead(analogInput);             // Werte am analogen Pin lesen
  vout = (value * 5.0) / 1024.0; 
  vin = vout / (R2 / (R1 + R2));
  
    /*  es wird kontrolliert, ob die Zeit für die Pause schon abgelaufen ist.
        Wenn die Zeitdifferenz zwischen dem letzten Abspeichern und der aktuellen Zeit größer als das
        Intervall ist, so wird die nachfolgende Funktion ausgeführt.
    */
    if (millis() - previousMillis > interval) {
      previousMillis = millis();                        // aktuelle Zeit abspeichern

      float t = dht22.readTemperature();        // Die Temperatur wird vom DHT22 ausgelesen, Wert in "t" schreiben
      float h = dht22.readHumidity();             // Die Luftfeuchte wird vom DHT22 ausgelesen, Wert in "h" schreiben

      t = t - 0.5;                              // z.B. 0,5 °C abziehen wenn Sensor ungenau
      Serial.print("Temperatur: ");        // Temperatur im Seriellen Monitor ausgeben
      Serial.print(t);                          // Temperature im Seriellen Monitor ausgeben
      Serial.print(" C\t");                    // Platzhalter zwischen Temperatur u. Luftfeuchte im Seriellen Monitor
      Serial.print("Luftfeuchte: ");         // Luftfeuchte im Seriellen Monitor ausgeben
      Serial.print(h);                          // Humidity im Seriellen Monitor ausgeben
      Serial.println(" %");                    // % im Seriellen Monitor ausgeben

      lcd.setCursor(0, 0);                       // Anfang auf Stelle 0, Zeile 0 setzen
      lcd.print("Temp. :");                      // Temp. : auf LCD ausgeben
      lcd.setCursor(9, 0);                       // Anfang auf Stelle 9, Zeile 0 setzen
      lcd.print(t, 1);                              // Wert aus "t" ausgeben (Temperatur)
      lcd.setCursor(15, 0);                     // Anfang auf Stelle 15, Zeile 0 setzen
      lcd.print("C");                               // C auf LCD ausgeben
      lcd.setCursor(0, 1);                       // Anfang auf Stelle 0, Zeile 1 setzen
      lcd.print("Luftf.:");                         // Luft.: auf LCD ausgeben
      lcd.setCursor(9, 1);                       // Anfang auf Stelle 9, Zeile 1 setzen
      lcd.print(h, 1);                              // Wert aus "h" ausgeben (Luftfeuchtigkeit)
      lcd.setCursor(15, 1);                      // Anfang auf Stelle 15, Zeile 1 setzen
      lcd.print("%");                              // % auf LCD ausgeben

      lcd.setCursor(0, 2);
      lcd.print("Spannung = ");
      lcd.print(vin);
      lcd.setCursor(15, 2);
      lcd.print(" Volt");
    }
}

Schon mal Danke

Du musst die Ausgabe der Spannung aus dem
if (millis() - previousMillis > interval) { raus nehmen.

Ich würde sie in ein eigenes if legen und nur ausgeben, wenn sich der Wert auch geändert hat etwa so

if (vin != vinalt) {
      vinalt = vin;
      lcd.setCursor(0, 2);
      lcd.print("Spannung = ");
      lcd.print(vin);
      lcd.setCursor(15, 2);
      lcd.print(" Volt");
}

Dann flackert die ASnzeige nicht so.

Gruß Tommy

Danke für deine Hilfe!

und mit diesen zwei Zeilen

if (vin != vinalt) {
vinalt = vin;

ist die Spannung dann aus den millis raus?

und mit diesen zwei Zeilen

   if (vin != vinalt) {

vinalt = vin;



ist die Spannung dann aus den millis raus?

Deine Frage versteh ich nicht.
Mit den zwei Zeilen wird dafür gesorgt, dass der Rest des Blocks bei jeder Änderung von vin genau einmal drankommt.
Nachtrag: Die Anweisungen werden optimalerweise wahnsinnig schnell und immer wieder abgearbeitet. Durch

if (millis() - prevmillis > intervall ) {
   prevmillis = millis();

wird erreicht, dass der Rest des Blocks nur einmal alleintervallMillisekunden drankommt.

Nach Geschmack und Sinn kann man diese beidenif ineinanderschachteln oder unabhängig voneinander "wahnsinnig schnell und immer wieder" prüfen.

Ich hatte geschrieben raus nehmen und in ein eigenes if legen.

Gruß Tommy

Entschuldige ich bin leider Anfänger und verstehe noch nicht viel vom Programmieren.
Habe jetzt schon zwei Tage damit verbracht und es nicht hin bekommen.

AlterMann:
Ich habe mir ein Sketch zusammen geraubt.
Es werden Temperatur und Luftfeuchte mit DHT22 ausgelesen und ich messe eine Spannung.
Später soll noch Strom gemessen werden.
Nun will ich mit "Millis" die Temperatur und Luftfeuchte nur alle 60 Sekunden auslesen.
Die Spannung und später der Strom sollen aber jede Änderung sofort anzeigen.
Leider wirkt sich aber die Verzögerung auch auf die Spannungsmessung aus.
Ich hänge mal den Sketch hier an. Vielleicht kann ja mal einer drüber schauen und mir meinen Fehler zeigen.

Ich habe Dir mal einen Beispiel-Sketch gemacht, für zwei asynchron laufende Tasks im kooperativen Multitasking.

Voltmessung und Temperaturmessung werden dabei nur "simuliert.

void setup() 
{
  // put your setup code here, to run once:
  Serial.begin(9600);  
}


unsigned long timeTemp,timeVolt, intervalTemp=30000,intervalVolt=250;


void tempMessung()
{
  Serial.println("Dummy-Temperaturmessung");
}

void voltMessung()
{
  Serial.print("Dummy-Spannung: ");
 float spannung=random(5000)/1000.0; 
 Serial.print(spannung,2);Serial.println('V');
}




void loop() 
{
 long  now=millis();
  if (now-timeTemp>=intervalTemp)
  {
    timeTemp=now;
    tempMessung();
  }
  if (now-timeVolt>=intervalVolt)
  {
    timeVolt=now;
    voltMessung();
  }
    
}

Das Intervall für die Spannungsmessung habe ich dabei auf 250 Millisekunden gesetzt.
Viel schneller aktualisiert sich die Anzeige auf Deinem Textdisplay sowieso nicht, weil die Flüssigkristalle so lahm sind.
Angezeigt wird ein zufälliger Spannungswert zwischen 0 und 5 Volt (zwei Nachkommastellen).

Das Intervall für die Temperaturmessung habe ich auf 30 Sekunden gesetzt.
Angezeigt wird alle 30 Sekunden auf Serial "Dummy-Temperaturmessung"

Teste mal die Programmlogik!
Die sollte mit Ausgabe auf LCD genau so blockierungsfrei laufen wie mit Ausgabe aufSerial.

Und die Intervalle lassen sich leicht anpassen, falls Du die Spannungsmessung doch öfter als alle 250ms haben möchtest oder die Temperaturmessung seltener als alle 30 Sekunden. Einfach im Quelltext anpassen!

Sollte now nicht static oder global sein?

ElEspanol:
Sollte now nicht static oder global sein?

Nein, die Variablen, in denen sich das Programm merkt, wann die letzte Temperaturmessung und wann die letzte Spannungsmessung gemacht wurden (timeTemp,timeVolt) sind globale Variablen. Aber now ist in meinem Programmbeispiel die laufende Zeit, die sich alle paar tausend Durchläufe in der loop() Funktion ändert und auch ändern soll, damit ab und zu mal eine neue Volt- oder Temperaturmessung gemacht wird.

Vielen Dank an alle!
@jurs
Dein Beispiel-Sketch hat mir sehr geholfen.
Das Sketch läuft jetzt fast so wie ich es wollte.
Nur für die Spannungsabfrage werden die Millis nicht berücksichtigt. Läuft ohne Verzögerung und beim Kompilieren erhalte ich folgende Warnung:
sketch_dec29b\sketch_dec29b.ino:
In function ‘void voltMessung()’:

sketch_dec29b\sketch_dec29b.ino:63:9:
warning: unused variable ‘volt’ [-Wunused-variable]

float volt = analogRead(analogInput);

Und hier der Sketch:

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
#include <DHT.h>

int analogInput = A1;                        // Spannung wird aus PIN A1 ausgelesen
float vout = 0.0;
float volt = 0.0;
float R1 = 100000.0;                         // Widerstandswert R1 (100K)
float R2 = 10000.0;                          // Widerstandswert R2 (10K)
int value = 0;

#define DHTPIN A0                            // DHT Sensor wird aus PIN A0 ausgelesen
#define DHTTYPE DHT22                        // DHT Type wird auf DHT22 festgelegt
DHT dht22(DHTPIN, DHTTYPE);                  // DHTPIN und DHTTYPE in dht22 definiert


void setup()
{
  pinMode(analogInput, INPUT);
  Serial.begin(9600);                         // Serielle Ausgabe beginnen mit: 9600baud
  lcd.begin(20, 4);                           // LCD festlegen
  Serial.println("DHT22 Serielle Ausgabe");   // Begrüßung beim Aufruf vom seriellen Monitor
  dht22.begin();                              // Auslesen des DHT22 beginnt

}
unsigned long timeT, timeVolt, intervalT = 15000, intervalVolt = 250;

void tMessung()
{
  float h = dht22.readHumidity();
  float t = dht22.readTemperature();
  Serial.print("Luftfeuchte: ");
  Serial.print(h, 1); Serial.println(" %");
  
  Serial.print("Temperatur: ");
  Serial.print(t, 1); Serial.println(" Grad");

  lcd.setCursor(0, 0);                       // Anfang auf Stelle 0, Zeile 0 setzen
  lcd.print("Temp. :");                      // Temp. : auf LCD ausgeben
  lcd.setCursor(9, 0);                       // Anfang auf Stelle 9, Zeile 0 setzen
  lcd.print(t, 1);                           // Wert aus "t" ausgeben (Temperatur)
  lcd.setCursor(15, 0);                      // Anfang auf Stelle 15, Zeile 0 setzen
  lcd.print("C");                            // C auf LCD ausgeben
  
  lcd.setCursor(0, 1);                       // Anfang auf Stelle 0, Zeile 1 setzen
  lcd.print("Luftf.:");                      // Luft.: auf LCD ausgeben
  lcd.setCursor(9, 1);                       // Anfang auf Stelle 9, Zeile 1 setzen
  lcd.print(h, 1);                           // Wert aus "h" ausgeben (Luftfeuchtigkeit)
  lcd.setCursor(15, 1);                      // Anfang auf Stelle 15, Zeile 1 setzen
  lcd.print("%");

}

void voltMessung()

{

  float volt = analogRead(analogInput);

}

void loop()
{
  long  now = millis();
  if (now - timeT >= intervalT)
  {
    timeT = now;
    tMessung();
  }
  if (now - timeVolt >= intervalVolt)
  {
    timeVolt = now;
    voltMessung();
  }



  {
    value = analogRead(analogInput);             // Werte am analogen Pin lesen
    vout = (value * 5.0) / 1024.0;
    volt = vout / (R2 / (R1 + R2));

    //Serial.print("Spannung: ");
    //Serial.print(volt, 1); Serial.println(" Volt");

    lcd.setCursor(0, 2);
    lcd.print("Spannung: ");
    lcd.print(volt, 2);
    lcd.setCursor(15, 2);
    lcd.print(" Volt");

  }
}

Da hat der Compiler recht.

void voltMessung()

{

  float volt = analogRead(analogInput);

}

Du erzeugst eine neue float-Variable volt, weist ihr einen Wert zu und dann ist die Funktion zuende.
Lass das float weg, dann wird die vorhandene globale Variable volt genutzt.

Gruß Tommy

AlterMann:
sketch_dec29b\sketch_dec29b.ino:63:9:
warning: unused variable 'volt' [-Wunused-variable]

Die Warnung bekommst Du, weil Du eine lokale Variable in einer Funktion deklariert hast, die im Programm überhaupt nicht verwendet wird.

Das ist RAM-Speicherverschwendung, sonst nichts.
Kein Fehler, der Compiler ignoriert sowas, er fragt sich nur, warum Du den Quatsch machst, eine Variable zu deklarieren, die dann nicht verwendet wird und gibt Dir per 'warning' einen Hinweis, dass da im Programm zwar nicht direkt ein fetter Fehler drin ist, dass Du aber möglicherweise ganz etwas anderes programmieren wolltest als was da im Quellcode steht?

@Tommy56
Danke
Das Kompilieren läuft jetzt, durch deinen Hinweis fehlerfrei durch. Aber die Millis werden für die Spannung nicht übernommen.
Habe "intervalVolt" auf 1000 gesetzt und mein Stufenlos regelbares Netzteil verwendet um es zu überprüfen.

Ich weiß nicht, als was Du die Intervalle ansiehst, aber beide Intervalle sind

Zeitangaben in Millisekunden

!

Wenn in meinem Programm steht:
intervalTemp=30000,intervalVolt=250;
dann bedeutet das:

Das Zeitintervall für Temperaturmessungen ist 30000 Millisekunden (=30 Sekunden)
(Alle 30 Sekunden eine Temperaturmessung)
Das Zeitintervall für Spannungsmessungen ist 250 Millisekunden
(vier Spannungsmessungen pro Sekunde)

Und bei ntervalVolt=1000 soll genau alle 1000 Millisekunden (einmal pro Sekunde) die Spannungsmessung erfolgen.
Nicht mehr und nicht weniger.

Schreib doch mal in Voltmessung eine serielle Ausgabe rein, um zu schauen, ob die überhaupt aufgerufen wird.

Gruß Tommy

OK wurde gemacht.
Die Spannung wird wie gewünscht angezeigt aber rennt durch den SerialMonitor so schnell kann ich nicht schauen. Obwohl ich 1000 millis (1Sek.) eingestellt habe. Das hatte ich auch schon mal überprüft
(siehe meinen Sketch). Habe es aber wieder raus genommen da man nicht viel sieht bei der Geschwindigkeit.

Da wäre der aktuelle Sketch mal wieder sinnvoll.

Gruß Tommy

AlterMann:
OK wurde gemacht.
Die Spannung wird wie gewünscht angezeigt aber rennt durch den SerialMonitor so schnell kann ich nicht schauen. Obwohl ich 1000 millis (1Sek.) eingestellt habe. Das hatte ich auch schon mal überprüft
(siehe meinen Sketch).

Dein in #9 geposteter Sketch hat drinstehen intervalVolt = 250;
und das bedeutet bei meinem Code: Alle 250ms eine Spannungsmessung (viermal pro Sekunde)

Das ist zum Mitlesen per Auge auf Serial tatsächlich etwas schnell.

Der aktuelle Code:

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
#include <DHT.h>

int analogInput = A1;                        // Spannung wird aus PIN A1 ausgelesen
float vout = 0.0;
float volt = 0.0;
float R1 = 100000.0;                         // Widerstandswert R1 (100K)
float R2 = 10000.0;                          // Widerstandswert R2 (10K)
int value = 0;

#define DHTPIN A0                            // DHT Sensor wird aus PIN A0 ausgelesen
#define DHTTYPE DHT22                        // DHT Type wird auf DHT22 festgelegt
DHT dht22(DHTPIN, DHTTYPE);                  // DHTPIN und DHTTYPE in dht22 definiert


void setup()
{
  pinMode(analogInput, INPUT);
  Serial.begin(9600);                         // Serielle Ausgabe beginnen mit: 9600baud
  lcd.begin(20, 4);                           // LCD festlegen
  Serial.println("DHT22 Serielle Ausgabe");   // Begrüßung beim Aufruf vom seriellen Monitor
  dht22.begin();                              // Auslesen des DHT22 beginnt

}
unsigned long timeT, timeVolt, intervalT = 15000, intervalVolt = 1000;

void tMessung()
{
  float h = dht22.readHumidity();
  float t = dht22.readTemperature();
  Serial.print("Luftfeuchte: ");
  Serial.print(h, 1); Serial.println(" %");
  
  Serial.print("Temperatur: ");
  Serial.print(t, 1); Serial.println(" Grad");

  lcd.setCursor(0, 0);                       // Anfang auf Stelle 0, Zeile 0 setzen
  lcd.print("TEMPERATUR:");                  // Temp. : auf LCD ausgeben
  lcd.setCursor(13, 0);                      // Anfang auf Stelle 9, Zeile 0 setzen
  lcd.print(t, 1);                           // Wert aus "t" ausgeben (Temperatur)
  lcd.setCursor(18, 0);                      // Anfang auf Stelle 15, Zeile 0 setzen
  lcd.print("C");                            // C auf LCD ausgeben
  
  lcd.setCursor(0, 1);                       // Anfang auf Stelle 0, Zeile 1 setzen
  lcd.print("LUFTFEUCHTE:");                 // Luft.: auf LCD ausgeben
  lcd.setCursor(13, 1);                      // Anfang auf Stelle 9, Zeile 1 setzen
  lcd.print(h, 1);                           // Wert aus "h" ausgeben (Luftfeuchtigkeit)
  lcd.setCursor(18, 1);                      // Anfang auf Stelle 15, Zeile 1 setzen
  lcd.print("%");                            // % auf LCD ausgeben

}

void voltMessung()

{

  volt = analogRead(analogInput);

}

void loop()
{
  long  now = millis();
  if (now - timeT >= intervalT)
  {
    timeT = now;
    tMessung();
  }
  if (now - timeVolt >= intervalVolt)
  {
    timeVolt = now;
    voltMessung();
  }



  {
    value = analogRead(analogInput);             // Werte am analogen Pin lesen
    vout = (value * 5.0) / 1024.0;
    volt = vout / (R2 / (R1 + R2));
  
    Serial.print("Spannung: ");
    Serial.print(volt, 1); Serial.println(" Volt");

    lcd.setCursor(0, 2);
    lcd.print("SPANNUNG: ");
    lcd.setCursor(12, 2);
    lcd.print(volt, 2);
    lcd.setCursor(18, 2);
    lcd.print("V");
    //delay(500);                       // Nur für Test
  }
}

Wenn ich diesen Code-Teil

{
  long  now = millis();
  if (now - timeT >= intervalT)
  {
    timeT = now;
    tMessung();
  }
  if (now - timeVolt >= intervalVolt)
  {
    timeVolt = now;
    voltMessung();
  }

hinter diesen Teil einfüge, funktionieren die Millis auch bei der Spannung. Aber meine Spannungsanzeige wirft völlige falche Werte aus.

value = analogRead(analogInput);             // Werte am analogen Pin lesen
    vout = (value * 5.0) / 1024.0;
    volt = vout / (R2 / (R1 + R2));

Die Funktion voltMessung wird korrekt alle soundsoviel ms aufgerufen.

Danach das ganze in jedem loop. Du musst die beiden geschweiften Klammern nach voltMessung(); rausnehmen