Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

BMP085 Barometric Pressure Sensor

Status
Not open for further replies.

DirtyLude

Well-Known Member
I just wanted to post a quick note on this sensor because it's pretty cool. I bought one to add to a datalogging system I'm going to use while canoeing. It'll have GPS, Pressure, Temperature, and Humidity. That's all that I could think of. So I bought this sensor and made up a little board for it.

The sensor has a thermometer and pressure sensor in it and the temperature is used to compensate the pressure data. It doesn't do this itself, you have to do it. There is also a bunch of encoded calibration data in the chip itself you need to take into account. So there's a bunch of coding you'll need to do on your microcontroller.

I just pulled all the calculations from these arduino sites where the code is simply based off the datasheet, but slightly cleaned up. Looks like you can get a breakout board from the first link; second link shows that if you are pretty careful you can directly solder some small gauge wires. You only need a few connections.
**broken link removed**
**broken link removed**

Anyway, the thing can really tell the difference in pressure every few feet, even at its lowest resolution. Here it is showing the data its getting. The temperature is in degrees Celsius. I didn't bother putting in a decimal point, it's 23.2 degrees. Fairly warm. Temperature data seems much more sensitive than the LM75. Putting my finger on it, it immediately jumps several degrees, very quickly. The Pressure is shown in Pascals and it's about 20 Pascals difference in the Pressure at my feet compared to at my head height.
20100315-bmp085-di&#.jpg

Here is the code I used for calculations, but it's pretty much the same as in the linked pages.

First you have to get all the calibration data stored in ROM. You only need to do this once.
Code:
  I2CWriteLength = 2;
  I2CReadLength = 22;
  I2CMasterBuffer[0] = BMP085_ADDR;
  I2CMasterBuffer[1] = 0xAA;
  I2CMasterBuffer[2] = BMP085_ADDR | RD_BIT;
  I2CEngine();
  ac1 = (I2CSlaveBuffer[0] << 8) | I2CSlaveBuffer[1];
  ac2 = (I2CSlaveBuffer[2] << 8) | I2CSlaveBuffer[3];
  ac3 = (I2CSlaveBuffer[4] << 8) | I2CSlaveBuffer[5];
  ac4 = (I2CSlaveBuffer[6] << 8) | I2CSlaveBuffer[7];
  ac5 = (I2CSlaveBuffer[8] << 8) | I2CSlaveBuffer[9];
  ac6 = (I2CSlaveBuffer[10] << 8) | I2CSlaveBuffer[11];
  b1  = (I2CSlaveBuffer[12] << 8) | I2CSlaveBuffer[13];
  b2  = (I2CSlaveBuffer[14] << 8) | I2CSlaveBuffer[15];
  mb  = (I2CSlaveBuffer[16] << 8) | I2CSlaveBuffer[17];
  mc  = (I2CSlaveBuffer[18] << 8) | I2CSlaveBuffer[19];
  md  = (I2CSlaveBuffer[20] << 8) | I2CSlaveBuffer[22];

