Barometric Presure sensor BMP180

I'm Using the BMP180 sensor

The ting is that I plugged it into an arduino leonardo using 5 v, then reading the datasheet I realized that it has to be 3.3v so I change it, fortunately the sketch wasn't loaded and the arduino totally ignore the sensor so it will not work any way because the arduino did not start it.

then I load the example of the sparkfun library of the BMP180 sensor and the serial give me data:
So it is working normally

provided altitude: 1655 meters, 5430 feet
temperature: 36.95 deg C, 98.51 deg F
absolute pressure: 1007.49 mb, 29.75 inHg
relative (sea-level) pressure: 1230.48 mb, 36.34 inHg
computed altitude: 1655 meters, 5430 feet

provided altitude: 1655 meters, 5430 feet
temperature: 36.96 deg C, 98.52 deg F
absolute pressure: 1007.47 mb, 29.75 inHg
relative (sea-level) pressure: 1230.45 mb, 36.34 inHg
computed altitude: 1655 meters, 5430 feet

provided altitude: 1655 meters, 5430 feet
temperature: 36.96 deg C, 98.52 deg F
absolute pressure: 1007.46 mb, 29.75 inHg
relative (sea-level) pressure: 1230.45 mb, 36.34 inHg
computed altitude: 1655 meters, 5430 feet

provided altitude: 1655 meters, 5430 feet
temperature: 36.92 deg C, 98.46 deg F
absolute pressure: 1007.42 mb, 29.75 inHg
relative (sea-level) pressure: 1230.40 mb, 36.34 inHg
computed altitude: 1655 meters, 5430 feet

The temperature was ok hire is hoot right now. but the elevation of my city is 10 - 30 meters over sea level.
I don't know if I'm misunderstanding the provided altitude (1655 m) or if the sensor was damaged by the 5v in "Standby mode" or is because of the 5 v of the arduino IIC pins.

Can help me to understand what is going on?

There is always a sketch loaded (maybe except for the very first time). So your sensor could be damaged.

You could write a bare bones sketch that reads the raw values from the sensor.
And see if it reacts on on pressure changes.

If it always gives same value the sensor is broken.

If it is not broken, the formulas used might be incorrect. But that is hard to see without code.

what is the code of your sketch ?

"provided altitude" is something that your code has in it, it is not coming from the device.

This is other tread where I ask for advice since I got the same problem using a code posted by @Leo hire: bmp180 library - #11 by _Leo - Sensors - Arduino Forum

the @sparkfun code and the one posted by @Leo gave me different data as you can see if you check my first post in each treat, I post the corresponding results of different codes in each treat, well... I din't notice that the inHg was really different for each code results, just notice that the data was to much to be true acording to the location data that i get from different media. except for the temperature that was ok for me.

some of you tell me that the sensor may be broken beacuse the reading is around 1500 hPa, but the pressure value varies if I put it on an improvised vacuum pump.

I was tinking about the fact that I'm using an arduino Leonardo wich has 5v logic level.
I'm using that cheap sensor form ebay by the way

The absolute pressure reading seems OK to me (if this is actually the sensor pressure reading), normal atmospheric pressure at sea level is 1013.25 millibar or about 29.9 inch Hg. The sea-level pressure seems high, which could explain the wrong calculated elevation.

I'm in near the sea, my city is just above the sea level that is way i think it is quite wrong

If you want help, post the exact code that you are using.

originaly posted by Leo
http://forum.arduino.cc/index.php?topic=202816.msg1621373#msg1621373
the code that i'm using

/**********************************************************
  Bosch Pressure Sensor BMP085 / BMP180 readout routine
  for the Arduino platform.
   
  Compiled by Leo Nutz
  www.ALTDuino.de              
 **********************************************************/

#include <Wire.h>

#define ADDRESS_SENSOR 0x77                 // Sensor address

int16_t  ac1, ac2, ac3, b1, b2, mb, mc, md; // Store sensor PROM values from BMP180
uint16_t ac4, ac5, ac6;                     // Store sensor PROM values from BMP180
// Ultra Low Power       OSS = 0, OSD =  5ms
// Standard              OSS = 1, OSD =  8ms
// High                  OSS = 2, OSD = 14ms
// Ultra High Resolution OSS = 3, OSD = 26ms
const uint8_t oss = 3;                      // Set oversampling setting
const uint8_t osd = 26;                     // with corresponding oversampling delay 

float T, P;                                 // Set global variables for temperature and pressure 

