Barometer mit BMP180

Hallo!
Mein zweites Arduino Projekt will nicht so recht.
Ich möchte ein BAROMETER mit einem BMP180 (GY-68 Board) bauen.
Auslesen des Luftdruckes und der Temperatur funktioniert wunderbar, die Werte stimmen sogar mit denen aus dem Internet überein.
Nun möchte ich aber eine Meldung haben, wenn der Akt.Luftdruck mit dem vor einer Stunde vergleichen und mit dem vor 2h verglichen eine Grenze überschreitet.

Differenz1h= (Akt LuftDruck0m) - (Luftdruck vor einer Stunde “LDruck1h”)
Differenz2h= (Akt LuftDruck0m) - (Luftdruck vor zwei Stunden “LDruck2h”)

Laut einer Wetterseite kommt nämlich bei einer Luftdruckänderung von …

+1.3hPa /h => ein Sturm mit 6-7 Bft
+2… +3hPa/h => ein Sturm mit 8-9 Bft
+3.3 hPa/h => ein Sturm mit 10 und mehr Bft
-1 … -2 hPa/h => ein Sturm mit 6-7 Bft
-2 hPa => ein Sturm mit 8-12 Bft

Eine Rote LED oder Summer soll dann angesteuert werden wenn Sturm kommt.

Aber so recht funktioniert das nicht.
Wie könnte ich das machen?
Auch, dass nach sagen wir mal 3h die Werte wieder neu angepasst werden und Hinten rausfallen, wie bei einem Schieberegister oder so und durch die neuen 1 Stunden / 2Stunden / 3 Stunden Werte überschrieben werden?

Mfg Hans

///////////////////////////////////////////////////////////////////////////////
// FUNKTION: -LuftDruck, Temp, Höhe mit BMP-180(GY-68) Drucksensor messen => OK
// HARDWARE: -Arduino NANO
//           -GY-68 Board
//   -LOP: - Meldung, LED, Piezo, wenn Sturm in Anmarsch
/////////////////////////////////////////////////////////////////////////////////

///### INCLUDES #################################################################
#include <Wire.h>
#include <Adafruit_BMP085.h>

///### VARIABLEN ... ############################################################
Adafruit_BMP085 bmp;

float LuftDruck;          // in hPa 
float LuftDruck0m;        // Meereshöhe

float Ta;                 // Aussentemperatur
float Hoehe;

// Variablen für Luftdruckvergleiche
int i=0;
float LDruck1h= 0; // besser den ersten LDruck abspeichern damit nicht gleich eine Diff vorhanden
float LDruck2h= 0;
float LDruck3h= 0;
int DiffDruck1h;  // DifferenzDruck1h= Aktueller Druck - (vor einer Stunde)
int DiffDruck2h;  // DifferenzDruck2h= Aktueller Druck - (vor 2h)
int DiffDruck3h;  // DifferenzDruck2h= Aktueller Druck - (vor 3hh)

///### SETUP #####################################################################
void setup() 
{
Serial.begin(9600);
if (!bmp.begin()) 
{
Serial.println("Keinen BMP-180 Sensor gefunden");
while (1) {}
}

}
///### LOOP ######################################################################
void loop() 
{
 
  
  
   
//### 5s Zeitscheibe ###############################################################
// Zeitscheibe_1
  static unsigned long 	Zeitscheibe_1 = 0;
  if (millis() > Zeitscheibe_1 )
  { 
    // zum Test 5s//
    Zeitscheibe_1  = millis() + 5000;      // 5000ms
   //////* Ab hier die Befehle //////////////////////////
     UPLuftDruck();   // Abs. Luftdruck aus Sensor BMP180 lesen
     UPLuftDruck0m(); // Auf SeeLevel umgerechneter Luftdruck 
     UPAnzeige();
     ;
   } // Zeitscheibe_1 Ende ###//  

//### 1h Zeitscheibe ###############################################################
// Zeitscheibe_1
  static unsigned long 	Zeitscheibe_2 = 0;
  if (millis() > Zeitscheibe_2 )
  { 
    // zum Test 20s, sonst 3600000//
    Zeitscheibe_2  = millis() + 20000;      // 3600s x 1000ms
   //////* Ab hier die Befehle //////////////////////////
   UPLuftDruckSpeicherUndVergleich();
     ;
   } // Zeitscheibe_2 Ende ###//  

 } // Ende MAIN LOOP

