BMP180 giving incorrect temperature

I am using 4 pin bmp180 sensor connected to Arduino Nano board. I have run some basic sketch from Examples to see if it is functioning. While it is giving other readings, the temp reading is way off at 220 deg C. I varied my altitude but the temp remains at 220 deg C no matter the altitude. I have seen other users get normal temp using same sketch. I connected and checked at both 5v and 3.3v. I am attaching code:

 * SFE_BMP180 library example sketch

This sketch shows how to use the SFE_BMP180 library to read the
Bosch BMP180 barometric pressure sensor.
https://www.sparkfun.com/products/11824

Like most pressure sensors, the BMP180 measures absolute pressure.
This is the actual ambient pressure seen by the device, which will
vary with both altitude and weather.

Before taking a pressure reading you must take a temparture reading.
This is done with startTemperature() and getTemperature().
The result is in degrees C.

Once you have a temperature reading, you can take a pressure reading.
This is done with startPressure() and getPressure().
The result is in millibar (mb) aka hectopascals (hPa).

If you'll be monitoring weather patterns, you will probably want to
remove the effects of altitude. This will produce readings that can
be compared to the published pressure readings from other locations.
To do this, use the sealevel() function. You will need to provide
the known altitude at which the pressure was measured.

If you want to measure altitude, you will need to know the pressure
at a baseline altitude. This can be average sealevel pressure, or
a previous pressure reading at your altitude, in which case
subsequent altitude readings will be + or - the initial baseline.
This is done with the altitude() function.

Hardware connections:

- (GND) to GND
+ (VDD) to 3.3V

(WARNING: do not connect + to 5V or the sensor will be damaged!)

You will also need to connect the I2C pins (SCL and SDA) to your
Arduino. The pins are different on different Arduinos:

Any Arduino pins labeled:  SDA  SCL
Uno, Redboard, Pro:        A4   A5
Mega2560, Due:             20   21
Leonardo:                   2    3

Leave the IO (VDDIO) pin unconnected. This pin is for connecting
the BMP180 to systems with lower logic levels such as 1.8V

Have fun! -Your friends at SparkFun.

The SFE_BMP180 library uses floating-point equations developed by the
Weather Station Data Logger project: http://wmrx00.sourceforge.net/

Our example code uses the "beerware" license. You can do anything
you like with this code. No really, anything. If you find it useful,
buy me a beer someday.

V10 Mike Grusin, SparkFun Electronics 10/24/2013a
*/

// Your sketch must #include this library, and the Wire library.
// (Wire is a standard library included with Arduino.):

#include <SFE_BMP180.h>
#include <Wire.h>

// You will need to create an SFE_BMP180 object, here called "pressure":

SFE_BMP180 pressure;

#define ALTITUDE 34.0 // Altitude of SparkFun's HQ in Boulder, CO. in meters

void setup()
{
  Serial.begin(9600);
  Serial.println("REBOOT");

  // Initialize the sensor (it is important to get calibration values stored on the device).

  if (pressure.begin())
    Serial.println("BMP180 init success");
  else
  {
    // Oops, something went wrong, this is usually a connection problem,
    // see the comments at the top of this sketch for the proper connections.

    Serial.println("BMP180 init fail\n\n");
    while(1); // Pause forever.
  }
}