void setup()
{
  Serial.begin(9600);                       // Set up serial port
  while(!Serial){;}                         // waith until leonardo serial port ready
  delay(5000);
  Wire.begin();                             // Activate I2C
  
    init_SENSOR();                            // Initialize baro sensor variables
  delay(100);
}

void loop()
{
  int32_t b5;
 
  b5 = temperature();                       // Read and calculate temperature (T) 

  Serial.print("Temperature: ");
  Serial.print(T, 2);
  Serial.print(" C, ");
  Serial.print(1.8 * T + 32.0, 2);
  Serial.println(" F");

  P = pressure(b5);                         // Read and calculate pressure (P) 

  Serial.print("Pressure: ");
  Serial.print(P, 2);
  Serial.print(" mbar, ");
  Serial.print(P * 0.0295299830714, 2);
  Serial.println(" inHg");
  Serial.println("");

  delay(500);                               // Delay between each readout
  
}

/**********************************************
  Initialize sensor variables
 **********************************************/
void init_SENSOR()
{
  ac1 = read_2_bytes(0xAA);
  ac2 = read_2_bytes(0xAC);
  ac3 = read_2_bytes(0xAE);
  ac4 = read_2_bytes(0xB0);
  ac5 = read_2_bytes(0xB2);
  ac6 = read_2_bytes(0xB4);
  b1  = read_2_bytes(0xB6);
  b2  = read_2_bytes(0xB8);
  mb  = read_2_bytes(0xBA);
  mc  = read_2_bytes(0xBC);
  md  = read_2_bytes(0xBE);

  Serial.println("");
  Serial.println("Sensor calibration data:");
  Serial.print(F("AC1 = ")); Serial.println(ac1);
  Serial.print(F("AC2 = ")); Serial.println(ac2);
  Serial.print(F("AC3 = ")); Serial.println(ac3);
  Serial.print(F("AC4 = ")); Serial.println(ac4);
  Serial.print(F("AC5 = ")); Serial.println(ac5);
  Serial.print(F("AC6 = ")); Serial.println(ac6);
  Serial.print(F("B1 = "));  Serial.println(b1);
  Serial.print(F("B2 = "));  Serial.println(b2);
  Serial.print(F("MB = "));  Serial.println(mb);
  Serial.print(F("MC = "));  Serial.println(mc);
  Serial.print(F("MD = "));  Serial.println(md);
  Serial.println("");
}

/**********************************************
  Calcualte pressure readings
 **********************************************/
float pressure(int32_t b5)
{
  int32_t x1, x2, x3, b3, b6, p, UP;
  uint32_t b4, b7; 

  UP = read_pressure();                         // Read raw pressure

  b6 = b5 - 4000;
  x1 = (b2 * (b6 * b6 >> 12)) >> 11; 
  x2 = ac2 * b6 >> 11;
  x3 = x1 + x2;
  b3 = (((ac1 * 4 + x3) << oss) + 2) >> 2;
  x1 = ac3 * b6 >> 13;
  x2 = (b1 * (b6 * b6 >> 12)) >> 16;
  x3 = ((x1 + x2) + 2) >> 2;
  b4 = (ac4 * (uint32_t)(x3 + 32768)) >> 15;
  b7 = ((uint32_t)UP - b3) * (50000 >> oss);
  if(b7 < 0x80000000) { p = (b7 << 1) / b4; } else { p = (b7 / b4) << 1; } // or p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;
  x1 = (p >> 8) * (p >> 8);
  x1 = (x1 * 3038) >> 16;
  x2 = (-7357 * p) >> 16;
  return (p + ((x1 + x2 + 3791) >> 4)) / 100.0f; // Return pressure in mbar
}

/**********************************************
  Read uncompensated temperature
 **********************************************/
int32_t temperature()
{
  int32_t x1, x2, b5, UT;

  Wire.beginTransmission(ADDRESS_SENSOR); // Start transmission to device 
  Wire.write(0xf4);                       // Sends register address
  Wire.write(0x2e);                       // Write data
  Wire.endTransmission();                 // End transmission
  delay(5);                               // Datasheet suggests 4.5 ms
  
  UT = read_2_bytes(0xf6);                // Read uncompensated TEMPERATURE value

  // Calculate true temperature
  x1 = (UT - (int32_t)ac6) * (int32_t)ac5 >> 15;
  x2 = ((int32_t)mc << 11) / (x1 + (int32_t)md);
  b5 = x1 + x2;
  T  = (b5 + 8) >> 4;
  T = T / 10.0;                           // Temperature in celsius 
  return b5;  
}

