Barometric Pressure Sensor with Arduino

5 Comments

Atmospheric pressure is the force per unit area exerted against a surface by the weight of air above that surface in the Earth’s atmosphere. In most circumstances atmospheric pressure is closely approximated by the hydrostatic pressure caused by the weight of air above the measurement point. Low pressure areas have less atmospheric mass above their location, whereas high pressure areas have more atmospheric mass above their location. Similarly, as elevation increases there is less overlying atmospheric mass, so that pressure decreases with increasing elevation. A column of air one square inch in cross-section, measured from sea level to the top of the atmosphere, would weigh approximately 14.7 lbf (65 N).

In the old days, we use mercury barometer to measure.

Nowadays, digital barometer is commonly used because it is portable and accurate. An electrical capacitor in it is used to measure the change in air pressure. Bosch Sensortech introduces a new type of MEMS based pressure sensor.

Features:

  • Digital two wire (I2C) interface
  • Wide barometric pressure range
  • Flexible supply voltage range
  • Ultra-low power consumption
  • Low noise measurement
  • Fully calibrated
  • Temperature measurement included
  • Ultra-flat, small footprint

Interface this module with Arduino is simple:

BMP085 Vcc –> Arduino 3.3V

BMP085 GND –> Arduino GND

BMP085 SDA –>Arduino Analog In Pin4

BMP085 SCL –> Arduino Analog In Pin 5


Arduino source code:


// BMP08 with Arduino

// DANGER: The BMP08 accepts 1.8 to 3.6 Volts – so no chance to connect it directly to 5 Volts.

// Connect VCC to VCC and GND to GND, SCL goes to analogue pin 5, SDA to analogue pin4.
// Notice! Sparkfun breakoutboard contains already 4.7K pull ups,
// If not using pre-built pull-ups:
// --> Add some pull up resistors (1K to 20K, most often something like 4.7K) between SDA, SCL and VCC finishes the setup.

// References: http://interactive-matter.org/2009/12/arduino-barometric-pressure-sensor-bmp085/ and http://news.jeelabs.org/2009/02/1/hooking-up-a-bmp085-sensor/
// Specification: http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP085-DS000-05.pdf
// SparkFun breakout board: http://www.sparkfun.com/commerce/product_info.php?products_id=9694

#include "Wire.h"

#define I2C_ADDRESS 0x77

const unsigned char oversampling_setting = 3; //oversamplig for measurement
const unsigned char pressure_waittime[4] = {
  5, 8, 14, 26 };

//just taken from the BMP085 datasheet
int ac1;
int ac2;
int ac3;
unsigned int ac4;
unsigned int ac5;
unsigned int ac6;
int b1;
int b2;
int mb;
int mc;
int md;

void setup()
{
  Serial.begin(9600); // start serial for output
  Serial.println("Setting up BMP085");
  Wire.begin();
  bmp085_get_cal_data();
}
void bmp085_read_temperature_and_pressure(int& temperature, long& pressure);
void loop()
{
  int temperature = 0;
  long pressure = 0;

  bmp085_read_temperature_and_pressure(&temperature,&pressure);
  Serial.print(temperature,DEC);
  Serial.print(" ");
  Serial.print(pressure,DEC);
  Serial.println();
  delay(100);
}

void bmp085_read_temperature_and_pressure(int* temperature, long* pressure) {
  int ut= bmp085_read_ut();
  long up = bmp085_read_up();
  long x1, x2, x3, b3, b5, b6, p;
  unsigned long b4, b7;

  //calculate the temperature
  x1 = ((long)ut - ac6) * ac5 >> 15;
  x2 = ((long) 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;

  if (oversampling_setting == 3) b3 = ((int32_t) ac1 * 4 + x3 + 2) << 1;
  if (oversampling_setting == 2) b3 = ((int32_t) ac1 * 4 + x3 + 2);
  if (oversampling_setting == 1) b3 = ((int32_t) ac1 * 4 + x3 + 2) >> 1;
  if (oversampling_setting == 0) 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 >> oversampling_setting);
  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);

}

unsigned int bmp085_read_ut() {
  write_register(0xf4,0x2e);
  delay(5); //longer than 4.5 ms
  return read_int_register(0xf6);
}

void bmp085_get_cal_data() {
  Serial.println("Reading Calibration Data");
  ac1 = read_int_register(0xAA);
  Serial.print("AC1: ");
  Serial.println(ac1,DEC);
  ac2 = read_int_register(0xAC);
  Serial.print("AC2: ");
  Serial.println(ac2,DEC);
  ac3 = read_int_register(0xAE);
  Serial.print("AC3: ");
  Serial.println(ac3,DEC);
  ac4 = read_int_register(0xB0);
  Serial.print("AC4: ");
  Serial.println(ac4,DEC);
  ac5 = read_int_register(0xB2);
  Serial.print("AC5: ");
  Serial.println(ac5,DEC);
  ac6 = read_int_register(0xB4);
  Serial.print("AC6: ");
  Serial.println(ac6,DEC);
  b1 = read_int_register(0xB6);
  Serial.print("B1: ");
  Serial.println(b1,DEC);
  b2 = read_int_register(0xB8);
  Serial.print("B2: ");
  Serial.println(b1,DEC);
  mb = read_int_register(0xBA);
  Serial.print("MB: ");
  Serial.println(mb,DEC);
  mc = read_int_register(0xBC);
  Serial.print("MC: ");
  Serial.println(mc,DEC);
  md = read_int_register(0xBE);
  Serial.print("MD: ");
  Serial.println(md,DEC);
}