void loop()
{
  char status;
  double T,P,p0,a;

  // Loop here getting pressure readings every 10 seconds.

  // If you want sea-level-compensated pressure, as used in weather reports,
  // you will need to know the altitude at which your measurements are taken.
  // We're using a constant called ALTITUDE in this sketch:
  
  Serial.println();
  Serial.print("provided altitude: ");
  Serial.print(ALTITUDE,0);
  Serial.print(" meters, ");
  Serial.print(ALTITUDE*3.28084,0);
  Serial.println(" feet");
  
  // If you want to measure altitude, and not pressure, you will instead need
  // to provide a known baseline pressure. This is shown at the end of the sketch.

  // You must first get a temperature measurement to perform a pressure reading.
  
  // Start a temperature measurement:
  // If request is successful, the number of ms to wait is returned.
  // If request is unsuccessful, 0 is returned.

  status = pressure.startTemperature();
  if (status != 0)
  {
    // Wait for the measurement to complete:
    delay(status);

    // Retrieve the completed temperature measurement:
    // Note that the measurement is stored in the variable T.
    // Function returns 1 if successful, 0 if failure.

    status = pressure.getTemperature(T);
    if (status != 0)
    {
      // Print out the measurement:
      Serial.print("temperature: ");
      Serial.print(T,2);
      Serial.print(" deg C, ");
      Serial.print((9.0/5.0)*T+32.0,2);
      Serial.println(" deg F");
      
      // Start a pressure measurement:
      // The parameter is the oversampling setting, from 0 to 3 (highest res, longest wait).
      // If request is successful, the number of ms to wait is returned.
      // If request is unsuccessful, 0 is returned.

      status = pressure.startPressure(3);
      if (status != 0)
      {
        // Wait for the measurement to complete:
        delay(status);

        // Retrieve the completed pressure measurement:
        // Note that the measurement is stored in the variable P.
        // Note also that the function requires the previous temperature measurement (T).
        // (If temperature is stable, you can do one temperature measurement for a number of pressure measurements.)
        // Function returns 1 if successful, 0 if failure.

        status = pressure.getPressure(P,T);
        if (status != 0)
        {
          // Print out the measurement:
          Serial.print("absolute pressure: ");
          Serial.print(P,2);
          Serial.print(" mb, ");
          Serial.print(P*0.0295333727,2);
          Serial.println(" inHg");

          // The pressure sensor returns abolute pressure, which varies with altitude.
          // To remove the effects of altitude, use the sealevel function and your current altitude.
          // This number is commonly used in weather reports.
          // Parameters: P = absolute pressure in mb, ALTITUDE = current altitude in m.
          // Result: p0 = sea-level compensated pressure in mb

          p0 = pressure.sealevel(P,ALTITUDE); // we're at 1655 meters (Boulder, CO)
          Serial.print("relative (sea-level) pressure: ");
          Serial.print(p0,2);
          Serial.print(" mb, ");
          Serial.print(p0*0.0295333727,2);
          Serial.println(" inHg");

          // On the other hand, if you want to determine your altitude from the pressure reading,
          // use the altitude function along with a baseline pressure (sea-level or other).
          // Parameters: P = absolute pressure in mb, p0 = baseline pressure in mb.
          // Result: a = altitude in m.

          a = pressure.altitude(P,p0);
          Serial.print("computed altitude: ");
          Serial.print(a,0);
          Serial.print(" meters, ");
          Serial.print(a*3.28084,0);
          Serial.println(" feet");
        }
        else Serial.println("error retrieving pressure measurement\n");
      }
      else Serial.println("error starting pressure measurement\n");
    }
    else Serial.println("error retrieving temperature measurement\n");
  }
  else Serial.println("error starting temperature measurement\n");

  delay(5000);  // Pause for 5 seconds.
} 

Pretty standard code, then what is causing the issue? Please share possible solutions. I'm fairly new at Arduino and new at this forum.

An "if" statement will only check once for a status before moving on. It's been a while since I last used the BMP280 but I think if you read before a measurement is complete the return value will always be the same.

Try changing your sketch to use "do...while" loops instead of "if" and "delay". In pseudocode it would be something like:

create status variable
start temperature reading

do
  -check temperature and update status
while status is not complete

Display results

Basically, you want to loop several times until the sensor is correctly read before moving on. Looping several times might be needed to ensure the reading completes. I hope that helps.

Is there any situation where delay is actually useful on a micro, except to give a very crude example, or for functions that are not part of the loop, and are ran only when needed and when nothing else is happening?

It seems to me that there's always a better option then to freeze the main loop, or use it altogether, it should probably just be removed from all example code.

I mean its always better to set flags then to pause the process, when ever I wanted to integrate anything into my project I had to find a work around for delay

I don't think delay is the best option as it will block all program operation. I use it to verify basic operation but then move onto a better method. I've had a lot of success with timer interrupts, the millis() command, and the Ticker library (linked here: Ticker Library )

@aer_a , I followed the link in the comment in your sample code and I see you've copied the code from the SparkFun github. It may be worth testing the same module with the Adafruit BMP180 sample code too: Adafruit BMP085 Unified. It might help a little in the debugging process.

If that doesn't solve it he should probably check hardware...

A little while ago I looked in the source code of a few BMP180 libaries, and discovered that those libraries use delay within them.
So even when you think you removed all delays from your own code that may not be the case for the compiled program
The referenced Adafruit library also uses delay.

I think the max it uses is 26 milliseconds of delay on ultra high sampling resolution.

1 Like

Good point @hmeijdam, I modelled part of my last project off of Adafruit's library and forgot that they used delays. My project had a loop that ran every 100ms using the timer interrupt. I just read the previous measurement and started a new measurement at the beginning of every loop. That gave somewhere between 80~99ms depending on the complexity of the tasks during a single loop and I set the refresh rate to 62.5ms per the BME280 datasheet. I had a good reading "guaranteed" at the beginning of every loop.

There certainly isn't a problem with short delays here and there, just make sure the delay is long enough for the sensor to complete the reading before checking that reading.