/**********************************************
  Read uncompensated pressure value
 **********************************************/
int32_t read_pressure()
{
  int32_t value; 
  Wire.beginTransmission(ADDRESS_SENSOR);   // Start transmission to device 
  Wire.write(0xf4);                         // Sends register address to read from
  Wire.write(0x34 + (oss << 6));            // Write data
  Wire.endTransmission();                   // SEd transmission
  delay(osd);                               // Oversampling setting delay
  Wire.beginTransmission(ADDRESS_SENSOR);
  Wire.write(0xf6);                         // Register to read
  Wire.endTransmission();
  Wire.requestFrom(ADDRESS_SENSOR, 3);      // Request three bytes
  if(Wire.available() >= 3)
  {
    value = (((int32_t)Wire.read() << 16) | ((int32_t)Wire.read() << 8) | ((int32_t)Wire.read())) >> (8 - oss);
  }
  return value;                             // Return value
}

/**********************************************
  Read 1 byte from the BMP sensor
 **********************************************/
uint8_t read_1_byte(uint8_t code)
{
  uint8_t value;
  Wire.beginTransmission(ADDRESS_SENSOR);         // Start transmission to device 
  Wire.write(code);                               // Sends register address to read from
  Wire.endTransmission();                         // End transmission
  Wire.requestFrom(ADDRESS_SENSOR, 1);            // Request data for 1 byte to be read
  if(Wire.available() >= 1)
  {
    value = Wire.read();                          // Get 1 byte of data
  }
  return value;                                   // Return value
}

/**********************************************
  Read 2 bytes from the BMP sensor
 **********************************************/
uint16_t read_2_bytes(uint8_t code)
{
  uint16_t value;
  Wire.beginTransmission(ADDRESS_SENSOR);         // Start transmission to device 
  Wire.write(code);                               // Sends register address to read from
  Wire.endTransmission();                         // End transmission
  Wire.requestFrom(ADDRESS_SENSOR, 2);            // Request 2 bytes from device
  if(Wire.available() >= 2)
  {
    value = (Wire.read() << 8) | Wire.read();     // Get 2 bytes of data
  }
  return value;                                   // Return value
}

If that is the code you are using, then what it all the stuff about the "provided" pressure and altitude, you had earlier ?

If you took any altitude-sensing device to Denver or Johannesburg, and misled it into believing that it was at sealevel, then when you actually went to somewhere at sealevel, you would get a bogus answer.

The device is going to measure the actual pressure that it detects, which is converts to an altitude using a "standard" formula for the relationship between pressure and altitude.

The problem is, the atmospheric pressure varies because of the weather and other things, and there are various ways to "adjust" for this. Sometimes the adjustment scheme is more confusing than it really needs to be.

No fear, I was stuck with it too. It is not any issue you were worried about. It was a type casting problem.

Here in the example code, this was the issue:

ORIGINAL FUNCTION (replace this one)

/**********************************************
  Calcualte pressure readings
 **********************************************/
float pressure(int32_t b5)
{
  int32_t x1, x2, x3, b3, b6, p, UP;
  uint32_t b4, b7; 

  UP = read_pressure();                         // Read raw pressure

  b6 = b5 - 4000;
  x1 = (b2 * (b6 * b6 >> 12)) >> 11; 
  x2 = ac2 * b6 >> 11;
  x3 = x1 + x2;
  b3 = (((ac1 * 4 + x3) << oss) + 2) >> 2;
  x1 = ac3 * b6 >> 13;
  x2 = (b1 * (b6 * b6 >> 12)) >> 16;
  x3 = ((x1 + x2) + 2) >> 2;
  b4 = (ac4 * (uint32_t)(x3 + 32768)) >> 15;
  b7 = ((uint32_t)UP - b3) * (50000 >> oss);
  if(b7 < 0x80000000) { p = (b7 << 1) / b4; } else { p = (b7 / b4) << 1; } // or p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;
  x1 = (p >> 8) * (p >> 8);
  x1 = (x1 * 3038) >> 16;
  x2 = (-7357 * p) >> 16;
  return (p + ((x1 + x2 + 3791) >> 4)) / 100.0f; // Return pressure in mbar
}

FIXED FUNCTION

/**********************************************
  Calcualte pressure readings
 **********************************************/