Then you retrieve the uncompensated raw temp and pressure data from the sensor and use them in these calculations.
Code:
//Retrieve the Uncompensated Termperature (ut) and the Uncompensated Pressure (up)
//This code has been cut out.  Just standard I2C data retrieve

  //calculate the temperature
  x1 = (ut - ac6) * ac5 >> 15;
  x2 = ((int32_t) mc << 11) / (x1 + md);
  b5 = x1 + x2;
  temperature = (b5 + 8) >> 4;

  //calculate the pressure
  b6 = b5 - 4000;
  x1 = (b2 * (b6 * b6 >> 12)) >> 11;
  x2 = ac2 * b6 >> 11;
  x3 = x1 + x2;
  b3 = ((int32_t) ac1 * 4 + x3 + 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;
  p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;
 	
  x1 = (p >> 8) * (p >> 8);
  x1 = (x1 * 3038) >> 16;
  x2 = (-7357 * p) >> 16;
  pressure = p + ((x1 + x2 + 3791) >> 4);

This is a better picture of the sensor mounted.
20100308-lpc1114-b&#11.jpg
 
Last edited:
Hi Mark, I've just started trying to use this same sensor.
Would you mind posting up the complete code, maybe as a zip ?
Also what compiler is it you are using ?
It looks similar to PicBasic Pro.
Martin
 
I used an LPC1114 with Crossworks. The rest of my code isn't going to help you any unless you're using the same.
 
I used an LPC1114 with Crossworks. The rest of my code isn't going to help you any unless you're using the same.
Thanks anyway Mark.
Your code has helped me a bit as it is. The way you handle the calibration data particularly.
My next phase is working out if I need signed math to do the conversions, signed values are not something I've needed before today.
Martin
 
Do you mean floating point or signed? You do not need floats for this. You can see the variable types in the datasheet and the link I posted. These are my variable declarations for this. All signed or unsigned declarations, but no float types are needed.

Code:
int16_t ac1;
int16_t ac2;
int16_t ac3;
uint16_t ac4;
uint16_t ac5;
uint16_t ac6;
int16_t b1;
int16_t b2;
int16_t b3;
uint32_t b4;
int32_t b5;
int32_t b6;
uint32_t b7;
int16_t mb;
int16_t mc;
int16_t md;
int32_t ut;   //uncompensated temperature
int32_t up;   //uncompensated pressure
int32_t x1;
int32_t x2;
int32_t x3;
int32_t t;   //temperature
int32_t p;   //pressure
 
Thanks,
No I meant signed. I'm unfamiliar with signed coding, and am trying to bootstrap myself in how it can be done with PBP. I've had no formal programmer training, so I learn each new item required as I go along. Yes it's slow :)

So in your list uint32_t b7 would be unsigned, and int16_t mb is signed ?

I see what you mean about the temperature sensor, it's very sensitive.
Martin
 
Yes, in C this is the naming convention for specific width integers. Technically the standard C 'int' type can be a different number of bits depending on the platform you are using.
intN_t is signed integer, N bit length.
uintN_t is unsigned integer, N bit length.

If you are using C, unless you are planning on doing some bit manipulation of the signed integer, the signed arithmetic should be no different than unsigned and should be transparent to you.
 
Last edited:
BMP085 code for LPC, since I've given up with the PIC18F

I've decided to transition my code to the LPC after trying and not getting the results I wanted with the PIC18F I'd been using.. i get either odd behavior at temperatures above 25C or weird multi-thousand feet offsets in expected altitude when i solve the 25C problem.. .both are issue I put down to a possible combination of my code and weirdness in the MP{LAB compiler behavior when bit shifting signed 32bit integers.

So I'm going 32bit and ARM 7, can you let me know if the code you have arrived at works well in these and any other respects ?, the 25C problem seems to be well know about, but I've not heard of anyone else seeing the large vertical offsets when fixing that problem (using divides and multiplies instead of shifts)

Besides, the LPC gives me far more power for the same money...why would I not.

Thanks ,

Peter
 
I managed to sort it all out using 32bit math option in PicBasic Pro and an 18F1320. I too had odd issues with readings, but eventually found all to be caused by bad assumptions with Longs and Signed Longs etc etc. So once I sorted the math the rest of it was fine. Did you see this calculator for Excel ?
 

Attachments

  • BMP085 Test Calculator.zip
    4.6 KB · Views: 610
So I'm going 32bit and ARM 7, can you let me know if the code you have arrived at works well in these and any other respects ?
...
Besides, the LPC gives me far more power for the same money...why would I not.

The code I wrote is running on lpc1114/lpc1313 under Crossworks/GCC. If you want to go ARM, then go Cortex-M3 or Cortex-M0. ARM7 is less speed, more cost, more complexity. I haven't touched ARM7 in a while now.
 
DirtyLude,

You are correct, the LPC I'm looking at is the LPC1751 (cortex) of course..., I've been playing with the higher end ARM 9 stuff for a while now on Crossworks (awesome toolset btw, beats the pants off MPLAB for usability and I get to play in my comfy linux environment), I guess I'm used to those cores.. time to branch out into the world of Cortex.

And Mr. Sneezy, thanks for the Excel calculator, thats an extremely valuable tool in checking out the math, I may be persuaded to stay with the PIC a little longer once I try it out with my values and see where my math goes awry...

Thank you guys,
 
Mark,

I'm back on track with my project having finally sent my prototype PCB away for manufacture and when I looked back at this email thread, I realise I'm using the exact combination you are... LPC1114, BMP085 and Crossworks on Ubuntu. I realise its a liberty, but is there any chance you can share your code, to get me started. Its been quite some time since I used Crossworks and I'm totally new to the LPC1114 (I had avoided the lower end Cortex M0 chips originally since it looked like they didn't provide PWM's, but they do... just a lot more flexibly through the use of timers) so I can reel back my requirements to the LPC1114 rather than the LPC1700's that I was originally planning.

Cheers,

Peter
 
This is using the delivered libraries from NXP. I2C Engine and timer code.

I'm not certain why but I've had to put a delay in the I2C engine to make it work. I haven't heard of anyone else needing this, but if I don't do it, the NXP I2C routines freeze.

This code should work fine, but I haven't played with this for months now. I've been doing small automotive stuff with the MSP430.

header
Code:
#ifndef __BMP085_H
#define __BMP085_H

extern int8_t bmp085_initialize( void);
extern int32_t bmp085_get( int32_t *p, int32_t *t);

#endif // __LIB_LCD7110_H

library
Code:
#include "LPC11xx.h"                        /* LPC13xx definitions */
#include "i2c.h"
#include "timer32.h"

#define BMP085_ADDR 0xEE
#define BMP085_OSS  0x01  //Oversampling Setting (modes 1 thru 4)

int16_t ac1;
int16_t ac2;
int16_t ac3;
uint16_t ac4;
uint16_t ac5;
uint16_t ac6;
int16_t b1;
int16_t b2;
int16_t b3;
uint32_t b4;
int32_t b5;
int32_t b6;
uint32_t b7;
int16_t mb;
int16_t mc;
int16_t md;
int32_t ut;   //uncompensated temperature
int32_t up;   //uncompensated pressure
int32_t x1;
int32_t x2;
int32_t x3;
int32_t t;   //temperature
int32_t p;   //pressure

extern volatile uint32_t I2CCount;
extern volatile uint8_t I2CMasterBuffer[BUFSIZE];
extern volatile uint8_t I2CSlaveBuffer[30];
extern volatile uint32_t I2CMasterState;
extern volatile uint32_t I2CReadLength, I2CWriteLength;

int8_t bmp085_initialize( void)
{
  /* Get calibration data */
  I2CWriteLength = 2;
  I2CReadLength = 22;
  I2CMasterBuffer[0] = BMP085_ADDR;
  I2CMasterBuffer[1] = 0xAA;
  I2CMasterBuffer[2] = BMP085_ADDR | RD_BIT;
  I2CEngine();
  ac1 = (I2CSlaveBuffer[0] << 8) | I2CSlaveBuffer[1];
  ac2 = (I2CSlaveBuffer[2] << 8) | I2CSlaveBuffer[3];
  ac3 = (I2CSlaveBuffer[4] << 8) | I2CSlaveBuffer[5];
  ac4 = (I2CSlaveBuffer[6] << 8) | I2CSlaveBuffer[7];
  ac5 = (I2CSlaveBuffer[8] << 8) | I2CSlaveBuffer[9];
  ac6 = (I2CSlaveBuffer[10] << 8) | I2CSlaveBuffer[11];
  b1  = (I2CSlaveBuffer[12] << 8) | I2CSlaveBuffer[13];
  b2  = (I2CSlaveBuffer[14] << 8) | I2CSlaveBuffer[15];
  mb  = (I2CSlaveBuffer[16] << 8) | I2CSlaveBuffer[17];
  mc  = (I2CSlaveBuffer[18] << 8) | I2CSlaveBuffer[19];
  md  = (I2CSlaveBuffer[20] << 8) | I2CSlaveBuffer[21];

  if( ac1 == 0xFF)
    return 0;

  return 1;
}

int32_t bmp085_get( int32_t *p, int32_t *t)
{
 //get uncompensated temp value
  I2CWriteLength = 3;
  I2CReadLength = 0;
  I2CMasterBuffer[0] = BMP085_ADDR;
  I2CMasterBuffer[1] = 0xF4;
  I2CMasterBuffer[2] = 0x2E;
  I2CEngine();

  delay32Ms(0, 6);          
//  delay_ms( 20);

  I2CWriteLength = 2;
  I2CReadLength = 2;
  I2CMasterBuffer[0] = BMP085_ADDR;
  I2CMasterBuffer[1] = 0xF6;
  I2CMasterBuffer[2] = BMP085_ADDR | RD_BIT;
  I2CEngine();
  ut= (I2CSlaveBuffer[0] << 8) | I2CSlaveBuffer[1];

 //get uncompensated pressure value
  I2CWriteLength = 3;
  I2CReadLength = 1;
  I2CMasterBuffer[0] = BMP085_ADDR;
  I2CMasterBuffer[1] = 0xF4;
  I2CMasterBuffer[2] = 0x34 + (BMP085_OSS << 6);
  I2CEngine();

  delay32Ms(0, 15 + BMP085_OSS);          
//  delay_ms( 20);
  I2CWriteLength = 2;
  I2CReadLength = 3;
  I2CMasterBuffer[0] = BMP085_ADDR;
  I2CMasterBuffer[1] = 0xF6;
  I2CMasterBuffer[2] = BMP085_ADDR | RD_BIT;
  I2CEngine();
  up  = ((I2CSlaveBuffer[0] << 16) | (I2CSlaveBuffer[1] << 8) | I2CSlaveBuffer[1]) >> (8 - BMP085_OSS);

  //calculate the temperature
  x1 = (ut - ac6) * ac5 >> 15;
  x2 = ((int32_t) mc << 11) / (x1 + md);
  b5 = x1 + x2;
  *t = (b5 + 8) >> 4;

  //calculate the pressure
  b6 = b5 - 4000;
  x1 = (b2 * (b6 * b6 >> 12)) >> 11;
  x2 = ac2 * b6 >> 11;
  x3 = x1 + x2;
  b3 = (((int32_t) ac1 * 4 + x3) << BMP085_OSS) >> 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 >> BMP085_OSS);
  *p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;
 	
  x1 = (*p >> 8) * (*p >> 8);
  x1 = (x1 * 3038) >> 16;
  x2 = (-7357 * *p) >> 16;
  *p = *p + ((x1 + x2 + 3791) >> 4);
}

Modified I2C library function:
Code:
uint32_t I2CEngine( void ) 
{
  I2CMasterState = I2C_IDLE;
  RdIndex = 0;
  WrIndex = 0;
  if ( I2CStart() != TRUE )
  {
	I2CStop();
	return ( FALSE );
  }

  while ( 1 )
  {
	if ( I2CMasterState == DATA_NACK )
	{
          delay32Ms(0, 2); //This line has been added to the original code.         
	  I2CStop();
	  break;
	}
  }    
  return ( TRUE );      
}
 
Last edited:
Mark, as a friend of mine says a little too often... "you da' man !!"

Thanks, I'll be gettinng my board back from the fab house next week and I'll let you know if I figure out any tweaks to the code, thanks a million, this should save me a chunk of time.

I spent the vast majority of my time on the PIC's debugging the I2C code , its well documented, but by a lot of people in a lot of different ways, I'm not surprised that it gave problems here too... it seems that for a lot of this stuff you pretty much have to figure it out by yourself with too much information to mislead you to the truth.., learning a lot on the way... :)

Cheers,

Peter
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top