Calculating corrected Altitude from Pressure & Temperature using Teensy 3.2, BME280, and library from farmerkeith

Hi again, I'm sure this is a really trivial programming question, but I can't figure out what I'm doing wrong:

Farmerkeith provides functions to calculate the altitude. But when I try to actually use those functions to get the altitude, the compile fails. I was careful to use float for bmeAltitude and the seaLevelhPa varible:

double temperature, pressure, humidity;
float bmeAltitude;
const float seaLevelhPa 1013.15; //in hPa. The standard sea level pressure is 1013.15 hPa.

And then I try using the function in a function here:

void readBME() {
  humidity = bme0.readHumidity (temperature, pressure); // measure temperature and pressure
 // bmeAltitude = calcAltitude (pressure, seaLevelhPa);
 bmeAltitude = bme0.calcAltitude (pressure);
 // calcAltitude(pressure, seaLevelhPa);
  writeBME();
}

void writeBME() {
  Serial.println();
  Serial.print("*** ");
  // Serial.print("Humidity = ");
  Serial.print(humidity, 4); // print with 4 decimal places
  Serial.print("%RH\t");
  // Serial.print("Pressure = ");
  Serial.print(pressure, 4); // print with 4 decimal places
  Serial.print(" hPa\t");
  // Serial.print("Temperature = ");
  Serial.print(temperature, 2); // print with 2 decimal places
  Serial.print( " C ***");
  Serial.print(bmeAltitude);
  Serial.println(" m");
  flagPrintBME = false;
}

I'm just not sure how to use this function. His code examples don't show altitude calculations. Can anyone show me?

The library for the BME280 (similar to BMP280, and BMP180) is described here:

farmerkeith's actual library is here:

He describes how to use his altitude functions here (iI'm trying to use block quotes but it isn't working -- sorry):


Altitude and Sea Level pressure

There is a known relationship between atmospheric pressure and altitude. The weather also influences pressure. When the weather organisations publish atmospheric pressure information, they usually adjust it for altitude and so the "synoptic chart" shows isobars (lines of constant pressure) standardised to mean sea level. So really there are 3 values in this relationship, and knowing two of them enables derivation of the third one. The 3 values are:

  • altitude above sea level
  • actual air pressure at that altitude
  • equivalent air pressure at sea level (more strictly, mean sea level, because instantaneous sea level constantly changes)

This library provides two functions for this relationship, as follows:

calcAltitude (pressure, seaLevelhPa); calcNormalisedPressure (pressure, altitude);

There is also a simpllified version, which assumes the standard sea level pressure of 1013.15 hPa.

calcAltitude (pressure); // standard seaLevelPressure assumed

My code is below:

// Purpose: test all sensors with 3 ultrasounds on breadboard, for RC rover.
// Based on Teensy 3.2
// Sensors: GPS, 3 ultrasounds (HC-SR04), BME280, BNO085
// Outputs to Serial (if connected) and to OLED display (126x64 SSD1306)
//
// I2C addresses for breadboard:
//    0x3C - OLED Display
//    0x76 - BME-280
//    0x70 and 0x76 ??? - servo board -- collision with BME???
//    ?    - BNO085
//
//
// Improvements needed: 
// -- replace timing code for ultrasonics with below so doesn't fail after timer rollover
//    if ( millis() - lastPingTime[i] >= PING_INTERVAL ) {....}
//
// --  Need to address rollover in timers for BME and ultrasound readings
// 
// -- Need to get average readings from BME for better stability
// -- Put BME to sleep when not reading to save power
// 
// ---------------------------------------------------------------------------


#include <NewPing.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <farmerkeith_BMP280.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define SONAR_NUM     3 // Number of sensors.
#define MAX_DISTANCE 200 // Maximum distance (in cm) to ping.
#define PING_INTERVAL 33 // Milliseconds between sensor pings (29ms is about the min to avoid cross-sensor echo).

#define BME_INTERVAL 5000 // Milliseconds between reading BME280 sensor
bme280 bme0 ; // creates object bme0 of type bme280, base address
double temperature, pressure, humidity;
float bmeAltitude;
const float seaLevelhPa 1013.15; //in hPa. The standard sea level pressure is 1013.15 hPa.
unsigned long lastBMEReadTime = 0;      // Holds the time for when the BME280 was last read
bool flagPrintBME = true;

int loopcount = 0;
unsigned long pingTimer[SONAR_NUM]; // Holds the times when the next ping should happen for each sensor.
unsigned int cm[SONAR_NUM];         // Where the ping distances are stored.
uint8_t currentSensor = 0;          // Keeps track of which sensor is active.

char *sonarLabel[] = {"Left", "Right", "Rear"};

NewPing sonar[SONAR_NUM] = {     // Sensor object array.
  NewPing(10, 9, MAX_DISTANCE),   // Front left. Each sensor's trigger pin, echo pin, and max distance to ping.
  NewPing(12, 11, MAX_DISTANCE), // Front right
  NewPing(15, 16, MAX_DISTANCE)  // Back
};


