//************************************************ // BMP085 Barometric Pressure Sensor // // - Datasheet: http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP085-DS000-05.pdf // // - Written in CCS PCH C using floating point math // - Several integer math versions of this driver exist but the speed improvement is // not warranted in typical weather station type applications // // - Based on a paper posted to thebackshed.com by DuinoMiteMegaAn // http://www.thebackshed.com/forum/forum_posts.asp?TID=4768&PN=9 // // - Usage: // Call once: bmp085Calibration(); // P_mBar_float = BMP085Pressure(true); // calls for temperature first // P_mBar_float = BMP085Pressure(false); // skips temperature reading, assumes done previously // T_Cent_float = BMP085Temperature(); // t_reading = _Temp; _Temp set on every temperature reading // Note: pressure reading is temp compensated so call for temp reading prior to pressure reading periodically or on each reading // // Al Testani // 08/17/12 //************************************************ // place a #use i2c statement in the main program and comment this out if not applicable //#use i2c(master, sda=PIN_C4, scl=PIN_C3, FAST, FORCE_HW) #use i2c( Master, Fast, sda=SDAPort, scl=SCLPort, force_hw) #include const int8 OVS_S = 3; // Oversampling Setting (0,1,2,3 from ultra low power, to ultra hi-resolution) #define BMP085_ADDRESS 0xEE // I2C address of BMP085 #define P_CORRECTION 1.5 // in mBars - factor to adjust for elevation to match local weather station pressure // this value for 14' above sea level (in Boca Raton, Florida) // Calibration values signed int16 ac1; signed int16 ac2; signed int16 ac3; int16 ac4; int16 ac5; int16 ac6; signed int16 b1; signed int16 b2; signed int16 mb; signed int16 mc; signed int16 md; // floating point cal factors float _c3; float _c4; float _b1; float _c5; float _c6; float _mc; float _md; // polynomomial constants float _x0; float _x1; float _x2; float _y0; float _y1; float _y2; float _p0; float _p1; float _p2; float _s; // T-25, used in pressure calculation - must run temperature reading before pressure reading float _Temp; // set after every temperature or temperature/pressure reading int8 BMP085ReadByte(int8 address) { int8 data; i2c_start(); i2c_write(BMP085_ADDRESS); i2c_write(address); i2c_start(); i2c_write(BMP085_ADDRESS | 0x01 ); data=i2c_read(0); i2c_stop(); return(data); } int16 BMP085ReadInt(int8 address) { int8 msb, lsb; int16 temp; i2c_start(); i2c_write(BMP085_ADDRESS); i2c_write(address); i2c_start(); i2c_write(BMP085_ADDRESS | 0x01 ); msb = i2c_read(); lsb = i2c_read(0); i2c_stop(); temp = make16(msb, lsb); return ( temp ); } void BMP085WriteByte(int8 address, int8 data) { i2c_start(); i2c_write(BMP085_ADDRESS); i2c_write(address); i2c_write(data); i2c_stop(); } void bmp085Calibration() { // read BMP085 EEPROM cal factors ac1 = bmp085ReadInt(0xAA); ac2 = bmp085ReadInt(0xAC); ac3 = bmp085ReadInt(0xAE); ac4 = bmp085ReadInt(0xB0); ac5 = bmp085ReadInt(0xB2); ac6 = bmp085ReadInt(0xB4); b1 = bmp085ReadInt(0xB6); b2 = bmp085ReadInt(0xB8); mb = bmp085ReadInt(0xBA); mc = bmp085ReadInt(0xBC); md = bmp085ReadInt(0xBE); ac1 = bmp085ReadInt(0xAA); // calculate floating point cal factors _c3 = 0.0048828125 * ac3; // 160 * pow2(-15) * ac3; _c4 = 0.000000030517578125 * ac4; // 1E-3 * pow2(-15) * ac4; _c5 = 0.00000019073486328125 * ac5; // (pow2(-15)/160) * ac5; _c6 = (float)ac6; _b1 = 0.00002384185791015625 * b1; // 25600 * pow2(-30) * b1; _mc = 0.08 * mc; // (pow2(11) / 25600) * mc; _md = (float)md / 160; // calculate polynomial constants _x0 = (float)ac1; _x1 = 0.01953125 * ac2; // 160 * pow2(-13) * ac2; _x2 = 0.000762939453125 * b2; // 25600 * pow2(-25) * b2; _y0 = _c4 * 32768; //_c4 * pow2(15); _y1 = _c4 * _c3; _y2 = _c4 * _b1; _p0 = 2.364375; _p1 = 0.992984; _p2 = 0.000004421; } // Read the uncompensated temperature value //---------------------------------------------- int16 BMP085ReadUT() { int16 ut; // Write 0x2E into Register 0xF4 BMP085WriteByte(0xF4, 0x2E); delay_ms(5); // Wait at least 4.5ms // Read two bytes from registers 0xF6 and 0xF7 ut = BMP085ReadInt(0xF6); return((float)ut); } // Read the uncompensated pressure value //---------------------------------------------- int32 bmp085ReadUP() { int8 msb, lsb, xlsb; float p; // Write 0x34+(OSS<<6) into register 0xF4 // Request a pressure reading w/ oversampling setting BMP085WriteByte(0xF4, (0x34 + (OVS_S<<6)) ); // Wait for conversion, delay time dependent on OSS switch (OVS_S) { case 0: delay_ms(5); break; case 1: delay_ms(8); break; case 2: delay_ms(14); break; case 3: delay_ms(26); break; } // Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB) msb = BMP085ReadByte(0xF6); lsb = BMP085ReadByte(0xF7); xlsb = BMP085ReadByte(0xF8); p = (256*msb) + lsb + (xlsb/256); return(p); } float BMP085GetTemp(float _tu) { float alpha, T; alpha = _c5 * (_tu - _c6); T = alpha + (_mc/(alpha + _md)); _s = T - 25; return(T); } float BMP085GetPressure(float _pu) { float x, y, z; float P; x = _x2*_s*_s + _x1*_s + _x0; y = _y2*_s*_s + _y1*_s + _y0; z = ((float)_pu - x) / y; P = _p2*z*z + _p1*z + _p0; P += P_CORRECTION; return(P); } float BMP085Pressure(boolean getTemp) { if (getTemp) _Temp = BMP085GetTemp(BMP085ReadUT()); // creates _s required for pressure calculation return(BMP085GetPressure(BMP085ReadUP())); } float BMP085Temperature(void) { _Temp = BMP085GetTemp(BMP085ReadUT()); return(_Temp); } float BMP085pressureToAltitude(float seaLevel, float atmospheric) { // Equation taken from BMP180 datasheet (page 16): // http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf // Note that using the equation from wikipedia can give bad results // at high altitude. See this thread for more information: // http://forums.adafruit.com/viewtopic.php?f=22&t=58064 return 44330.0 * (1.0 - pow(atmospheric / seaLevel, 0.1903)); //return 44330.0 * (1.0 - (atmospheric / seaLevel)); }