I'm trying to indicate whether the barometric pressure is rising or falling or steady. My coding experiance is between noob and average. I'm using a Pro mini and bmp180. I want to indicate whether the pressure is rinsing falling or steady any help would be most appreciated.
You need to take readings at regular intervals and store the last N in an array, calculating the linear regression
to estimate the slope.
To get started though, just read the pressure at regular intervals and compare the newly read one with the previous. If this one is more than some arbitrary amount larger than the last, pressure is rising. If this one is more than that chosen amount smaller than the last pressure is falling, otherwise it is steady.
Here's a link to the UK met office where they define time periods and differences used for this purpose: Marine forecasts glossary - Met Office
Thank you for your reply.This is what I was trying to implement. However the coding is what is driving me bonkers could you give me some basic examples. I know the code is sloppy but this is what I came up with . when the code runs Hg and hgPast are equal But as it loops hgPast turns and stays 0. Again sorry for sloppy code
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DS3232RTC.h>
#include <Adafruit_BMP085.h>
Adafruit_BMP085 bmp;
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address
float Hg = 0.00;
float F = 0.00;
float hgPast = 0.00;
float Pa = 0.00;
void setup()
{
Serial.begin(9600); // Used to type in characters
setSyncProvider(RTC.get);
if(timeStatus() != timeSet)
Serial.println("Unable to sync with the RTC");
else
Serial.println("RTC has set the system time");
lcd.begin(16,2);
bmp.begin();
Pa=bmp.readSealevelPressure();
const float hgPast=Pa/3386.39;
Serial.print("hgPast ");
Serial.print(hgPast);
Serial.println();
for(int i = 0; i< 3; i++)
{
lcd.backlight();
delay(250);
lcd.noBacklight();
delay(250);
}
lcd.backlight();
void loop()
{
lcd.clear();
digitalClockDisplay();
lcd.setCursor(2,1);
bmpTemp();
delay(3000);
lcd.clear();
lcd.setCursor(2,0);
bmpBar();
delay(3000);
}
void bmpTemp()
{
lcd.print("Temp ");
//Serial.print(bmp.readTemperature());
float C = bmp.readTemperature();
F = C * 9/5 + 32;
lcd.print(F);
lcd.print(" F");
}
void bmpBar()
{
Pa=bmp.readSealevelPressure();
Hg = Pa/3386.39;
lcd.print("Bar ");
lcd.print(Hg);
Serial.print("Current ");
Serial.println(Hg);
Serial.println();
Serial.print("Past ");
Serial.println(hgPast);
lcd.print(" Hg");
lcd.setCursor(3,1);
if(hgPast==Hg)
{
lcd.print("And Steady");
}
if (hgPast < Hg)
{
lcd.print("And Rising!");
}
if (hgPast > Hg)
{
lcd.print("And Falling");
}
}
void digitalClockDisplay()
{
lcd.setCursor(0,0);
lcd.print(" ");
lcd.print(hour());
printDigits(minute());
printDigits(second());
lcd.print(' ');
}
void printDigits(int digits)
{
// utility function for digital clock display: prints preceding colon and leading 0
lcd.print(':');
if(digits < 10)
lcd.print('0');
lcd.print(digits);
}
I should perhaps have mentioned that N=2 is permissable!
A good structure would be something like:
unsigned long last_time = 0L ; // timer variable
#DEFINE FIVE_MINUTES (5 * 60 * 1000L)
float old_reading_Pa ; // previous pressure sample
void setup()
{
.... // other init here
old_reading_Pa = bmp.readSealevelPressure(); // initialize variables.
last_time = millis() ;
}
void loop()
{
handle_pressure_readings() ;
.... // other tasks go here
}
void handle_pressure_readings ()
{
if (millis() - last_time >= FIVE_MINUTES) // see BlinkWithoutDelay example about this
{
last_time += FIVE_MINUTES ;
float new_reading_Pa = bmp.readSealevelPressure(); // get reading
report_changes (new_reading_Pa, old_reading_Pa) ; // interpret readings
old_reading_Pa = new_reading_P1 ; // update for next time
}
}
void report_changes (float new_Pa, float old_Pa)
{
.... data reporting goes here
}
Note the separation of handling the raw data from the interpretation/printing code
"separation of concerns" is the buzzphrase here. Also keep loop() as just a simple set of
tests or handler functions, again separating out the code in to logical places, rather than
stiring it all together in one big loop() function body...
And losing the delays means you can do other stuff easily, as nothing blocks.
Your immediate problem is that your global hgPast variable is never set to anything. Somewhere, it needs to take the value of Hg. Last thing in your bmpBar function would be a good time to do it.
Here is my code to gather the pressure over a time period:
#include <Adafruit_BMP280.h>
#include <SPI.h>
//
#define DEVICE_PIN 5
//#define BME_SCK 18
//#define BME_MISO 19
//#define BME_MOSI 23
Adafruit_BMP280 bme(DEVICE_PIN); // hardware SPI
// Adafruit_BMP280 bme(DEVICE_PIN, BME_MOSI, BME_MISO, BME_SCK);
float BMEpressure = 0.0;
float BMEtemperature = 0.0;
////////////////////////////////////////////////////////////////
int mmHg_Hourly[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
//
int iSecomds = 0;
int iMinutes = 0;
int iHours = 0;
void fDoPressureDataGather( void * parameter )
{
int iArrayCell = 0;
int iPast = -1;
for (;;)
{
xEventGroupWaitBits (eg, DoPressureDataGatherEvent, pdTRUE, pdTRUE, portMAX_DELAY) ;
if ( GPS.fix )
{
//seed initial value and hour cell
if ( iPast == -1 )
{
iPast = GPS.minute; // store mmHg data
mmHg_Hourly[iArrayCell] = int(BMEpressure);
iArrayCell++;
}
else
{
if ( iPast != GPS.minute )
{
if ( ((GPS.minute % 6) == 0) )
{
iPast = GPS.minute; // keep current reading
mmHg_Hourly[iArrayCell] = int(BMEpressure); //add new reading to array
iArrayCell++; // go to the next cell
}
}
}
if ( iArrayCell >= PressureDataArrayCount )
{
iArrayCell = 0; // start array count over
}
}
}
vTaskDelete( NULL );
} // void fDoPressureDataGather
Here is my code, snippet, to display the pressure changes in a line graph on a OLED:
if ( (iCount >= 20) && (iCount <= 30) )
{
int x = 10; // create and display mmHg graph
int yBase = 38; // line number for the 0 line
int y1 = yBase;
int y2 = 0;
int pressureBase = mmHg_Hourly[0];
if ( pressureBase != 0 )
{
for (int i = 0; i <= PressureDataArrayCount; i++)
{
if ( mmHg_Hourly[i] != 0 )
{
y2 = yBase + (pressureBase - mmHg_Hourly[i]);
u8g2.drawLine(x, y1, x + 1, y2); // draw line between previous reading and current
y1 = y2; // Make current reading previous
x += 2;
}
}
}
}
// code to check / get pressure
void fCheck_Pressure( void * parameter )
{
while (1)
{
xEventGroupWaitBits (eg, PressureEvent, pdTRUE, pdTRUE, portMAX_DELAY) ;
BMEtemperature = bme.readTemperature();
// BMEpressure = bme.readPressure() * 0.0002952998751 ; // inHg
BMEpressure = bme.readPressure() / 133.3223684; // mmHg
xEventGroupSetBits( eg, DoPressureDataGatherEvent ); // trigger fDoPressureDataGather
}
vTaskDelete( NULL );
}
Looking over the code you should be able to deduce the globals and locals.
I originally coded for a update once per hour but that took way to long to get a history.
You have to take a number of readings, take the average, and see if that changes by more than a certain amount per time. Or indeed take a linear regression value.
Just checking whether a value is greater than or less than a previous value will give lots of issues, as no two readings are equal due to measurement errors and noise (electrical, random air movements and pressure changes, etc).
Even with the regression or averaging formulas you will never see it to be exactly equal, so a "steady" air pressure just means it's changing less than a certain rate.
You probably need to use values over the last 10 minutes or even a longer interval to determine rising/falling air pressure.
Thanks to all that replied. After spending the night with this I only ended up more confused than ever.
MarkT- I have been trying to follow your example. I'm confused about this:
void report_changes (float new_Pa, float old_Pa)
{
.... data reporting goes here
}
also I kept getting an error here
void handle_pressure_readings ()
{
if (millis() - last_time >= FIVE_MINUTES) // see BlinkWithoutDelay example about this
{
last_time += FIVE_MINUTES ;
float new_reading_Pa = bmp.readSealevelPressure(); // get reading
report_changes (new_reading_Pa, old_reading_Pa) ; // interpret readings
old_reading_Pa = new_reading_P1 ; // update for next time
}
}
Where new_reading_P1 was not declared in this scope so I declared it in the beginning under
float old_reading_Pa ; // previous pressure sample.
For a test I did this:
void report_changes (float new_Pa, float old_Pa)
{
.... data reporting goes here
Serial.println(new_Pa);
Serial.println(old_Pa);
}
the first reading seemed to be correct but all proceeding 5 minute interval produced 0.00 for old_Pa
I did learn one VERY important thing: I'm 57 and have sooo much to learn
It's a typo. This:
report_changes (new_reading_Pa, old_reading_Pa) ; // interpret readings
old_reading_Pa = new_reading_P1 ; // update for next time
was intended to be:
report_changes (new_reading_Pa, old_reading_Pa) ; // interpret readings
old_reading_Pa = new_reading_Pa ; // update for next time
wildbill: Darn should have seen that thank you. I guess I need to learn to walk away once in a while to let my eyes refocus
mrmom96:
Thanks to all that replied. After spending the night with this I only ended up more confused than ever.MarkT- I have been trying to follow your example. I'm confused about this:
void report_changes (float new_Pa, float old_Pa)
{
.... data reporting goes here
}
Why are you confused - you've got to write this function, and you did!
also I kept getting an error here
void handle_pressure_readings ()
{
if (millis() - last_time >= FIVE_MINUTES) // see BlinkWithoutDelay example about this
{
last_time += FIVE_MINUTES ;
float new_reading_Pa = bmp.readSealevelPressure(); // get reading
report_changes (new_reading_Pa, old_reading_Pa) ; // interpret readings
old_reading_Pa = new_reading_P1 ; // update for next time
}
}Where new_reading_P1 was not declared in this scope so I declared it in the beginning under
float old_reading_Pa ; // previous pressure sample.
wrong, its a typo, change it to new_reading_Pa and understand why
For a test I did this:
void report_changes (float new_Pa, float old_Pa)
{
.... data reporting goes here
Serial.println(new_Pa);
Serial.println(old_Pa);
}
the first reading seemed to be correct but all proceeding 5 minute interval produced 0.00 for old_Pa
might be since you duplicated the variable instead of fixing the typo.
I just sketched out the outline, so you can digest how to do this sort of stuff readably/neatly, but make no promises its
correct as its incomplete and I don't have the sensor anyway..
I did learn one VERY important thing: I'm 57 and have sooo much to learn
MarkT wildbill pointed out the typo yesterday don't know how I missed it other than spending to many hours with this project and not enough breaks. After correcting the typo it worked flawlessly. thanks so much for you help. and a thank you to everyone else for there assistance. I don't really post much because I try to do every thing I can to figure things out and a lot of times I do. Plus I find it easier to retain what I learn when I work it out rather than just copy paste some code. This one just really had me twisted. again thank you.