Sensorwerte mit Zeitabstand vergleichen

Hallo,

ich würde gern einen Sensorwert messen, eine Stunde später den gleichen Wert nochmal messen und dann beide miteinander vergleichen.
Das ganze sollte wenn möglich fortlaufend passieren.
Ich habe leider gar keine Idee. Hat jemand eine Anregung wie das geht?

Mit Delay bleibt das ganze Programm stehen, das soll nicht passieren.
Blinkwithoutdelay habe ich schon entdeckt, daraus kann -> ich <- aber nichts brauchbares machen.

mfg

Je nachdem wie deine geforderte Genauigkeit ist, kannst du eine RTC einsetzen oder die Zeit Intervalle mit einem geeigneten Timer aufbauen.

Ja das ist nicht verwunderlich das du als Anfänger noch nichts aus dem BWD-Beispiel machen kannst.

Mit fortschreitendem Wissen kannst du es dann doch.
Die Arduino-Gründer haben da zwei Sachen zusammengesetzt die jetzt seit über 10 Jahren jede Woche die gleichen Verständnisschwierigkeiten verursachen und keiner will es mal verbessern.

Diese zwei Sachen sind:

  1. in Beispielprogrammen den Befehl delay() verwenden
  2. ein BWD-Beispiel das den fundamentalen Unterschied zwischen delay() und BWD nicht herausarbeitet.

DAS verursacht die ganzen Verständnisschwierigkeiten.
Es wäre viiiiiel besser gewesen gleich über all in jedem Beispiel nur nicht blockierendes Timing als function zu verwenden damit Anfänger gar nichts anderes kennenlernen.

Wie auch immer.
Hier ist ein Demo-Code der das macht.


unsigned long MyWaitTimer = 0; // Timer-variables MUST be of type unsigned long
const byte    OnBoard_LED = 13;
// 1000 Millisekunden pro Sekunde * 60 * 60 = 3600 Sekunden = 1 Stunde
//unsigned long myWaitInterval = 1000UL * 60 * 60;
unsigned long myWaitInterval = 1000UL * 6;
int myActualMeasuring;
int myLastMeasuring;


void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println( F(__FILE__) );
  Serial.print( F("  compiled ") );
  Serial.print( F(__DATE__) );
  Serial.print( F(" ") );
  Serial.println( F(__TIME__) );
}


// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}


void doMeasuring() {
  myActualMeasuring = random(1, 10);

  Serial.print("aktuelle Messung:");
  Serial.println(myActualMeasuring);

  Serial.print("letzte Messung:");
  Serial.println(myLastMeasuring);

  Serial.print("Differenz:");
  Serial.println(myActualMeasuring - myLastMeasuring);
  Serial.print("Ich warte jetzt ");
  Serial.print(myWaitInterval / 1000);
  Serial.println(" Sekunden. Dann messe ich wieder...");
  Serial.println();

  myLastMeasuring = myActualMeasuring;
}


void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
  PrintFileNameDateTime();
}


void loop() {
  BlinkHeartBeatLED(OnBoard_LED, 250);

  if ( TimePeriodIsOver(MyWaitTimer, myWaitInterval) ) {
    doMeasuring();
  }

}

Wenn du jetzt schon deinen Code gepostet hättest, hätte man das Sensoreinlesen auch schon einbauen können.

Jetzt musste es halt selber einbauen.

vgs

wieso? hast du andere Aufgaben für Prozessor in Zwischenzeit?

Hallo,
soll es etwa jede jede Stunde sein , oder sollte es zu bestimmten Zeiten sein. Ersteres geht mit millis() ganz gut, es wird dir aber mit der Zeit wegdriften.

Ja das stimmt. Wenn es über Wochen und Monate präzise jeweils zur vollen Stunde gemessen werden soll dann bräuchte man entweder ein RTC-modul
oder einen WLAN-fähigen microcontroller wie ESP8266 / ESP32 der dann ständig mit dem WLAN verbunden ist und dann durch die WLAN-Verbindung aktuelle Uhrzeit bekommt.

vgs

Hallo esp89

Benenne einfach das "Blinkwithoutdelay" Beispiel in "RecordingWithOutDelay" um und schon hast du die Funktion, die du suchst.
Anstatt das Blinken der LED auszuführen wird die Aufzeichnungs-Vergleichsfunktion() aufgerufen.

Ich wünsche einen geschmeidigen Tag und viel Spass beim Programmieren in C++.

Ich hab das mal als Kurzsketch gebaut.
Variante 1:

const unsigned long messIntervall = 1000UL; // Zeit in ms
const byte messPin = A0;

unsigned long lastMesszeit;
unsigned int messWert, lastMesswert;


void setup()
{
  Serial.begin(115200);
  Serial.println(F("\r\nStart...\r\n"));
  lastMesswert = analogRead(messPin);
  lastMesszeit = millis();
}

void  loop()
{
  if (millis() - lastMesszeit > messIntervall)
  {
    messWert = analogRead(messPin);
    Serial.print(F("Letzter Messwert: "));
    Serial.println(lastMesswert);
    Serial.print(F("aktueller Messwert: "));
    Serial.println(messWert);
    lastMesswert = messWert;
    lastMesszeit = millis();
  }
}

Variante 2:
selbes Ergebnis - lässt sich aber später besser an Deine bisher unbekannten Bedingungen anpassen.