void setup() {
  Serial.begin(115200);
  Wire.begin(); // initialize I2C protocol
  bme0.begin(); // initialize BME280 for continuous measurements
  // Delay to wait for the serial connection to be established,
  // without requiring a serial connection for the program to run
  delay(1000);

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("OLED Display SSD1306: allocation failed"));
    for (;;); // Don't proceed, loop forever
  }

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(22, 0);
  display.print("Rover v0.1");
  display.display();

  pingTimer[0] = millis() + 75;           // First ping starts at 75ms, gives time for the Arduino to chill before starting.
  for (uint8_t i = 1; i < SONAR_NUM; i++) // Set the starting time for each sensor.
    pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;
}

void loop() {

  for (uint8_t i = 0; i < SONAR_NUM; i++) { // Loop through all the sensors.
    if (millis() >= pingTimer[i]) {         // Is it this sensor's time to ping?
      pingTimer[i] += PING_INTERVAL * SONAR_NUM;  // Set next time this sensor will be pinged.
      if (i == 0 && currentSensor == SONAR_NUM - 1) oneSensorCycle(); // Sensor ping cycle complete, do something with the results.
      sonar[currentSensor].timer_stop();          // Make sure previous timer is canceled before starting a new ping (insurance).
      currentSensor = i;                          // Sensor being accessed.
      cm[currentSensor] = 999;                      // Make distance 999 in case there's no ping echo for this sensor.
      sonar[currentSensor].ping_timer(echoCheck); // Do the ping (processing continues, interrupt will call echoCheck to look for echo).
    }
  }

  // Other code that *DOESN'T* analyze ping results can go here.

  // *** Need to address rollover in timer ***
  if ( millis() - lastBMEReadTime >= BME_INTERVAL )
  {
    readBME();
    flagPrintBME = true;
    lastBMEReadTime = millis();
  }



}

void readBME() {
  humidity = bme0.readHumidity (temperature, pressure); // measure temperature and pressure
 // bmeAltitude = calcAltitude (pressure, seaLevelhPa);
 bmeAltitude = bme0.calcAltitude (pressure);
 // calcAltitude(pressure, seaLevelhPa);
  writeBME();
}

void writeBME() {
  Serial.println();
  Serial.print("*** ");
  // Serial.print("Humidity = ");
  Serial.print(humidity, 4); // print with 4 decimal places
  Serial.print("%RH\t");
  // Serial.print("Pressure = ");
  Serial.print(pressure, 4); // print with 4 decimal places
  Serial.print(" hPa\t");
  // Serial.print("Temperature = ");
  Serial.print(temperature, 2); // print with 2 decimal places
  Serial.print( " C ***");
  Serial.print(bmeAltitude);
  Serial.println(" m");
  flagPrintBME = false;
}


void echoCheck() { // If ping received, set the sensor distance to array.
  if (sonar[currentSensor].check_timer())
    cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM;

  //display.display();
}


void oneSensorCycle() { // Sensor ping cycle complete, do something with the results.


  // The following code would be replaced with your code that does something with the ping results.
  for (uint8_t i = 0; i < SONAR_NUM; i++) {
    // Serial.print(i);
    // Serial.print(" ");


    Serial.print(sonarLabel[i]);
    Serial.print(" = ");
    Serial.print(cm[i]);
    Serial.print("cm \t");
  }
  Serial.println();
  
  writeDisplay();
}

void writeDisplay() {
  display.clearDisplay();

//  display.setCursor(25, 0);
//  display.print("Rover v0.2");

  display.setCursor(0, 0);
  display.print("L:");
  display.print(cm[0]);

  display.setCursor(49, 0);
  display.print("R:");
  display.print(cm[1]);

  display.setCursor(98, 0);
  display.print("B:");
  display.print(cm[2]);

  display.setCursor(0, 15);
  display.print(temperature, 2); // print with 2 decimal places
  display.print(" C");

  display.setCursor(60, 15);
  display.print(pressure, 2); // print with 4 decimal places
  display.print(" hPa");
  
  display.setCursor(0, 25);
  display.print(humidity, 2); // print with 4 decimal places
  display.print(" %RH");


  

  

  display.display();
}

void oledUltrasonics() { // write ultrasound data to OLED screen
  display.clearDisplay();

  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(0, 0);            // Start at top-left corner

  display.print(cm[0]);
  display.print("    ");
  display.print(cm[1]);
  display.print("     ");
  display.println(cm[2]);


  display.display();
}

So the problem is fixed when I change "const float seaLevelhPa 1013.15;" to "#define seaLevelhPa 1013.15".

Can anyone explain why?

Farmerkeith recommended using const declarations, not defines. ..

const float seaLevelhPa 1013.15;

Needs an = ‘equal sign’ to assign the value to seaLevelhPa

The #define simply performs text replacement at compile time… which works in this case.

1 Like

Can you still help me to understand why the program does NOT compile with this function call:

bmeAltitude = bme0.calcAltitude(pressure, seaLevelhPa);

but it compiles fine with this:

bmeAltitude = bme0.calcAltitude (pressure);

as described here...