float pressure(int32_t b5)
{
  int32_t x1, x2, x3, b3, b6, p, UP;
  uint32_t b4, b7; 

  UP = read_pressure();                         // Read raw pressure

  b6 = b5 - 4000;
  x1 = (b2 * (b6 * b6 >> 12)) >> 11; 
  x2 = ac2 * b6 >> 11;
  x3 = x1 + x2;
  b3 = (((uint32_t)(ac1 * 4 + x3) << oss) + 2) >> 2;
  x1 = ac3 * b6 >> 13;
  x2 = (b1 * (b6 * b6 >> 12)) >> 16;
  x3 = ((x1 + x2) + 2) >> 2;
  b4 = (ac4 * (uint32_t)(x3 + 32768)) >> 15;
  b7 = ((uint32_t)UP - b3) * (50000 >> oss);
  if(b7 < 0x80000000) { p = (b7 << 1) / b4; } else { p = (b7 / b4) << 1; } // or p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;
  x1 = (p >> 8) * (p >> 8);
  x1 = (x1 * 3038) >> 16;
  x2 = (-7357 * p) >> 16;
  return (p + ((x1 + x2 + 3791) >> 4)) / 100.0f; // Return pressure in mbar
}

See the difference?

b3 = (((uint32_t)(ac1 * 4 + x3) << oss) + 2) >> 2;

The rest of the code was fine, leave it alone for now!

That fixed it. A lot of head scratching for me as maths is not my forte and this stuff is pretty convoluted.

I hope this sorts it out for you.

My only guess as to why it may work for some people is that for some versions of arduino casting was handled differently.

Cheers
Jacob

Jacob,

thanks for that. It is a surprise to me that it would be the source of the problem for some!

I don't know how many different Arduino compiler versions I've run the code on. And from the hardware side UNO's and Pro minis.... The results always corresponded with the data sheet.

Would this have to do with the Leonardo? What is your setup?

It also shows me from now on to tell people with such or similar problems to use the data sheet variables to confirm the calculations.

thanks askjacob and Leo
Well I also had wrong readings with the sparkfun library, but now I'm trying the adafruit library and it seems to work ok:

Temperature = 35.60 *C
Pressure = 101231 Pa
Altitude = 8.00 meters
Pressure at sealevel (calculated) = 101232 Pa
Real altitude = 22.55 meters

I'll try to make changes to the code posted by Leo and also try it on Leonardo and a nano v3.0 and post the results.

Hi Leo,

I wanted to use your code rather than the Adafruit library for 2 reasons really:

1: I have very little codespace left
2: Just "throwing another library at a problem" leaves little to learning

And did I get some learning done last night :slight_smile:

Considering C and all it's variants are new to me (why did my university insist on Pascal?) - at least the strong background on type casting helped :slight_smile: - I have been working hard on both the hardware and software aspects on my current project - hence using the arduino platform to speed things up rather than my usual route of rolling my own. Makes it easier knowing it is less likely to be a hardware issue...

Anyway, back on topic, the environment I have in place is:

Arduino Pro Mini 5v 16MHz 328 (Maybe the 328 is key here? Unsure why it would be a major difference other than ram space although I find more and more quirks with the arduino compiler as I go...)
Bosch BMP180 sensor on breakout with 3v3 supply (ebay special)
Various other i2c devices not currently in use in test code (now in use in full code, and happily co-existing), other than the oLED used as the debug display (rather than serial terminal)

I was getting 1480 - 1508 mbar readings (was actually 1008 compared to my weather station) until I fixed the casting. Once casting fixed - bingo - spot on.

By the way - I popped over to your website to see if there was any updated code, and instead was enthalled by the rocketry and altimeter stuff - amazing stuff :slight_smile:

Cheers from Aus,
Jacob

I have the same sensor and i used a bi-directional logic level converter for it to work. Also, the code i tested it with had altitude input, for a more exact pressure output.
I think you used same code when you got those high readings. Now I don't know if you can use it on 5 v logic level and get valid readings..

The code you tested it with would be the Adafruit Unified library. Dig inside the codebase, and you will find the exact same compenstation logic - taken from the same datasheet sample.

Once you dig in there - Adafruit also cast everything correctly, INCLUDING this example.

As mentioned, the issue appears to be how the compiler/environment handles default casting, if you leave it to the compiler to handle it (bad) you will get an unpredictable result based on how the author of your environment feels on the day. Isn't it better to strictly cast it anyway (good) to ensure you get it in the format you desire regardless? There is no overhead, and at best someone reading your code will also understand what is going on.