long bmp085_read_up() {
  write_register(0xf4,0x34+(oversampling_setting<<6));
  delay(pressure_waittime[oversampling_setting]);

  unsigned char msb, lsb, xlsb;
  Wire.beginTransmission(I2C_ADDRESS);
  Wire.send(0xf6); // register to read
  Wire.endTransmission();

  Wire.requestFrom(I2C_ADDRESS, 3); // read a byte
  while(!Wire.available()) {
    // waiting
  }
  msb = Wire.receive();
  while(!Wire.available()) {
    // waiting
  }
  lsb |= Wire.receive();
  while(!Wire.available()) {
    // waiting
  }
  xlsb |= Wire.receive();
  return (((long)msb<<16) | ((long)lsb<<8) | ((long)xlsb)) >>(8-oversampling_setting);
}

void write_register(unsigned char r, unsigned char v)
{
  Wire.beginTransmission(I2C_ADDRESS);
  Wire.send(r);
  Wire.send(v);
  Wire.endTransmission();
}

char read_register(unsigned char r)
{
  unsigned char v;
  Wire.beginTransmission(I2C_ADDRESS);
  Wire.send(r); // register to read
  Wire.endTransmission();

  Wire.requestFrom(I2C_ADDRESS, 1); // read a byte
  while(!Wire.available()) {
    // waiting
  }
  v = Wire.receive();
  return v;
}

int read_int_register(unsigned char r)
{
  unsigned char msb, lsb;
  Wire.beginTransmission(I2C_ADDRESS);
  Wire.send(r); // register to read
  Wire.endTransmission();

  Wire.requestFrom(I2C_ADDRESS, 2); // read a byte
  while(!Wire.available()) {
    // waiting
  }
  msb = Wire.receive();
  while(!Wire.available()) {
    // waiting
  }
  lsb = Wire.receive();
  return (((int)msb<<8) | ((int)lsb));
}

Once finish compile and upload, open Serial Monitor from Arduino IDE, and set the baud rate to 9600. You should see print out like:

Setting up BMP085
Reading Calibration Data
AC1: 8755
AC2: -1074
AC3: -14382
AC4: 33510
AC5: 24991
AC6: 22852
B1: 5498
B2: 5498
MB: -32768
MC: -11075
MD: 2432
166 100882
166 100875
166 100869
166 100883
166 100886
166 100878
167 100897
165 100860
166 100885
165 100859
166 100887
166 100872
165 100862
166 100888
166 100877
165 100856
166 100883
166 100883
166 100897
166 100895
166 100885
166 100894
165 100865
165 100863
165 100873
165 100867
165 100870
166 100896
166 100880
166 100887
165 100876
166 100888
166 100881
165 100872
165 100873
165 100887
165 100884
... ...

Reference

Atmospheric pressure on Wikipedia
BMP085 Breakout board from Sparkfun
Arduino source code

5 Comments (+add yours?)

  1. pfeili
    Mar 23, 2012 @ 21:18:18

    it doesn’t work with my arduino even i connected it in the way you mentioned. if i watch the serial i can only read:

    Setting up BMP085
    Reading Calibration Data

    then it stops. no other information is readable. maybe i have to use the pull-ups. but how should i do that. sorry but i’m absolutely new in this issues.

    kind regards,

    pfeili

  2. Steve
    May 16, 2012 @ 16:23:34

    The problem is that this code is written for Arduino before 1.0.

    I’m looking for a fix now…. was hoping to find it here.

  3. Brian Magnuson
    Jul 07, 2012 @ 08:19:05

    How can the output be converted to Fahrenheit and Millibars in code as another output for those who are metrically challenged? Thanks.

  4. L'Horloge
    Nov 09, 2012 @ 22:36:04

    Hi !

    Do you have fix the code to Arduino post 1.0 ?
    With your code, I have this error (I manage it to you) :

    Barometre:176: error: ‘class TwoWire’ has no member named ‘send’
    Depuis Arduino 1.0, la fonction Wire.send() à été renommée en Wire.write() pour maintenir une cohérence avec d’autres bibliothèques.
    Barometre:183: error: ‘class TwoWire’ has no member named ‘receive’
    Depuis Arduino 1.0, la fonction Wire.receive() a été renommée en Wire.read() pour maintenir une cohérence avec

    Thanks

  5. tgtl
    Nov 15, 2012 @ 01:47:48

    @l’horloge:
    you just have to replace Wire.send() with Wire.write() etc. ;)

    another thing is connecting to pins, pins A4 and A5 are ok only in arduino uno and ethernet.

    from arduino site:
    Board I2C / TWI pins
    Uno, Ethernet A4 (SDA), A5 (SCL)
    Mega2560 20 (SDA), 21 (SCL)
    Leonardo 2 (SDA), 3 (SCL)
    Due 20 (SDA), 21 (SCL), SDA1, SCL1

Leave a Reply

*

Spam Protection by WP-SpamFree

Switch to our mobile site