Pressure, Temperature, Altitude Sensor on breakout from sparkfun (I2C)

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BMP085.cpp Source File

BMP085.cpp

00001 /*
00002  * @file BMP085.cpp
00003  * @author Tyler Weaver
00004  * @author Kory Hill
00005  *
00006  * @section LICENSE
00007  *
00008  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00009  * and associated documentation files (the "Software"), to deal in the Software without restriction,
00010  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
00011  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
00012  * furnished to do so, subject to the following conditions:
00013  *
00014  * The above copyright notice and this permission notice shall be included in all copies or
00015  * substantial portions of the Software.
00016  *
00017  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00018  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00019  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00020  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00021  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00022  *
00023  * @section DESCRIPTION
00024  *
00025  * BMP085 I2C Temperature/Pressure/Altitude Sensor
00026  *
00027  * Datasheet:
00028  *
00029  * http://dlnmh9ip6v2uc.cloudfront.net/datasheets/Sensors/Pressure/BST-BMP085-DS000-06.pdf
00030  */
00031 
00032 #include "BMP085.h"
00033 #include <new>
00034 
00035 BMP085::BMP085(PinName sda, PinName scl) : i2c_(*reinterpret_cast<I2C*>(i2cRaw))
00036 {
00037     // Placement new to avoid additional heap memory allocation.
00038     new(i2cRaw) I2C(sda, scl);
00039 
00040     init();
00041 }
00042 
00043 BMP085::~BMP085()
00044 {
00045     // If the I2C object is initialized in the buffer in this object, call destructor of it.
00046     if(&i2c_ == reinterpret_cast<I2C*>(&i2cRaw))
00047         reinterpret_cast<I2C*>(&i2cRaw)->~I2C();
00048 }
00049 
00050 void BMP085::init()
00051 {
00052     get_cal_param();
00053     set_oss(8); // standard over sampling (2 samples)
00054     get_ut(); // initalize values
00055     get_up();
00056 }
00057 
00058 void BMP085::get_cal_param()
00059 {
00060     // get calibration values
00061     AC1 = read_int16(0xAA);
00062     AC2 = read_int16(0xAC);
00063     AC3 = read_int16(0xAE);
00064     AC4 = read_uint16(0xB0);
00065     AC5 = read_uint16(0xB2);
00066     AC6 = read_uint16(0xB4);
00067     B1  = read_int16(0xB6);
00068     B2  = read_int16(0xB8);
00069     MB  = read_int16(0xBA);
00070     MC  = read_int16(0xBC);
00071     MD  = read_int16(0xBE);
00072 }
00073 
00074 void BMP085::display_cal_param(Serial *pc)
00075 {
00076     pc->printf("AC1 %x\r\n", AC1);
00077     pc->printf("AC2 %x\r\n", AC2);
00078     pc->printf("AC3 %x\r\n", AC3);
00079     pc->printf("AC4 %x\r\n", AC4);
00080     pc->printf("AC5 %x\r\n", AC5);
00081     pc->printf("AC6 %x\r\n", AC6);
00082     pc->printf("B1 %x\r\n", B1);
00083     pc->printf("B2 %x\r\n", B2);
00084     pc->printf("MB %x\r\n", MB);
00085     pc->printf("MC %x\r\n", MC);
00086     pc->printf("MD %x\r\n", MD);
00087 }
00088 
00089 void BMP085::get_ut()
00090 {
00091     write_char(0xF4,0x2E);
00092     wait(0.045);
00093     char buffer[3];
00094     read_multiple(0xF6, buffer, 2);
00095     
00096     UT = (buffer[0]<<8) | buffer[1];
00097 }
00098 
00099 void BMP085::get_up()
00100 {
00101     // set sample setting
00102     write_char(0xF4, oversampling_setting_);
00103     
00104     // wait
00105     wait(conversion_time_);
00106     
00107     // read the three bits
00108     char buffer[3];
00109     read_multiple(0xF6, buffer, 3);
00110     
00111     UP = ((buffer[0]<<16) | (buffer[1]<<8) | (buffer[2])) >> (8 - oss_bit_);
00112 }
00113 
00114 void BMP085::set_oss(int oss)
00115 {
00116     switch(oss) {
00117         case 1: // low power
00118             oss_bit_ = 0;
00119             oversampling_setting_ = 0x34;
00120             conversion_time_ = 0.045;
00121             break;
00122         case 2: // standard
00123             oss_bit_ = 1;
00124             oversampling_setting_ = 0x74;
00125             conversion_time_ = 0.075;
00126             break;
00127         case 4: // high resolution
00128             oss_bit_ = 2;
00129             oversampling_setting_ = 0xB4;
00130             conversion_time_ = 0.135;
00131             break;
00132         case 8: // ultra high resolution
00133             oss_bit_ = 3;
00134             oversampling_setting_ = 0xF4;
00135             conversion_time_ = 0.255;
00136             break;
00137         default: // standard
00138             oss_bit_ = 1;
00139             oversampling_setting_ = 0x74;
00140             conversion_time_ = 0.075;
00141     }
00142 }
00143 
00144 void BMP085::write_char(char address, char data)
00145 {
00146     char cmd[2];
00147     cmd[0] = address;
00148     cmd[1] = data;
00149     i2c_.write( I2C_ADDRESS , cmd, 2);
00150 }
00151 
00152 int16_t BMP085::read_int16(char address)
00153 {
00154     char tx[2];
00155     tx[0] = address;
00156     i2c_.write(I2C_ADDRESS, tx, 1);
00157     i2c_.read(I2C_ADDRESS, tx, 2);
00158     int16_t value = ((tx[0] << 8) | tx[1]);
00159     return value;
00160 }
00161 
00162 void BMP085::read_multiple(char address, char* buffer, int bits)
00163 {
00164     char cmd[2];
00165     cmd[0] = address;
00166     i2c_.write(I2C_ADDRESS, cmd, 1);
00167     i2c_.read(I2C_ADDRESS, buffer, bits);
00168 }
00169 
00170 uint16_t BMP085::read_uint16(char address)
00171 {
00172     char tx[2];
00173     tx[0] = address;
00174     i2c_.write(I2C_ADDRESS, tx, 1);
00175     i2c_.read(I2C_ADDRESS, tx, 2);
00176     uint16_t value = ((tx[0] << 8) | tx[1]);
00177     return value;
00178 }
00179 
00180 int32_t BMP085::get_temperature()
00181 {
00182     get_ut(); // uncompressed temperature
00183     get_up(); // uncompressed pressure
00184     
00185     long x1,x2;
00186 
00187     //Start temperature calculation
00188     x1 = ((UT - AC6) * AC5) >> 15;
00189     x2 = (MC << 11) / (x1 + MD);
00190     B5 = x1 + x2;
00191     temperature = ((B5 + 8) >> 4);
00192     return temperature;
00193 }
00194 
00195 int32_t BMP085::get_pressure()
00196 {
00197     get_up(); // get uncompressed pressure (uncompressed temperature must be called recently)
00198 
00199     B6 = B5 - 4000;
00200     X1 = (B2 * ((B6 * B6) >> 12)) >> 11;
00201     X2 = (AC2 * B6) >> 11;
00202     X3 = X1 + X2;
00203     B3 = ((((((long)(AC1) * 4) + X3) << oss_bit_) + 2) >> 2);
00204     X1 = (AC3 * B6) >> 13;
00205     X2 = (B1 * ((B6 * B6) >> 12)) >> 16;
00206     X3 = ((X1 + X2) + 2) >> 2;
00207     B4 = (AC4 * (unsigned long)(X3 + 32768)) >> 15;
00208     B7 = ((unsigned long)(UP - B3) * (50000 >> oss_bit_));
00209     if (B7 < 0x80000000)
00210         pressure = (B7 << 1) / B4;
00211     else
00212         pressure = (B7 / B4) << 1;
00213 
00214     X1 = (pressure >> 8);
00215     X1 *= X1;
00216     X1 = (X1 * 3038) >>16;
00217     X2 = (-7357 * pressure) >>16;
00218     pressure += (X1 + X2 + 3791)>>4;
00219     
00220     return pressure;
00221 }
00222 
00223 double BMP085::get_altitude_m()
00224 {
00225     const double P0 = 1013.25; //pressure at sea level in hPa
00226     double pres_hpa = pressure / 100.0;
00227     altitude = 44330.0 * (1.0 - pow((pres_hpa/P0), 0.190295));
00228     return altitude;
00229 }
00230 
00231 double BMP085::get_altitude_ft()
00232 {
00233     return get_altitude_m()*3.28084;
00234 }