For the case where I wanted to avoid delay I settled on the BMP180MI library this has the option to use:

  1. A single "readpressure" command, that will send the read command to the sensor and uses delay to wait for the response

or

  1. A separate "getPressure" command, a "hasValue" command and a "measurePressure" command. This takes the pressure reading apart in 3 steps that can be done without using delay.

Below is a sketch I made for the Attiny806 (using MagaTinycore) that has the temperature and pressure reading in a Switch-Case statement.
If you remove the stuff related to writing to the USART directly and put some print statements instead it should work on an Arduino (but did not test that myself).

//#define USE_ALTERNATE_TXD  //  uncomment if you want to use the alternate TXD* / RXD* pins

#include <Wire.h>
#include <BMP180I2C.h>
#define I2C_ADDRESS 0x77
BMP180I2C bmp180(I2C_ADDRESS);

int main(void) {
  char state  = 0;
  uint16_t kel; //temp in Kelvin
  uint16_t previous_kel;
  uint32_t pa; 

  // reconfigure CPU clock prescaler
  CCP = CCP_IOREG_gc;    // enable write to protected IO registers (timed sequence)
  CLKCTRL_MCLKCTRLB = 0; // turn off prescaler (and the default factor 6 division)
  USART_init(9600);      //Call the USART initialization code and choose ( baudrate )

  char printbuffer[7];   //The ASCII of the integer will be stored in this char array
  const static uint8_t Sometext[] = " and counting !\r\n"; // A string array with some fixed text
  const static uint8_t temperature[] = "Temperature "; // A string array with some fixed text
  const static uint8_t kelvin[] = " DegK\r\n"; // A string array with some fixed text
  const static uint8_t pressure[] = "Pressure: "; // A string array with some fixed text
  const static uint8_t pascal[] = " Pa\r\n"; // A string array with some fixed text

  Wire.begin();
  if (bmp180.begin()) {   // initializes the interface, checks the sensor ID and reads the calibration parameters.
    bmp180.resetToDefaults();  //sensor to default parameters.
    bmp180.setSamplingMode(BMP180MI::MODE_UHR);  //enable ultra high resolution mode for pressure measurements
    state = 1;
  }

  while (1) {      //Infinite loop
    switch (state) {  // note: if state = 0 BMP has not started and switch will be skipped
      case 1: //start a temperature measurement
        if (bmp180.measureTemperature()) {
          state = 2;
        }
        break;
      case 2: //check if temperature measurement has finished. proceed as soon as hasValue() returned true.
        if (bmp180.hasValue()) {
          kel =  bmp180.getTemperature() + 273;
          if (!(kel == previous_kel)) {
            USART_putstring(temperature);
            itoa(kel, printbuffer, 10);    //(integer, yourBuffer, base)
            USART_putstring(printbuffer); // print the
            USART_putstring(kelvin);
            previous_kel = kel;
          }
          state = 3;
        }
        break;
      case 3: //start a pressure measurement. pressure measurements depend on temperature measurement
        if (bmp180.measurePressure()) {
          state = 4;
        }
        break;
      case 4://check if pressure measurement has finished. proceed as soon as hasValue() returned true.
        if (bmp180.hasValue()) {
          pa = bmp180.getPressure();
          USART_putstring(pressure);
          ltoa(pa, printbuffer, 10);    //(long, yourBuffer, base)
          USART_putstring(printbuffer); // print the
          USART_putstring(pascal);
          state = 1;
        }
        break;
    }
  }
}

void USART_init(uint32_t BAUDRATE) {
  USART0_BAUD = (F_CPU * 4LL / BAUDRATE);
#ifdef USE_ALTERNATE_TXD
  PORTMUX_CTRLB = PORTMUX_USART0_bm; // activate alternate RXD* / TXD* pins
  //  VPORTA_DIR |= PIN1_bm;   // set pin PA1 as output (select manually to save flash)
  pinModeFast(PIN_HWSERIAL0_TX_PINSWAP_1, OUTPUT); // let the core to figure out the pin (uses more memory)
#else
  // VPORTA_DIR |= PIN6_bm;   // set pin PA6 as output (select manually to save flash)
  pinModeFast(PIN_HWSERIAL0_TX, OUTPUT); // if you want the core to figure out the pin (uses more memory)
#endif
  USART0_CTRLB |= USART_TXEN_bm ; //enable tx only
}

void USART_send(unsigned char data) {
  while (!(USART0_STATUS & USART_DREIF_bm));
  USART0_TXDATAL = data;
}

void USART_putstring(char* StringPtr) {
  while (*StringPtr != 0x00) {
    USART_send(*StringPtr);
    StringPtr++;
  }
}

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