const unsigned long messIntervall = 1000UL; // Zeit in ms
const byte messPin = A0;

unsigned long lastMesszeit;
unsigned int messWert, lastMesswert;


void setup()
{
  Serial.begin(115200);
  Serial.println(F("\r\nStart...\r\n"));
  lastMesswert = analogRead(messPin);
  lastMesszeit = millis();
}

void  loop()
{
  if (millis() - lastMesszeit > messIntervall)
  {
    messen();
    ausgeben();
    lastMesswert = messWert;
    lastMesszeit = millis();
  }
}

void messen()
{
  messWert = analogRead(messPin);
}

void ausgeben()
{
  Serial.print(F("Letzter Messwert: "));
  Serial.println(lastMesswert);
  Serial.print(F("aktueller Messwert: "));
  Serial.println(messWert);
}
1 Like

Schau mal da rein:

Hier wird erklärt, wie das funktioniert mit den millis() ohne delay()

Vielen vielen Dank für die zahlreichen Rückmeldungen. Das geht echt schnell hier.
Es geht darum einen starken Luftdruckabfall zu messen.
Wenn das ein bisschen weg driftet ist es nicht schlimm, muss nicht genau zur vollen Stunde sein.
Es soll mit anderem Code verbunden werden, der existiert aber noch nicht.
Ich muss mich da jetzt erstmal rein fuchsen. Ich denke das wird klappen :slight_smile:

1 Like

Meine Lösung für das Problem sieht so aus. Ich habe es mit kleineren Werten getestet und es scheint zu funktionieren. Sollte jemand Fehler finden, würde ich mich über Hinweise freuen :slight_smile:
An der Stelle auch nochmal vielen Dank für die schnelle Hilfe.

#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>

Adafruit_BMP280 bmp;

float Druck1;
float Druck2;
float Druckdiff;
String Druckabfall;
unsigned long Druckzeit;

void setup() {

  Serial.begin(9600);

  if (!bmp.begin()) {
    Serial.println("Could not find a valid BMP280 sensor, check wiring!");
    while (1)
      ;
  }
}

void loop() {

  if (millis() - Druckzeit >= 3600000) {
    Druck2 = bmp.readPressure();
    Druckdiff = Druck1 - Druck2;
    Druckzeit = millis();

    if (Druckdiff > 200.00) {
      Druckabfall = "Druckabfall";
      Serial.println(Druckabfall);
    }
    Druck1 = Druck2;
  }

  Serial.println(" ");

}

Variable entfernt
F Makro eingesetzt

#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>

Adafruit_BMP280 bmp;

float Druck1;
float Druck2;
unsigned long Druckzeit;

void setup() {
  Serial.begin(9600);
  if (!bmp.begin()) {
    Serial.println("Could not find a valid BMP280 sensor, check wiring!");
    while (1);
  }
}

void loop() {
  if (millis() - Druckzeit >= 3600000) {
    Druck2 = bmp.readPressure();
    Druckzeit = millis();
    if ((Druck1 - Druck2) > 200.0) {
      Serial.println(F("Druckabfall"));
    }
    Druck1 = Druck2;
  }
}

Warum machst Du sowas?
Das ist vollkommen überflüssig, schiebt Dir nur die Ausgabe weiter durch den Monitor und kostet Speicher.

Ich hab mir Deinen mal vorgenommen.
Wenn die Zeile raus ist, brauchst Du auf nem UNO 580 bytes globalen Speicher.
Der ist aber recht begrenzt. Fange von Anfang an, dort Speicher zu sparen.

#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>

Adafruit_BMP280 bmp;

float lastPressure;
unsigned long Druckzeit;
constexpr uint32_t intervall {3600000};
constexpr float hysterese {200.00};

void setup()
{
  Serial.begin(9600);
  if (!bmp.begin())
  {
    // EDIT
    Serial.println(F("Could not find a valid BMP280 sensor, check wiring!"));
    while (1);
  }
}

void loop()
{
  if (millis() - Druckzeit >= intervall)
  {
    Druckzeit = millis();
    float aktualPress = bmp.readPressure();
    if (lastPressure - aktualPress > hysterese)
    {
      Serial.print(F("Druckabfall bei: "));
      Serial.print(Druckzeit / 1000);
      Serial.println(F(" Sekunden"));
    }
    lastPressure = aktualPress;
  }
}

Wie Du siehst, habe ich eine globale Variable lokal gemacht, da der Inhalt nach dem Durchlauf nicht mehr gebraucht wird.
Ausserdem die magischen Zahlen zwischendurch als constante deklariert.
Und der Ausgabe sogar noch etwas mehr Informationen hinzugefügt.
Ich brauch nur 554 502 bytes :wink: (EDIT: siehe Folgeposting)

Und ich geh mal davon aus, das der Druck nicht soweit runterfällt, das die Differenz ins negative fällt.

Happy Computing.

Wenn Du den langen Text im setup noch ins F-Macro stopfst, wird es noch weniger :wink:

Gruß Tommy

Auch grad gemerkt, das ich den überseen habe - und war am editieren...
Jetzt las ichs. Sonst passt Dein text nicht zum Code :wink:

Mit der Anmerkung würde es wieder passen, also editiere ruhig.

Gruß Tommy

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.