///### UNTERPROGRAMME #############################################################
// LuftDruck (PH) absolut in 270m Höhe --------------------------------------------
void UPLuftDruck()
{
 LuftDruck= bmp.readPressure();          // Liest den LuftDruck aus
 LuftDruck= (LuftDruck/100);             // Pascal in hPa => /100
}           
 
/// UP Luftdruck Seehöhe////////////////////////////////////////////////////////////
void UPLuftDruck0m()
{
 LuftDruck0m= (LuftDruck/0.967135);        // Umrechnung auf Seelevel von meinem Standort
}

///--- UP_Luftdruck Werte speichern und auswerte----------------------------------
// - Aufruf von Zeitschleife jede Stunde einmal
// -Lufdruckwert jede Stunde abspeichern
// -Nachsehen, ob Druck innerhalb der letzten Stunde gestiegen oder gefallen ist, Wert in LDruck1h speichern
// -Nachsehen, ob Druck innerhalb der letzten 2 h gestiegen oder gefallen ist, Wert in LDruck2h speichern
// -Nachsehen, ob Druck innerhalb der letzten 3 h gestiegen oder gefallen ist, Wert in LDruck3h speichern
//
void UPLuftDruckSpeicherUndVergleich()
{
 i=i+1;    // Laufvariable um die Werte der Reihe nach abzuspeichern
  if (i=1)
    {
      LDruck1h = LuftDruck0m;       // Druck vor 1h
      Serial.print("Druck1h=   ");
      Serial.print(LDruck1h);
      Serial.println();
      
      Serial.print("Differenz= ");
      Serial.print(DiffDruck1h);
      Serial.println();
     }
  if (i=2)
    {
      LDruck2h = LuftDruck0m;       // Druck vor 2h
      Serial.print("Druck2h=   ");
      Serial.print(LDruck2h);
      Serial.println();
      
      Serial.print("Differenz= ");
      Serial.print(DiffDruck2h);
      Serial.println();
    }
  if (i=3)
    {
      LDruck3h = LuftDruck0m;       // Druck vor 3h 
     
      Serial.print("Druck3h=   ");
      Serial.print(LDruck3h);
      Serial.println();
      
      Serial.print("Differenz= ");
      Serial.print(DiffDruck3h);
      Serial.println();
    }

  // 1h- Vergleich ob gestiegen oder gefallen
  // ----------------------------------------------
  // Diff pos und > 1.3hPa       => Starkwind 6-7Bft => Rote LED blinken
  // Diff pos und > 2-3hPa       => Sturm 8-9Bft     => Rote LED blinken
  // Diff pos und > 3.3hPa       => Orkan 10 und mehr Bft => Rote LED blinken
  
  // Diff neg und > -1 bis -2hPa => Starkwind 6-7Bft => Rote LED blinken
  // Diff neg und > -2hPa        => Sturm 8-12Bft    => Rote LED blinken
  
  // Bei starkem Druckabfall bei geringem Wind oder keinem 
  // => plötzlich starker Wind/Sturm ohne Vorwanung
  
  // Front mit Regen vor dem Wind => Wind nimmt zu
  // Front mit Wind vor dem Regen => Wind nimmt ab

 DiffDruck1h= (LuftDruck0m - LDruck1h);    // Differenz= akt. Luftdruck - LuftDruck vor 1h.
  if (DiffDruck1h > 1.3) 
   {
     Serial.print("Starkwind=");
     Serial.print(DiffDruck1h);
     Serial.println(" hPa");
   }
  if (DiffDruck1h > 2) 
   {
     Serial.print("Sturm=");
     Serial.print(DiffDruck1h);
     Serial.println(" hPa");
   }
 if (DiffDruck1h < -1.3)  
   {
     Serial.print("Starkwind");
     Serial.print(DiffDruck1h);
     Serial.println(" hPa");
   }
 if (DiffDruck1h < -2)  
   {
     Serial.print("Sturm");
     Serial.print(DiffDruck1h);
     Serial.println(" hPa");
   }
   
 // Damit Laufvariable Reset, damit alles von vorne beginnt
  if (i=3) i=0; 
}