I should have mentioned all my i2c is at 3v3, although it is often mentioned that the BMP180 technically 5v tolerant on SDA and SCL - although the datasheet never points it out as the I2C specs are external to the device itself and another kettle of fish - it is about an ability to "drive" a voltage above a threshold cleanly without reflection/ringing (hence the termination resistors) and starts to enter the realm of throw stuff at it and see black magic once lines get long and more devices get added :slight_smile:

Can we please STOP trying to tell me what it isn't in this case? it is not hardware or voltage. I am not a newbie to electronics or to code, just to the arduino environment (and c - c++) - which I am hopping into just because of the flood of cheap dev boards from china...Cheaper than I can get bare ATMegas for these days... I am happy to be wrong, but not happy to have the conversation derailed.

Regards
Jacob

Also, the code i tested it with had altitude input, for a more exact pressure output.

This statement makes no sense. This device measures pressure.

Knowing any other outside information ( other than the temperature, which it measures itself ), cannot make the pressure output "more exact".

Outside information can be used to make the altitude calculation "more exact".

I think I had that sort of problem with the casting as well. Not sure now, it was a couple of years ago. It took a while to get it to work, I went through all those shift manipulations looking very closely at the bosch description. It appears that some of the library code that people published for this device, they never even tried running it.

I also recall seeing somewhere, an alternative processing scheme that someone devised, which used float instead of int ( or maybe the other way around ), to get an output with less bit errors in it. It looked very interesting but I did not implement it.

The Adafruit library allows you to put in a base altitude for more accurate altitude above sea level readings as that library also provides an altitude calculation. It has zero effect on the accuracy of anything else.

It also is no good for compensating any weather effects, so is more for experimentation - it is better to use a sample "ground level at now" and then measure differences rather than ever try to somehow measure an absolute above sea level with just a pressure sensor alone.

Normally if "altitude matters" you want to measure how high something went, or how high above the ground you are in the real time space, not how high above some arbitrary (sea level) number you are. You can always factor in the arbitrary number at another non-realtime time later if need be - well, according to my two cents anyway.

askjacob:
...

Arduino Pro Mini 5v 16MHz 328 (Maybe the 328 is key here? Unsure why it would be a major difference other than ram space although I find more and more quirks with the arduino compiler as I go...)
Bosch BMP180 sensor on breakout with 3v3 supply (ebay special)
Various other i2c devices not currently in use in test code (now in use in full code, and happily co-existing), other than the oLED used as the debug display (rather than serial terminal)

So essentially the same setup as I'm using except that mine are Pro Mini 3.3v boards.

Now, since I want to understand this to the fullest I'd like you to post your sensor variables for me please :slight_smile:

ac1 = ;
ac2 = ;
ac3 = ;
ac4 = ;
ac5 = ;
ac6 = ;
b1 = ;
b2 = ;
mb = ;
mc = ;
md = ;

I'm going to try to replicate it.

askjacob:
...
By the way - I popped over to your website to see if there was any updated code, and instead was enthalled by the rocketry and altimeter stuff - amazing stuff :slight_smile:

Thanks very much mate :slight_smile:

Now imagine if I had the problem with my altimeter (I'm using the Bosch sensor in one of them) I'd be in serious trouble. Rockets aren't very forgiving. Either everything works out 100% or your doomed.

Leo

I tried to replicate the problem but can't.

Example:

Oversampling setting (oss) = 0

Sensor calibration data:
AC1 = 408
AC2 = -72
AC3 = -14383
AC4 = 32741
AC5 = 32757
AC6 = 23153
B1 = 6190
B2 = 4
MB = -32768
MC = -8711
MD = 2868

Calculate true temperature:
UT = 27898 (raw temperature from sensor)
x1 = 4743
x2 = -2343
b5 = 2400
T = 150.00
T = 15.00

Temperature: 15.00 C, 59.00 F

Calculate true pressure:
UP = 23843 (raw pressure from sensor)
b6 = -1600
x1 = 1
x2 = 56
x3 = 57
b3 = 422
x1 = 2809
x2 = 59
x3 = 717
b4 = 33457
b7 = 1171050000
p = 70003
x1 = 74529
x1 = 3454
x2 = -7859

Pressure: 699.64 mbar, 20.66 inHg

Could you post your calibration data, UT and UP.