Wim Huiskamp / HP03SA

Dependents:   mbed_HP03SA_LM77

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HP03SA.cpp Source File

HP03SA.cpp

00001 /* mbed HP03SA Library, for an I2C Pressure and Temperature sensor which provides derived Altitude values
00002  * Copyright (c) 2015, v01: WH, Initial version, ported in part from Elektor weatherstation (Sept 2011), Author: W. Waetzig
00003  *                          See http://www.elektor-labs.com/project/usb-long-term-weather-logger-100888.12037.html
00004  *                          Code also based on several other public sources:   
00005  *                          See http://en.wikipedia.org/wiki/Atmospheric_pressure
00006  *                          See https://learn.sparkfun.com/tutorials/bmp180-barometric-pressure-sensor-hookup-?_ga=1.94307604.888266135.1310146152
00007  *
00008  *
00009  * Permission is hereby granted, free of charge, to any person obtaining a copy
00010  * of this software and associated documentation files (the "Software"), to deal
00011  * in the Software without restriction, including without limitation the rights
00012  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00013  * copies of the Software, and to permit persons to whom the Software is
00014  * furnished to do so, subject to the following conditions:
00015  *
00016  * The above copyright notice and this permission notice shall be included in
00017  * all copies or substantial portions of the Software.
00018  *
00019  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00020  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00021  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00022  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00023  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00024  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00025  * THE SOFTWARE.
00026  */
00027 
00028 #include "mbed.h"
00029 #include "HP03SA.h"
00030 
00031 /** Create an HP03SA interface for mbed pins
00032   *
00033   * @param i2c    I2C Bus 
00034   * @param XCLR   Clock enable control line
00035   */ 
00036 HP03SA::HP03SA(I2C *i2c, PinName XCLR) : _i2c(i2c), _xclr(XCLR) {
00037 
00038   _init();
00039 }
00040 
00041 /**  Init the HP03SA
00042   *  
00043   */
00044 void HP03SA::_init() {
00045   char buffer[18];
00046 
00047   //HP03S initialization
00048 
00049   _xclr=0;   //XCLR low for coefficients readout
00050       
00051   // Select C1 register
00052   buffer[0] = 0x10;                                // Register address for _C1 MSB is 0x10
00053   _i2c->write(HP03SA_EEPROM_SA, buffer, 1, true);  // Repeated Start
00054   // Read calibration parameters
00055   _i2c->read(HP03SA_EEPROM_SA, buffer, 18);   
00056   
00057   _C1 = (buffer[0] << 8)  | buffer[1];  // _C1 MSB, LSB
00058   _C2 = (buffer[2] << 8)  | buffer[3];  // _C2 MSB, LSB
00059   _C3 = (buffer[4] << 8)  | buffer[5];  // _C3 MSB, LSB
00060   _C4 = (buffer[6] << 8)  | buffer[7];  // _C4 MSB, LSB
00061   _C5 = (buffer[8] << 8)  | buffer[9];  // _C5 MSB, LSB
00062   _C6 = (buffer[10] << 8) | buffer[11]; // _C6 MSB, LSB
00063   _C7 = (buffer[12] << 8) | buffer[13]; // _C7 MSB, LSB
00064   _A  =  buffer[14];                    // _A 
00065   _B  =  buffer[15];                    // _B 
00066   _C  =  buffer[16];                    // _C 
00067   _D  =  buffer[17];                    // _D               
00068 
00069   _pres_base_x10 = PBASE_X10;
00070   _temp_base_x10 = TBASE_X10;
00071 
00072   // Execute Dummy reads after init()
00073   sample();
00074   sample();   
00075 }  
00076 
00077 /** Read ADC value (either pressure or temperature depending on Control Register setting)
00078   *
00079   * @return int   pressure or temperature 
00080   */ 
00081 int HP03SA::_readADC (void) {
00082     char buffer[2];
00083 
00084     // Select ADC register
00085     buffer[0] = 0xFD;                              // Register address for ADC
00086     _i2c->write(HP03SA_BARO_SA, buffer, 1, true);  // Repeated Start
00087     // Read ADC
00088     _i2c->read(HP03SA_BARO_SA, buffer, 2);   
00089 
00090     return ((buffer[0] << 8) | buffer[1]);         // MSB, LSB
00091 }
00092 
00093 /** Read Pressure and Temperature
00094   *
00095   * @return none 
00096   */ 
00097 void HP03SA::_readTempPres(void) {
00098     char buffer[2];    
00099     
00100     _xclr=1;   // ADC-XCLR
00101     
00102     // Read ADC with pressure value
00103     buffer[0] = 0xFF;             // Control Register address  
00104     buffer[1] = 0xF0;             // function = select + start-conversion PRES
00105     _i2c->write(HP03SA_BARO_SA, buffer, 2);
00106     wait_ms(40);                  // delay for ADC-conversion
00107     _D1  = _readADC();
00108 
00109     // Read ADC with temperature value
00110     buffer[0] = 0xFF;             // Control Register address
00111     buffer[1] = 0xE8;             // function = select + start-conversion TEMP
00112     _i2c->write(HP03SA_BARO_SA, buffer, 2);
00113     wait_ms(40);                  // delay for ADC-conversion
00114     _D2  = _readADC();
00115 
00116     _xclr=0;   // ADC-XCLR                 
00117 }
00118 
00119 /** Calculate Pressure and Temperature
00120   *
00121   * @return none 
00122   */ 
00123 void HP03SA::_calcTempPres(void) {
00124     long int _D2_C5;
00125     int _corr;    
00126 
00127     // Temperature and Pressure calculations from HP03S datasheet version 1.3
00128     // with 2nd-order corrections using the parameters _A, _B, _C, _D
00129     // Measured values are: _D1(pressure) and _D2(temperature)
00130     // Correct offset-calculation (_off)
00131 
00132     _D2_C5 = _D2 - _C5;
00133     if (_D2_C5 >= 0) 
00134         _corr = _A;     // _A
00135     else
00136         _corr = _B;     // _B
00137 
00138     _dUT = _D2_C5 - ((_D2_C5 >> 7) * (_D2_C5 >> 7) * (_corr >> _C)); // _C
00139 
00140 //  _off = (   (_C4 - 1024) * _dUT / 16384 + _C2 ) * 4;
00141 //  _off = ((( (_C4 - 1024) * _dUT ) >> 14 ) + _C2 ) << 2;
00142     _off = ((( (_C4 - 1024) * _dUT ) >> 14 ) + _C2 ) << 2;
00143 
00144 //  _sens = _C3 * _dUT / 1024 + _C1 ;
00145     _sens = (( _C3 * _dUT ) >> 10 ) + _C1 ;   
00146 
00147 //  _x = (_D1 - 7168) * _sens / 16384 - _off;
00148     _x = (((_D1 - 7168) * _sens ) >> 14 ) - _off;    
00149 
00150 //  _pres = x * 10 / 32 + _C7;
00151     _pres_x10 = (( _x * 10 ) >> 5 ) + _C7;  // Pressure in hPa x 10
00152 
00153 //  _temp = _dUT * _C6 / 65536 + 250;
00154     _temp_x10 = (( _dUT * _C6 ) >> 16 ) - (_dUT >> _D) + 250; // _D, Temp in Celsius x 10
00155 }
00156 
00157 
00158 /** Calculate Altitude
00159   *
00160   * @return none 
00161   */ 
00162 void HP03SA::_calcAlt(void) {
00163 // Calculation based on ISA model
00164 // http://en.wikipedia.org/wiki/Atmospheric_pressure
00165 //
00166 //  h = (1 - pow((P/Pref), RL/gM)) * Tref / L
00167 //
00168 //    h     altitude above Mean Sea Level in m
00169 //    P     atmospheric pressure at altitude h
00170 //    Pref  sea level standard atmospheric pressure 101325 Pa
00171 //    L     temperature lapse rate, = g/cp for dry air  0.0065 K/m
00172 //    Tref  sea level standard temperature  288.15 K (= 15.0 + 273.15)
00173 //    g     Earth-surface gravitational acceleration    9.80665 m/s2
00174 //    M     molar mass of dry air   0.0289644 kg/mol
00175 //    R     universal gas constant  8.31447 J/(mol•K)
00176 //    RL/gM 0.19026674
00177 //    gM/RL 5.25578009f
00178 
00179 //ISA calculation  
00180 //  _alt = 44330.76923f * (1.0f - pow( ((float) _pres_x10 / _pres_base_x10), RLGM));
00181   _alt = (TBASE_X10 / LBASE_X10) * (1.0f - pow( ((float) _pres_x10 / _pres_base_x10), RLGM));
00182       
00183 //Correction for temperature
00184 //  _temp_base_x10 = TBASE_X10 - ( (float) _alt * LBASE_X10 );
00185 //  _temp_base_x10 = TBASE_X10;
00186   
00187   _alt = (float) _alt * ((float)_temp_x10 + 2731.5f) / _temp_base_x10; 
00188 }
00189 
00190 /** Get Pressure and Temperature sample
00191   *
00192   * @return none 
00193   */ 
00194 void HP03SA::sample(void) {
00195   _readTempPres();
00196   _calcTempPres();
00197   _calcAlt();  
00198 }    
00199 
00200 /** Get Absolute Atmospheric Pressure in hPa x 10
00201   * Note: sample() must be called before getAtmPressure()  
00202   * Checked using http://luchtdruk.com/luchtdruk-in-nederland.html
00203   *
00204   * @return int Pressure in hPa x 10 
00205   */ 
00206 int HP03SA::getAbsPressure(void) {
00207   return _pres_x10;
00208 }
00209 
00210 /** Get Sealevel Atmospheric Pressure in hPa x 10
00211   * This produces pressure readings that can be used for weather measurements.
00212   * Note: sample() must be called before getSeaPressure()  
00213   *  
00214   * @param  int alt_meter Altitude above Mean Sea Level where measurement is taken
00215   * @return int Pressure at sea level in hPa x 10 
00216   */ 
00217 int HP03SA::getSeaPressure(int alt_meter) {
00218 //    return ( (float) _pres_x10 / pow (1.0f - ((float) alt_meter / 44330.0), 5.255) );    
00219     return ( (float) _pres_x10 / pow (1.0f - ((float) alt_meter * LBASE_X10 / TBASE_X10), GMRL) );
00220 }
00221 
00222 /** Get Temperature as int in °Celsius x 10
00223   * Note: sample() must be called before getTemperature()  
00224   *
00225   * @return int Temperature in °Celsius x 10
00226   */ 
00227 int HP03SA::getTemperatureInt(void) {
00228   return _temp_x10;
00229 }
00230 
00231 /** Get Temperature as float in °Celsius
00232   * Note: sample() must be called before getTemperature()  
00233   *
00234   * @return float Temperature in °Celsius
00235   */ 
00236 float HP03SA::getTemperature(void) {
00237   return (float) _temp_x10 / 10.0f;  
00238 }
00239 
00240 
00241 /** Convert Temperature from °Celsius into °Fahrenheit
00242   *
00243   * @param  float celsius in °Celsius  
00244   * @return float temperature in °Fahrenheit
00245   */ 
00246 float HP03SA::celsiusToFahrenheit(float celsius) {
00247   
00248   return ((celsius * 9.0f) / 5.0f) + 32.0f; // Convert to Fahrenheit
00249 }
00250 
00251 
00252 /** Get Altitude in meters using ISA
00253   * Note: sample() must be called before getAltitude()  
00254   *
00255   * @return int Altitude in meters above Mean Sea Level (MSL)
00256   */ 
00257 int HP03SA::getAltitude(void) {
00258   return _alt;
00259 }
00260 
00261 /** Get Altitude in feet using ISA
00262   * Note: sample() must be called before getAltitudeFt()  
00263   *
00264   * @return int Altitude in feet above Mean Sea Level (MSL)
00265   */ 
00266 int HP03SA::getAltitudeFt() {
00267   return (float)_alt * 3.28084f;
00268 }
00269     
00270 /** Get Status
00271   *
00272   * @return bool Sensor ready 
00273   */ 
00274 bool HP03SA::getStatus(void) {
00275   char buffer[2];      
00276   int status;
00277     
00278   _xclr=1;   // ADC-XCLR
00279 
00280   // Read ADC with pressure value (dummy operation to check status)
00281   buffer[0] = 0xFF;             // Control Register address  
00282   status=_i2c->write(HP03SA_BARO_SA, buffer, 1);
00283 
00284   _xclr=0;   // ADC-XCLR  
00285  
00286   return (status==0);           // True when device found   
00287 }
00288 
00289 /** Set QNH Pressure to calibrate sensor
00290   *
00291   * @param int pressure_x10 at Mean Sea Level in hPa x 10
00292   *            The getAltitude() reading will be 0 m for the set pressure.
00293   */  
00294 void HP03SA::setPressure(int pressure_x10) {
00295   _pres_base_x10 = (float) pressure_x10;
00296 }
00297 
00298 /** Set QNH Altitude in meter to calibrate sensor
00299   *
00300   * @param int alt_meter Altitude in meters above Mean Sea Level (MSL) for current pressure  
00301   *            The getAltitude() reading will be 'alt_meter' m for the current pressure.  
00302   */ 
00303 void HP03SA::setAltitude(int alt_meter) {
00304     
00305 // Compute _temp_base derived from the temp at set altitude and temp lapse
00306 //  _temp_base_x10 = ((float) _temp_x10 + 2731.5f) + ((float) alt * LBASE_X10);    
00307  
00308 // Compute pressure at Mean Sea Level from the pressure at the set altitude
00309   _pres_base_x10 = (float) _pres_x10 * pow( TBASE_X10 / (TBASE_X10 - ((float) alt_meter * LBASE_X10)), GMRL);
00310 }
00311 
00312 /** Set QNH Altitude in feet to calibrate sensor
00313   *
00314   * @param int alt_feet Altitude in meters above Mean Sea Level (MSL) for current pressure
00315   *            The getAltitudeFt() reading will be 'alt_feet' ft for the current pressure.   
00316   */ 
00317 void HP03SA::setAltitudeFt(int alt_feet){
00318   setAltitude(alt_feet / 3.28084f);
00319 }
00320 
00321