/// UP Anzeige ------------------------------------------------------------
void UPAnzeige()
{
 #if 1
Serial.print("LuftDruck0m=");
     Serial.print(LuftDruck0m);
     Serial.println(" hPa");
 #endif
}

Hans01:
Auch, dass nach sagen wir mal 3h die Werte wieder neu angepasst werden und Hinten rausfallen, wie bei einem Schieberegister oder so und durch die neuen 1 Stunden / 2Stunden / 3 Stunden Werte überschrieben werden?

Das eine Variante eines FIFO Puffers oder Ringpuffers

Standard C++ Code (nicht Arduino):

class FIFO
{
public:
  static const int BUFFER_SIZE = 3;

  FIFO()
  {
     memset(buffer, 0, BUFFER_SIZE * sizeof(int));
     w = 0;
  }

  void write(int value)
  {
    buffer[w] = value;
    w = (w + 1) % BUFFER_SIZE;
  }

  int read(int index)
  {
    return buffer[index];
  }

private:
  int w;
  int buffer[BUFFER_SIZE];
};

void printBuffer(FIFO* buffer)
{
  for (int i = 0; i < buffer->BUFFER_SIZE; i++)
     cout << buffer->read(i) << endl;
  cout << "----" << endl;
}


int _tmain(int argc, _TCHAR* argv[])
{
  FIFO buffer;
  printBuffer(&buffer);

  buffer.write(10);
  printBuffer(&buffer);

  buffer.write(20);
  buffer.write(30);
  printBuffer(&buffer);

  buffer.write(40);
  printBuffer(&buffer);

  buffer.write(50);
  printBuffer(&buffer);

  getchar();
}

Durch die Modulo Division beim Inkrementieren des Schreib-Index wird dann wieder bei 0 angefangen und der erste Wert überschrieben

Naja, das hilft mir gar nicht, ich versteh nur Bahnhof. Danke!

Einfach ausgedrückt: Du nimmst ein Array und schreibst da die Werte rein. Der Trick mit Modulo sorgt dafür, dass der Array-Index sozusagen immer im Kreis läuft.

Wenn das auch nur Bahnhof ist dann schau Dir erst mal Arrays an und die Funktion Modulo.

Du kannst - wenn's einfach er für Dich ist - natürlich auch statt Array z.B. mit 3 Variablen arbeiten. Aber auch hier musst Du dann mitzählen und schnell feststellen, dass ein Array einfacher im Handling ist.

Mal den Code für den Arduino abgeändert. Die Arduino IDE hat natürlich wieder mal Scheiße mit den automatischen Funktions-Prototypen gemacht (weil die FIFO Klasse ein Parameter von printBuffer() ist). Also printBuffer() einfach in die Klasse packen.

class FIFO
{
public:
  static const int BUFFER_SIZE = 3;

  FIFO()
  {
    memset(buffer, 0, BUFFER_SIZE * sizeof(int));
    w = 0;
  }

  void write(int value)
  {
    buffer[w] = value;
    w = (w + 1) % BUFFER_SIZE;
  }

  int read(int index)
  {
    return buffer[index];
  }
  
  void printBuffer()
  {
    for (int i = 0; i < this->BUFFER_SIZE; i++)
      Serial.println(this->read(i));
    Serial.println(F("----"));
  }

private:
  int w;
  int buffer[BUFFER_SIZE];
};

void setup() 
{
  Serial.begin(9600);
  delay(1000);
  
  FIFO buffer;
  buffer.printBuffer();

  buffer.write(10);
  buffer.printBuffer();

  buffer.write(20);
  buffer.write(30);
  buffer.printBuffer();

  buffer.write(40);
  buffer.printBuffer();

  buffer.write(50);
  buffer.printBuffer();
}

void loop() 
{
}

Lass das mal laufen und spiele vielleicht mit den Werten die hinzugefügt werden. Dann merkst du schon ob das was für dich ist. Ergebnis:

0
0
0
----
10
0
0
----
10
20
30
----
40
20
30
----
40
50
30
----

Wenn 40 hinzugefügt wird 10 überschrieben. 50 überschreibt dann 20

Modulo ist einfach der Rest einer Division. 3 % 3 = 0. Wenn also der Array Index durch das + 1 auf 3 angewachsen ist, wird er wieder auf 0 zurück gesetzt

