Lib for HP03SA atmospheric pressure sensor. Provides pressure, temperature and altitude data.

Dependents:   mbed_HP03SA_LM77

Committer:
wim
Date:
Sat Jan 10 19:10:17 2015 +0000
Revision:
0:61bbd81782de
First version of HP03SA library.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
wim 0:61bbd81782de 1 /* mbed HP03SA Library, for an I2C Pressure and Temperature sensor which provides derived Altitude values
wim 0:61bbd81782de 2 * Copyright (c) 2015, v01: WH, Initial version, ported in part from Elektor weatherstation (Sept 2011), Author: W. Waetzig
wim 0:61bbd81782de 3 * See http://www.elektor-labs.com/project/usb-long-term-weather-logger-100888.12037.html
wim 0:61bbd81782de 4 * Code also based on several other public sources:
wim 0:61bbd81782de 5 * See http://en.wikipedia.org/wiki/Atmospheric_pressure
wim 0:61bbd81782de 6 * See https://learn.sparkfun.com/tutorials/bmp180-barometric-pressure-sensor-hookup-?_ga=1.94307604.888266135.1310146152
wim 0:61bbd81782de 7 *
wim 0:61bbd81782de 8 *
wim 0:61bbd81782de 9 * Permission is hereby granted, free of charge, to any person obtaining a copy
wim 0:61bbd81782de 10 * of this software and associated documentation files (the "Software"), to deal
wim 0:61bbd81782de 11 * in the Software without restriction, including without limitation the rights
wim 0:61bbd81782de 12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
wim 0:61bbd81782de 13 * copies of the Software, and to permit persons to whom the Software is
wim 0:61bbd81782de 14 * furnished to do so, subject to the following conditions:
wim 0:61bbd81782de 15 *
wim 0:61bbd81782de 16 * The above copyright notice and this permission notice shall be included in
wim 0:61bbd81782de 17 * all copies or substantial portions of the Software.
wim 0:61bbd81782de 18 *
wim 0:61bbd81782de 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
wim 0:61bbd81782de 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
wim 0:61bbd81782de 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
wim 0:61bbd81782de 22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
wim 0:61bbd81782de 23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
wim 0:61bbd81782de 24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
wim 0:61bbd81782de 25 * THE SOFTWARE.
wim 0:61bbd81782de 26 */
wim 0:61bbd81782de 27
wim 0:61bbd81782de 28 #include "mbed.h"
wim 0:61bbd81782de 29 #include "HP03SA.h"
wim 0:61bbd81782de 30
wim 0:61bbd81782de 31 /** Create an HP03SA interface for mbed pins
wim 0:61bbd81782de 32 *
wim 0:61bbd81782de 33 * @param i2c I2C Bus
wim 0:61bbd81782de 34 * @param XCLR Clock enable control line
wim 0:61bbd81782de 35 */
wim 0:61bbd81782de 36 HP03SA::HP03SA(I2C *i2c, PinName XCLR) : _i2c(i2c), _xclr(XCLR) {
wim 0:61bbd81782de 37
wim 0:61bbd81782de 38 _init();
wim 0:61bbd81782de 39 }
wim 0:61bbd81782de 40
wim 0:61bbd81782de 41 /** Init the HP03SA
wim 0:61bbd81782de 42 *
wim 0:61bbd81782de 43 */
wim 0:61bbd81782de 44 void HP03SA::_init() {
wim 0:61bbd81782de 45 char buffer[18];
wim 0:61bbd81782de 46
wim 0:61bbd81782de 47 //HP03S initialization
wim 0:61bbd81782de 48
wim 0:61bbd81782de 49 _xclr=0; //XCLR low for coefficients readout
wim 0:61bbd81782de 50
wim 0:61bbd81782de 51 // Select C1 register
wim 0:61bbd81782de 52 buffer[0] = 0x10; // Register address for _C1 MSB is 0x10
wim 0:61bbd81782de 53 _i2c->write(HP03SA_EEPROM_SA, buffer, 1, true); // Repeated Start
wim 0:61bbd81782de 54 // Read calibration parameters
wim 0:61bbd81782de 55 _i2c->read(HP03SA_EEPROM_SA, buffer, 18);
wim 0:61bbd81782de 56
wim 0:61bbd81782de 57 _C1 = (buffer[0] << 8) | buffer[1]; // _C1 MSB, LSB
wim 0:61bbd81782de 58 _C2 = (buffer[2] << 8) | buffer[3]; // _C2 MSB, LSB
wim 0:61bbd81782de 59 _C3 = (buffer[4] << 8) | buffer[5]; // _C3 MSB, LSB
wim 0:61bbd81782de 60 _C4 = (buffer[6] << 8) | buffer[7]; // _C4 MSB, LSB
wim 0:61bbd81782de 61 _C5 = (buffer[8] << 8) | buffer[9]; // _C5 MSB, LSB
wim 0:61bbd81782de 62 _C6 = (buffer[10] << 8) | buffer[11]; // _C6 MSB, LSB
wim 0:61bbd81782de 63 _C7 = (buffer[12] << 8) | buffer[13]; // _C7 MSB, LSB
wim 0:61bbd81782de 64 _A = buffer[14]; // _A
wim 0:61bbd81782de 65 _B = buffer[15]; // _B
wim 0:61bbd81782de 66 _C = buffer[16]; // _C
wim 0:61bbd81782de 67 _D = buffer[17]; // _D
wim 0:61bbd81782de 68
wim 0:61bbd81782de 69 _pres_base_x10 = PBASE_X10;
wim 0:61bbd81782de 70 _temp_base_x10 = TBASE_X10;
wim 0:61bbd81782de 71
wim 0:61bbd81782de 72 // Execute Dummy reads after init()
wim 0:61bbd81782de 73 sample();
wim 0:61bbd81782de 74 sample();
wim 0:61bbd81782de 75 }
wim 0:61bbd81782de 76
wim 0:61bbd81782de 77 /** Read ADC value (either pressure or temperature depending on Control Register setting)
wim 0:61bbd81782de 78 *
wim 0:61bbd81782de 79 * @return int pressure or temperature
wim 0:61bbd81782de 80 */
wim 0:61bbd81782de 81 int HP03SA::_readADC (void) {
wim 0:61bbd81782de 82 char buffer[2];
wim 0:61bbd81782de 83
wim 0:61bbd81782de 84 // Select ADC register
wim 0:61bbd81782de 85 buffer[0] = 0xFD; // Register address for ADC
wim 0:61bbd81782de 86 _i2c->write(HP03SA_BARO_SA, buffer, 1, true); // Repeated Start
wim 0:61bbd81782de 87 // Read ADC
wim 0:61bbd81782de 88 _i2c->read(HP03SA_BARO_SA, buffer, 2);
wim 0:61bbd81782de 89
wim 0:61bbd81782de 90 return ((buffer[0] << 8) | buffer[1]); // MSB, LSB
wim 0:61bbd81782de 91 }
wim 0:61bbd81782de 92
wim 0:61bbd81782de 93 /** Read Pressure and Temperature
wim 0:61bbd81782de 94 *
wim 0:61bbd81782de 95 * @return none
wim 0:61bbd81782de 96 */
wim 0:61bbd81782de 97 void HP03SA::_readTempPres(void) {
wim 0:61bbd81782de 98 char buffer[2];
wim 0:61bbd81782de 99
wim 0:61bbd81782de 100 _xclr=1; // ADC-XCLR
wim 0:61bbd81782de 101
wim 0:61bbd81782de 102 // Read ADC with pressure value
wim 0:61bbd81782de 103 buffer[0] = 0xFF; // Control Register address
wim 0:61bbd81782de 104 buffer[1] = 0xF0; // function = select + start-conversion PRES
wim 0:61bbd81782de 105 _i2c->write(HP03SA_BARO_SA, buffer, 2);
wim 0:61bbd81782de 106 wait_ms(40); // delay for ADC-conversion
wim 0:61bbd81782de 107 _D1 = _readADC();
wim 0:61bbd81782de 108
wim 0:61bbd81782de 109 // Read ADC with temperature value
wim 0:61bbd81782de 110 buffer[0] = 0xFF; // Control Register address
wim 0:61bbd81782de 111 buffer[1] = 0xE8; // function = select + start-conversion TEMP
wim 0:61bbd81782de 112 _i2c->write(HP03SA_BARO_SA, buffer, 2);
wim 0:61bbd81782de 113 wait_ms(40); // delay for ADC-conversion
wim 0:61bbd81782de 114 _D2 = _readADC();
wim 0:61bbd81782de 115
wim 0:61bbd81782de 116 _xclr=0; // ADC-XCLR
wim 0:61bbd81782de 117 }
wim 0:61bbd81782de 118
wim 0:61bbd81782de 119 /** Calculate Pressure and Temperature
wim 0:61bbd81782de 120 *
wim 0:61bbd81782de 121 * @return none
wim 0:61bbd81782de 122 */
wim 0:61bbd81782de 123 void HP03SA::_calcTempPres(void) {
wim 0:61bbd81782de 124 long int _D2_C5;
wim 0:61bbd81782de 125 int _corr;
wim 0:61bbd81782de 126
wim 0:61bbd81782de 127 // Temperature and Pressure calculations from HP03S datasheet version 1.3
wim 0:61bbd81782de 128 // with 2nd-order corrections using the parameters _A, _B, _C, _D
wim 0:61bbd81782de 129 // Measured values are: _D1(pressure) and _D2(temperature)
wim 0:61bbd81782de 130 // Correct offset-calculation (_off)
wim 0:61bbd81782de 131
wim 0:61bbd81782de 132 _D2_C5 = _D2 - _C5;
wim 0:61bbd81782de 133 if (_D2_C5 >= 0)
wim 0:61bbd81782de 134 _corr = _A; // _A
wim 0:61bbd81782de 135 else
wim 0:61bbd81782de 136 _corr = _B; // _B
wim 0:61bbd81782de 137
wim 0:61bbd81782de 138 _dUT = _D2_C5 - ((_D2_C5 >> 7) * (_D2_C5 >> 7) * (_corr >> _C)); // _C
wim 0:61bbd81782de 139
wim 0:61bbd81782de 140 // _off = ( (_C4 - 1024) * _dUT / 16384 + _C2 ) * 4;
wim 0:61bbd81782de 141 // _off = ((( (_C4 - 1024) * _dUT ) >> 14 ) + _C2 ) << 2;
wim 0:61bbd81782de 142 _off = ((( (_C4 - 1024) * _dUT ) >> 14 ) + _C2 ) << 2;
wim 0:61bbd81782de 143
wim 0:61bbd81782de 144 // _sens = _C3 * _dUT / 1024 + _C1 ;
wim 0:61bbd81782de 145 _sens = (( _C3 * _dUT ) >> 10 ) + _C1 ;
wim 0:61bbd81782de 146
wim 0:61bbd81782de 147 // _x = (_D1 - 7168) * _sens / 16384 - _off;
wim 0:61bbd81782de 148 _x = (((_D1 - 7168) * _sens ) >> 14 ) - _off;
wim 0:61bbd81782de 149
wim 0:61bbd81782de 150 // _pres = x * 10 / 32 + _C7;
wim 0:61bbd81782de 151 _pres_x10 = (( _x * 10 ) >> 5 ) + _C7; // Pressure in hPa x 10
wim 0:61bbd81782de 152
wim 0:61bbd81782de 153 // _temp = _dUT * _C6 / 65536 + 250;
wim 0:61bbd81782de 154 _temp_x10 = (( _dUT * _C6 ) >> 16 ) - (_dUT >> _D) + 250; // _D, Temp in Celsius x 10
wim 0:61bbd81782de 155 }
wim 0:61bbd81782de 156
wim 0:61bbd81782de 157
wim 0:61bbd81782de 158 /** Calculate Altitude
wim 0:61bbd81782de 159 *
wim 0:61bbd81782de 160 * @return none
wim 0:61bbd81782de 161 */
wim 0:61bbd81782de 162 void HP03SA::_calcAlt(void) {
wim 0:61bbd81782de 163 // Calculation based on ISA model
wim 0:61bbd81782de 164 // http://en.wikipedia.org/wiki/Atmospheric_pressure
wim 0:61bbd81782de 165 //
wim 0:61bbd81782de 166 // h = (1 - pow((P/Pref), RL/gM)) * Tref / L
wim 0:61bbd81782de 167 //
wim 0:61bbd81782de 168 // h altitude above Mean Sea Level in m
wim 0:61bbd81782de 169 // P atmospheric pressure at altitude h
wim 0:61bbd81782de 170 // Pref sea level standard atmospheric pressure 101325 Pa
wim 0:61bbd81782de 171 // L temperature lapse rate, = g/cp for dry air 0.0065 K/m
wim 0:61bbd81782de 172 // Tref sea level standard temperature 288.15 K (= 15.0 + 273.15)
wim 0:61bbd81782de 173 // g Earth-surface gravitational acceleration 9.80665 m/s2
wim 0:61bbd81782de 174 // M molar mass of dry air 0.0289644 kg/mol
wim 0:61bbd81782de 175 // R universal gas constant 8.31447 J/(mol•K)
wim 0:61bbd81782de 176 // RL/gM 0.19026674
wim 0:61bbd81782de 177 // gM/RL 5.25578009f
wim 0:61bbd81782de 178
wim 0:61bbd81782de 179 //ISA calculation
wim 0:61bbd81782de 180 // _alt = 44330.76923f * (1.0f - pow( ((float) _pres_x10 / _pres_base_x10), RLGM));
wim 0:61bbd81782de 181 _alt = (TBASE_X10 / LBASE_X10) * (1.0f - pow( ((float) _pres_x10 / _pres_base_x10), RLGM));
wim 0:61bbd81782de 182
wim 0:61bbd81782de 183 //Correction for temperature
wim 0:61bbd81782de 184 // _temp_base_x10 = TBASE_X10 - ( (float) _alt * LBASE_X10 );
wim 0:61bbd81782de 185 // _temp_base_x10 = TBASE_X10;
wim 0:61bbd81782de 186
wim 0:61bbd81782de 187 _alt = (float) _alt * ((float)_temp_x10 + 2731.5f) / _temp_base_x10;
wim 0:61bbd81782de 188 }
wim 0:61bbd81782de 189
wim 0:61bbd81782de 190 /** Get Pressure and Temperature sample
wim 0:61bbd81782de 191 *
wim 0:61bbd81782de 192 * @return none
wim 0:61bbd81782de 193 */
wim 0:61bbd81782de 194 void HP03SA::sample(void) {
wim 0:61bbd81782de 195 _readTempPres();
wim 0:61bbd81782de 196 _calcTempPres();
wim 0:61bbd81782de 197 _calcAlt();
wim 0:61bbd81782de 198 }
wim 0:61bbd81782de 199
wim 0:61bbd81782de 200 /** Get Absolute Atmospheric Pressure in hPa x 10
wim 0:61bbd81782de 201 * Note: sample() must be called before getAtmPressure()
wim 0:61bbd81782de 202 * Checked using http://luchtdruk.com/luchtdruk-in-nederland.html
wim 0:61bbd81782de 203 *
wim 0:61bbd81782de 204 * @return int Pressure in hPa x 10
wim 0:61bbd81782de 205 */
wim 0:61bbd81782de 206 int HP03SA::getAbsPressure(void) {
wim 0:61bbd81782de 207 return _pres_x10;
wim 0:61bbd81782de 208 }
wim 0:61bbd81782de 209
wim 0:61bbd81782de 210 /** Get Sealevel Atmospheric Pressure in hPa x 10
wim 0:61bbd81782de 211 * This produces pressure readings that can be used for weather measurements.
wim 0:61bbd81782de 212 * Note: sample() must be called before getSeaPressure()
wim 0:61bbd81782de 213 *
wim 0:61bbd81782de 214 * @param int alt_meter Altitude above Mean Sea Level where measurement is taken
wim 0:61bbd81782de 215 * @return int Pressure at sea level in hPa x 10
wim 0:61bbd81782de 216 */
wim 0:61bbd81782de 217 int HP03SA::getSeaPressure(int alt_meter) {
wim 0:61bbd81782de 218 // return ( (float) _pres_x10 / pow (1.0f - ((float) alt_meter / 44330.0), 5.255) );
wim 0:61bbd81782de 219 return ( (float) _pres_x10 / pow (1.0f - ((float) alt_meter * LBASE_X10 / TBASE_X10), GMRL) );
wim 0:61bbd81782de 220 }
wim 0:61bbd81782de 221
wim 0:61bbd81782de 222 /** Get Temperature as int in °Celsius x 10
wim 0:61bbd81782de 223 * Note: sample() must be called before getTemperature()
wim 0:61bbd81782de 224 *
wim 0:61bbd81782de 225 * @return int Temperature in °Celsius x 10
wim 0:61bbd81782de 226 */
wim 0:61bbd81782de 227 int HP03SA::getTemperatureInt(void) {
wim 0:61bbd81782de 228 return _temp_x10;
wim 0:61bbd81782de 229 }
wim 0:61bbd81782de 230
wim 0:61bbd81782de 231 /** Get Temperature as float in °Celsius
wim 0:61bbd81782de 232 * Note: sample() must be called before getTemperature()
wim 0:61bbd81782de 233 *
wim 0:61bbd81782de 234 * @return float Temperature in °Celsius
wim 0:61bbd81782de 235 */
wim 0:61bbd81782de 236 float HP03SA::getTemperature(void) {
wim 0:61bbd81782de 237 return (float) _temp_x10 / 10.0f;
wim 0:61bbd81782de 238 }
wim 0:61bbd81782de 239
wim 0:61bbd81782de 240
wim 0:61bbd81782de 241 /** Convert Temperature from °Celsius into °Fahrenheit
wim 0:61bbd81782de 242 *
wim 0:61bbd81782de 243 * @param float celsius in °Celsius
wim 0:61bbd81782de 244 * @return float temperature in °Fahrenheit
wim 0:61bbd81782de 245 */
wim 0:61bbd81782de 246 float HP03SA::celsiusToFahrenheit(float celsius) {
wim 0:61bbd81782de 247
wim 0:61bbd81782de 248 return ((celsius * 9.0f) / 5.0f) + 32.0f; // Convert to Fahrenheit
wim 0:61bbd81782de 249 }
wim 0:61bbd81782de 250
wim 0:61bbd81782de 251
wim 0:61bbd81782de 252 /** Get Altitude in meters using ISA
wim 0:61bbd81782de 253 * Note: sample() must be called before getAltitude()
wim 0:61bbd81782de 254 *
wim 0:61bbd81782de 255 * @return int Altitude in meters above Mean Sea Level (MSL)
wim 0:61bbd81782de 256 */
wim 0:61bbd81782de 257 int HP03SA::getAltitude(void) {
wim 0:61bbd81782de 258 return _alt;
wim 0:61bbd81782de 259 }
wim 0:61bbd81782de 260
wim 0:61bbd81782de 261 /** Get Altitude in feet using ISA
wim 0:61bbd81782de 262 * Note: sample() must be called before getAltitudeFt()
wim 0:61bbd81782de 263 *
wim 0:61bbd81782de 264 * @return int Altitude in feet above Mean Sea Level (MSL)
wim 0:61bbd81782de 265 */
wim 0:61bbd81782de 266 int HP03SA::getAltitudeFt() {
wim 0:61bbd81782de 267 return (float)_alt * 3.28084f;
wim 0:61bbd81782de 268 }
wim 0:61bbd81782de 269
wim 0:61bbd81782de 270 /** Get Status
wim 0:61bbd81782de 271 *
wim 0:61bbd81782de 272 * @return bool Sensor ready
wim 0:61bbd81782de 273 */
wim 0:61bbd81782de 274 bool HP03SA::getStatus(void) {
wim 0:61bbd81782de 275 char buffer[2];
wim 0:61bbd81782de 276 int status;
wim 0:61bbd81782de 277
wim 0:61bbd81782de 278 _xclr=1; // ADC-XCLR
wim 0:61bbd81782de 279
wim 0:61bbd81782de 280 // Read ADC with pressure value (dummy operation to check status)
wim 0:61bbd81782de 281 buffer[0] = 0xFF; // Control Register address
wim 0:61bbd81782de 282 status=_i2c->write(HP03SA_BARO_SA, buffer, 1);
wim 0:61bbd81782de 283
wim 0:61bbd81782de 284 _xclr=0; // ADC-XCLR
wim 0:61bbd81782de 285
wim 0:61bbd81782de 286 return (status==0); // True when device found
wim 0:61bbd81782de 287 }
wim 0:61bbd81782de 288
wim 0:61bbd81782de 289 /** Set QNH Pressure to calibrate sensor
wim 0:61bbd81782de 290 *
wim 0:61bbd81782de 291 * @param int pressure_x10 at Mean Sea Level in hPa x 10
wim 0:61bbd81782de 292 * The getAltitude() reading will be 0 m for the set pressure.
wim 0:61bbd81782de 293 */
wim 0:61bbd81782de 294 void HP03SA::setPressure(int pressure_x10) {
wim 0:61bbd81782de 295 _pres_base_x10 = (float) pressure_x10;
wim 0:61bbd81782de 296 }
wim 0:61bbd81782de 297
wim 0:61bbd81782de 298 /** Set QNH Altitude in meter to calibrate sensor
wim 0:61bbd81782de 299 *
wim 0:61bbd81782de 300 * @param int alt_meter Altitude in meters above Mean Sea Level (MSL) for current pressure
wim 0:61bbd81782de 301 * The getAltitude() reading will be 'alt_meter' m for the current pressure.
wim 0:61bbd81782de 302 */
wim 0:61bbd81782de 303 void HP03SA::setAltitude(int alt_meter) {
wim 0:61bbd81782de 304
wim 0:61bbd81782de 305 // Compute _temp_base derived from the temp at set altitude and temp lapse
wim 0:61bbd81782de 306 // _temp_base_x10 = ((float) _temp_x10 + 2731.5f) + ((float) alt * LBASE_X10);
wim 0:61bbd81782de 307
wim 0:61bbd81782de 308 // Compute pressure at Mean Sea Level from the pressure at the set altitude
wim 0:61bbd81782de 309 _pres_base_x10 = (float) _pres_x10 * pow( TBASE_X10 / (TBASE_X10 - ((float) alt_meter * LBASE_X10)), GMRL);
wim 0:61bbd81782de 310 }
wim 0:61bbd81782de 311
wim 0:61bbd81782de 312 /** Set QNH Altitude in feet to calibrate sensor
wim 0:61bbd81782de 313 *
wim 0:61bbd81782de 314 * @param int alt_feet Altitude in meters above Mean Sea Level (MSL) for current pressure
wim 0:61bbd81782de 315 * The getAltitudeFt() reading will be 'alt_feet' ft for the current pressure.
wim 0:61bbd81782de 316 */
wim 0:61bbd81782de 317 void HP03SA::setAltitudeFt(int alt_feet){
wim 0:61bbd81782de 318 setAltitude(alt_feet / 3.28084f);
wim 0:61bbd81782de 319 }
wim 0:61bbd81782de 320
wim 0:61bbd81782de 321