Danke! Ich muss es allerdings erst mal ausprobieren und kapieren.

Hans01: Laut einer Wetterseite kommt nämlich bei einer Luftdruckänderung von .. ... Eine Rote LED oder Summer soll dann angesteuert werden wenn Sturm kommt.

Aber so recht funktioniert das nicht. Wie könnte ich das machen?

Also wenn Du weniger Voodoo und mehr akkurate Informationen über drohende Wettergefahren haben möchtest, dann steckst Du ein Ethernet-Shield auf Deinen Arduino, schließt ein 16x2 LCD-Display an und saugst die aktuellen amtlichen Unwetterwarnungen für Deinen Landkreis oder Deine Stadt beim Deutschen Wetterdienst ab.

Wenn Du lieber bei Deinem Luftdruckänderungs-Voodoo bleiben möchtest, dann bekommst Du Deine Luftdruckänderungen über zwei Stunden mit einer viertelstündlichen Auflösung wie folgt:

Du legst Dir ein Array mit 4 Luftdruckwerten pro Stunde über den Zeitraum von sagen wir mal zwei Stunden an, dann hat das Array neun Luftdruckwerte:

  float pressureHistory[9];

Das wären die Werte:

  pressureHistory[0] ==> Luftdruck erste Stunde, Minute 0
  pressureHistory[1] ==> Luftdruck erste Stunde, Minute 15
  pressureHistory[2] ==> Luftdruck erste Stunde, Minute 30
  pressureHistory[3] ==> Luftdruck erste Stunde, Minute 45
  pressureHistory[4] ==> Luftdruck zweite Stunde, Minute 0
  pressureHistory[5] ==> Luftdruck zweite Stunde, Minute 15
  pressureHistory[6] ==> Luftdruck zweite Stunde, Minute 30
  pressureHistory[7] ==> Luftdruck zweite Stunde, Minute 45
  pressureHistory[8] ==> Luftdruck am Anfang der dritten Stunde, Minute 0

Sobald jetzt eine neue Minute 0, 15, 30 oder 45 anbricht, fällt der älteste Wert weg, die übrigen 8 Werte werden um einen Platz im Array umkopiert und der neueste Wert hintendrangehängt.

Die 2-Stunden-Luftdrucktendenz ergibt sich dann jeweils aus der Differenz

  float pressureDiff= pressureHistory[8]-pressureHistory[0];

Wenn der Controller nach einem Reset oder Power-On neu startet, wird in der setup-Funktion eine einzelne Messung gemacht und alle Werte im Array auf diesen ersten Startwert gesetzt.

Dass umkopieren in dem Fall eine gute Idee wäre, hatte auch schon daran gedacht. Da es hier die Reihenfolge erhalten werden sollte.

Da kann man aber auch die Klasse als Grundgerüst nehmen und muss nur die write() Methode anpassen. z.B.:

void write(int value)
{
  if (w == BUFFER_SIZE)
  {
     for (int i = 1; i < BUFFER_SIZE; i++)
       buffer[i - 1] = buffer[i];

      buffer[BUFFER_SIZE - 1] = value;
  }
  else
    buffer[w++] = value;
}

Dürfte in der Tat eher in die gewünschte Richtung gehen :slight_smile:

Hier ein kleines Beispielprogramm:

#define NUMPRESSUREVALUES 9
float pressureHistory[NUMPRESSUREVALUES];

void addNewPressure(float newValue)
{
  memmove(pressureHistory, &pressureHistory[1], sizeof(pressureHistory)-sizeof(float) );
  pressureHistory[NUMPRESSUREVALUES-1]=newValue;
}

void printValues(float* pressureHistory)
{
  for (int i=0;i<NUMPRESSUREVALUES;i++) Serial.println(pressureHistory[i]);
}

void setup() {
  Serial.begin(9600);
  float diff;
  // Hier normalerweise denselben Druckwert in das gesamte Array reinschieben:
  for (int i=0;i<NUMPRESSUREVALUES;i++) pressureHistory[i]=1015+i*0.25;
  // im Demoprogramm werden zu Demozwecken um jeweils 0.25 hPa steigende Werte geschrieben
  printValues(pressureHistory);
  diff=pressureHistory[NUMPRESSUREVALUES-1]-pressureHistory[0];
  Serial.print("Diff: ");Serial.println(diff);

  // Und ein neuer Wert wird danach dann normalerweise alle 15 Minuten in das Array geschoben
  Serial.println("Add new pressure value");
  addNewPressure(1022.1);
  printValues(pressureHistory);
  diff=pressureHistory[NUMPRESSUREVALUES-1]-pressureHistory[0];
  Serial.print("Diff: ");Serial.println(diff);
}

void loop() {
}

Die Funktion “addNewPressure(float newValue)” wird in der setup() Funktion 9x mit dem anfänglichen “ersten” Luftdruck aufgerufen, um das Array mit demselben Startwert zu initialisieren.

Danach muss die Funktion “addNewPressure(float newValue)” alle 15 Minuten einmal aufgerufen werden, um jeweils den neuesten Viertelstunden-Luftdruckwert in das Array reinzuschieben.

Die 2-Stunden Luftdrucktendenz kann zu jedem beliebigen Zeitpunkt kalkuliert werden mit:

  diff=pressureHistory[NUMPRESSUREVALUES-1]-pressureHistory[0];

Danke erst mal!! Ich bin bin noch am rumfummeln. Bascom-AVR war irgendwie einfacher zu verstehen als das C.

Nun gehts!

Das versteh ich wenigstens und erfüllt genau das was ich brauche. Alle 30 Minuten wird in den FIFO ein Barometerwert eingetragen und hinten wird der letzte vom Wert davor überschrieben und fällt raus.

Der code von @Jurs und @Serenifly ist zwar sehr viel eleganter und funktioniert auch, leider verstehe ich diese Art der höheren Programmierkunst noch nicht.

@Jurs, das mit dem Voodoo ist deshalb, weil man auf dem Segelboot leider nicht immer eine Internetanbindung hat.

Gruß

/// UNTERPRGRAMM FIFO wird von einer Zeitscheibe alle 30Min aufgerufen ///
void UPFifo(float LuftDruck0m)
{ 
  LDruckVor2h  = LDruckVor15h;   // Den Letzten 2h Wert überschreiben
  LDruckVor15h = LDruckVor1h;    // den davor
  LDruckVor1h  = LDruckVor05h;   // ... usw.
  LDruckVor05h = aktLDruck;      // ...
  aktLDruck    = LuftDruck0m;    // das ist der aktuelle Wert 
}

Ich würd das nicht so machen. Benutze ein Array nimm mehr Werte undarbeite für die FiFO mit dem index. Grüße Uwe

Wenn du es nicht verstehst, dann lass das mit der Klasse weg. Das braucht man nicht wirklich. Das war wohl etwas zu weit ausgeholt. Sorry.

Du kannst auch einfach ein Array als globale Variable nehmen und den Schreib-Zugriff in einer Funktion machen. Jurs had den Speicher einfach mit memmove() in einer Zeile verschoben. Aber man kann wie in #Reply 7 auch naiv Index für Index umkopieren. Das wird für dich einfacher zu verstehen sein.

Die Funktion die ich geschrieben habe fängt bei Index 1 und kopiert immer den aktuellen Index in den Index eins davor. Dabei wird automatisch Index 0 mit Index 1 überschrieben. Und der aktuelle Wert kommt nach dem Verschieben in den höchsten Index.

Wenn du wie jurs beschrieben hat das Array gleich in setup() n mal mit dem aktuellen Wert füllst, kannst du auch auf die Variable w verzichten:

const int BUFFER_SIZE = 4;
float buffer[BUFFER_SIZE];

void write(float value)
{
   for (int i = 1; i < BUFFER_SIZE; i++)
       buffer[i - 1] = buffer[i];

   buffer[BUFFER_SIZE - 1] = value;
}

Das ist alles :slight_smile:

Der Vorteil ist dass das beliebig mit der Array Größe skaliert.

Ihr habt Recht!!

Wenn ich eine SD-Card dranhängen und über einen längeren Zeitraum speichern will, muss ich es mit einem Array machen. Ich freue mich erst mal, dass das Barometer funktioniert. Optimieren werde ich, wenn alles fertig ist. Auf jeden Fall erst mal vielen DANK!