bazot-laurent / Mbed 2 deprecated TH02_humidity_temp

Dependencies:   mbed

Fork of TH02_humidity_temp by bazot-laurent

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers th02.cpp Source File

th02.cpp

00001 // **********************************************************************************
00002 // Driver definition for HopeRF TH02 temperature and humidity sensor
00003 // **********************************************************************************
00004 // Creative Commons Attrib Share-Alike License
00005 // You are free to use/extend this library but please abide with the CC-BY-SA license:
00006 // http://creativecommons.org/licenses/by-sa/4.0/
00007 //
00008 // For any explanation see TH02 sensor information at
00009 // http://www.hoperf.com/sensor/app/TH02.htm
00010 //
00011 // Code based on following datasheet
00012 // http://www.hoperf.com/upload/sensor/TH02_V1.1.pdf
00013 //
00014 // Written by Charles-Henri Hallard (http://hallard.me)
00015 //
00016 // History : V1.00 2014-07-14 - First release
00017 //           V1.10 2015-04-13 - changed to Wire library instead of m_I2C
00018 //
00019 // All text above must be included in any redistribution.
00020 //
00021 // **********************************************************************************
00022 #include "th02.h"
00023 #include "mbed.h"
00024 #include "math.h"
00025 
00026 // Class Constructor
00027 
00028 TH02::TH02(PinName sda,PinName scl,uint8_t address): m_I2C(sda, scl)
00029 {
00030     _address = address; // m_I2C Module Address
00031     _last_temp = TH02_UNINITIALIZED_TEMP;  // Last measured temperature (for linearization)
00032     _last_rh = TH02_UNINITIALIZED_RH;      // Last measured RH
00033 //m_I2C.frequency(10000); //set 10khz i2c frequency
00034 
00035 }
00036 
00037 TH02::~TH02()
00038 {
00039 
00040 }
00041 
00042 
00043 
00044 /* ======================================================================
00045 Function: writeCommand
00046 Purpose : write the "register address" value on m_I2C bus
00047 Input   : register address
00048           true if we need to release the bus after (default yes)
00049 Output  : Arduino Wire library return code (0 if ok)
00050 Comments:
00051 ====================================================================== */
00052 uint8_t TH02::writeCommand(uint8_t command, bool release)
00053 {
00054     int iError;
00055     (void) m_I2C.start();
00056     //Wire.beginTransmission(_address);
00057     iError=m_I2C.write(_address);// send adress of i2c slave
00058 
00059     if (iError==1) { // ack received
00060 // Wire.write(command) ;
00061         iError= m_I2C.write(command);
00062 
00063 
00064         if (release==true) {
00065             m_I2C.stop();// return stop error code
00066         }
00067     }
00068 
00069     if (iError==1) iError=0;// ack received
00070     else iError=1;// no ack
00071     return iError;
00072 }
00073 
00074 /* ======================================================================
00075 Function: writeRegister
00076 Purpose : write a value on the designed register address on m_I2C bus
00077 Input   : register address
00078           value to write
00079 Output  : Arduino Wire library return code (0 if ok)
00080 Comments:
00081 ====================================================================== */
00082 uint8_t TH02::writeRegister(uint8_t reg, uint8_t value)
00083 {
00084     int iError;
00085 
00086     bool ret = false;
00087 
00088     //Wire.beginTransmission(_address);
00089     (void) m_I2C.start();
00090     iError=m_I2C.write(_address);// send adress of i2c slave
00091 // Wire.write(reg);
00092     if (iError==1) {
00093 
00094         iError= m_I2C.write(reg);
00095 
00096 // Wire.write(value);
00097         (void) m_I2C.write(value);
00098     }
00099 // return Wire.endTransmission();
00100     m_I2C.stop();// return stop error code
00101     if (iError==1) iError=0;// ack received
00102     else iError=1;// no ack
00103     wait_ms(1);
00104     return iError;
00105 }
00106 
00107 /* ======================================================================
00108 Function: readRegister
00109 Purpose : read a register address value on m_I2C bus
00110 Input   : register address
00111           pointer where the return value will be filled
00112 Output  : Arduino Wire library return code (0 if ok)
00113 Comments:
00114 ====================================================================== */
00115 uint8_t TH02::readRegister(uint8_t reg, uint8_t * value)
00116 {
00117     uint8_t ret ;
00118     int iAck,iRedVal,iError;
00119     // Send a register reading command
00120     // but DO NOT release the m_I2C bus
00121 // (void) m_I2C.start();
00122     //iError=m_I2C.write(_address);// send adress of i2c slave
00123 
00124     //if (iError==1) // ack received
00125     //{
00126     ret = writeCommand(reg, false);// no stop
00127 
00128     if ( ret == 0) { //if command ok
00129         // Wire.requestFrom( (uint8_t) _address, (uint8_t) 1);
00130         (void) m_I2C.start();
00131         iError=m_I2C.write(_address+0x01);// send adress of i2c slave in read mode
00132         *value =m_I2C.read(0);//send non ack
00133         // if (Wire.available() != 1)
00134         /*if (iAck != 1)
00135 
00136         // Other error as Wire library
00137         ret = 4;
00138         else
00139         // grab the value*/
00140         //   *value = iRedVal; // return Red value by ref
00141 
00142         //}
00143 
00144         // Ok now we have finished
00145 // Wire.endTransmission();
00146 
00147     }
00148     (void) m_I2C.stop();// return stop error code
00149     wait_ms(1);
00150     return ret;
00151 }
00152 
00153 /* ======================================================================
00154 Function: getId
00155 Purpose : Get device ID register
00156 Input   : pointer where the return value will be filled
00157 Output  : Arduino Wire library return code (0 if ok)
00158 Comments: -
00159 ====================================================================== */
00160 uint8_t TH02::getId(uint8_t * pvalue)
00161 {
00162     return (readRegister(TH02_ID, pvalue));
00163 }
00164 
00165 /* ======================================================================
00166 Function: getStatus
00167 Purpose : Get device status register
00168 Input   : pointer where the return value will be filled
00169 Output  : Arduino Wire library return code (0 if ok)
00170 Comments:
00171 ====================================================================== */
00172 uint8_t TH02::getStatus(uint8_t * pvalue)
00173 {
00174     return (readRegister(TH02_STATUS, pvalue));
00175 }
00176 
00177 /* ======================================================================
00178 Function: isConverting
00179 Purpose : Indicate if a temperature or humidity conversion is in progress
00180 Input   : -
00181 Output  : true if conversion in progress false otherwise
00182 Comments:
00183 ====================================================================== */
00184 bool TH02::isConverting(void)
00185 {
00186     uint8_t status;
00187     // Get status and check RDY bit
00188     if ( getStatus(&status) == 0)
00189 
00190     {
00191        // printf("\n lecture status %x",status);
00192         if ( (status & TH02_STATUS_RDY) ==1 )
00193             return true;
00194     }
00195     return false;
00196 }
00197 
00198 /* ======================================================================
00199 Function: getConfig
00200 Purpose : Get device configuration register
00201 Input   : pointer where the return value will be filled
00202 Output  : Arduino Wire library return code (0 if ok)
00203 Comments:
00204 ====================================================================== */
00205 uint8_t TH02::getConfig(uint8_t * pvalue)
00206 {
00207     return (readRegister(TH02_CONFIG, pvalue));
00208 }
00209 
00210 /* ======================================================================
00211 Function: setConfig
00212 Purpose : Set device configuration register
00213 Input   : value to set
00214 Output  : true if succeded, false otherwise
00215 Comments:
00216 ====================================================================== */
00217 uint8_t TH02::setConfig(uint8_t config)
00218 {
00219     return (writeRegister(TH02_CONFIG, config));
00220 }
00221 
00222 /* ======================================================================
00223 Function: startTempConv
00224 Purpose : Start a temperature conversion
00225 Input   : - fastmode true to enable fast conversion
00226           - heater true to enable heater
00227 Output  : true if succeded, false otherwise
00228 Comments: if heater enabled, it will not be auto disabled
00229 ====================================================================== */
00230 uint8_t TH02::startTempConv(bool fastmode, bool heater)
00231 {
00232     // init configuration register to start and temperature
00233     uint8_t config = TH02_CONFIG_START | TH02_CONFIG_TEMP;
00234 
00235     // set fast mode and heater if asked
00236     if (fastmode) config |= TH02_CONFIG_FAST;
00237     if (heater)   config |= TH02_CONFIG_HEAT;
00238 
00239     // write to configuration register
00240     return ( setConfig( config ) );
00241 }
00242 
00243 /* ======================================================================
00244 Function: startRHConv
00245 Purpose : Start a relative humidity conversion
00246 Input   : - fastmode true to enable fast conversion
00247           - heater true to enable heater
00248 Output  : true if succeded, false otherwise
00249 Comments: if heater enabled, it will not be auto disabled
00250 ====================================================================== */
00251 uint8_t TH02::startRHConv(bool fastmode, bool heater)
00252 {
00253     // init configuration register to start and no temperature (so RH)
00254     uint8_t config = TH02_CONFIG_START;
00255 
00256     // set fast mode and heater if asked
00257     if (fastmode) config |= TH02_CONFIG_FAST;
00258     if (heater)   config |= TH02_CONFIG_HEAT;
00259 
00260     // write to configuration register
00261     return ( setConfig( config ) );
00262 }
00263 
00264 /* ======================================================================
00265 Function: waitEndConversion
00266 Purpose : wait for a temperature or RH conversion is done
00267 Input   :
00268 Output  : delay in ms the process took.
00269 Comments: if return >= TH02_CONVERSION_TIME_OUT, time out occured
00270 ====================================================================== */
00271 uint8_t TH02::waitEndConversion(void)
00272 {
00273     // okay this is basic approach not so accurate
00274     // but avoid using long and millis()
00275     uint8_t time_out = 0;
00276 
00277     // loop until conversion done or duration >= time out
00278     while (isConverting() && (time_out <= TH02_CONVERSION_TIME_OUT) ) {
00279         ++time_out;
00280         wait_ms(2);
00281     }
00282 
00283     // return approx time of conversion
00284     return (time_out);
00285 }
00286 
00287 /* ======================================================================
00288 Function: roundInt
00289 Purpose : round a float value to int
00290 Input   : float value
00291 Output  : int value rounded
00292 Comments:
00293 ====================================================================== */
00294 int16_t TH02::roundInt(float value)
00295 {
00296 
00297     // check positive number and do round
00298     if (value >= 0.0f)
00299         value = floor(value + 0.5f);
00300     else
00301         value = ceil(value - 0.5f);
00302 
00303     // return int value
00304     return (static_cast<int16_t>(value));
00305 }
00306 
00307 /* to avoid math library may I need to test something
00308    like that
00309 float TH02::showDecimals(float x, int numDecimals)
00310 {
00311     int y=x;
00312     double z=x-y;
00313     double m=pow(10,numDecimals);
00314     double q=z*m;
00315     double r=round(q);
00316     return static_cast<double>(y)+(1.0/m)*r;
00317 }
00318 */
00319 
00320 
00321 /* ======================================================================
00322 Function: getConversionValue
00323 Purpose : return the last converted value to int * 10 to have 1 digit prec.
00324 Input   : float value
00325 Output  : value rounded but multiplied per 10 or TH02_UNDEFINED_VALUE on err
00326 Comments: - temperature and rh raw values (*100) are stored for raw purpose
00327           - the configuration register is checked to see if last conv was
00328             a temperature or humidity conversion
00329 ====================================================================== */
00330 int16_t TH02::getConversionValue(void)
00331 {
00332     char cMaChaine[4];
00333     int iError;
00334     int32_t result=0 ;
00335     uint8_t config;
00336     int16_t  ret = TH02_UNDEFINED_VALUE;
00337 
00338     // Prepare reading address of ADC data result
00339     /*if ( writeCommand(TH02_DATAh, false) == 0 ) // no stop
00340     {*/
00341     // Read 2 bytes adc data result MSB and LSB from TH02
00342     //Wire.requestFrom( (uint8_t) _address, (uint8_t) 2);
00343     writeCommand(TH02_DATAh, false);
00344 
00345     // read of two register
00346     (void) m_I2C.start();
00347     iError=m_I2C.write(_address+1);// send adress of i2c slave read mode
00348     if (iError==1) {
00349         cMaChaine[0]= m_I2C.read(1);// read first byte with ack
00350         cMaChaine[1]=m_I2C.read(0);// read first byte without ack
00351        
00352       m_I2C.stop();// rperform stop
00353 
00354 
00355 
00356         //iError= m_I2C.read (_address,cMaChaine,4,false);// send stop at end
00357        // printf (" \n\r lecture I2C: %02x %02x",cMaChaine[0],cMaChaine[1]);
00358       //}
00359        result=(cMaChaine[0]<<8 )|cMaChaine[1];
00360         // Get configuration to know what was asked last time
00361        
00362         if (getConfig(&config)==0) {
00363             // last conversion was temperature ?
00364             if( config & TH02_CONFIG_TEMP) {
00365                 result >>= 2;  // remove 2 unused LSB bits
00366                 result *= 100; // multiply per 100 to have int value with 2 decimal
00367                 result /= 32;  // now apply datasheet formula
00368                 if(result >= 5000) {
00369                     result -= 5000;
00370                 } else {
00371                     result -= 5000;
00372                     result = -result;
00373                 }
00374 
00375                 // now result contain temperature * 100
00376                 // so 2134 is 21.34 C
00377 
00378                 // Save raw value
00379                 _last_temp = result;
00380             }
00381             // it was RH conversion
00382             else {
00383                 result >>= 4;  // remove 4 unused LSB bits
00384                 result *= 100; // multiply per 100 to have int value with 2 decimal
00385                 result /= 16;  // now apply datasheet formula
00386                 result -= 2400;
00387 
00388                 // now result contain humidity * 100
00389                 // so 4567 is 45.67 % RH
00390                 _last_rh = result;
00391             }
00392 
00393             // remember result value is multiplied by 10 to avoid float calculation later
00394             // so humidity of 45.6% is 456 and temp of 21.3 C is 213
00395         ret = roundInt(result/10.0f);
00396         }
00397      }   
00398      
00399      else{
00400          
00401       m_I2C.stop();// rperform stop
00402       }
00403     return ret;
00404 }
00405 
00406 
00407 
00408 
00409 
00410 /* ======================================================================
00411 Function: getConpensatedRH
00412 Purpose : return the compensated calulated humidity
00413 Input   : true if we want to round value to 1 digit precision, else 2
00414 Output  : the compensed RH value (rounded or not)
00415 Comments:
00416 ====================================================================== */
00417 int16_t TH02::getConpensatedRH(bool round)
00418 {
00419     float rhvalue  ;
00420     float rhlinear ;
00421     int16_t  ret = TH02_UNDEFINED_VALUE;
00422 
00423     // did we had a previous measure RH
00424     if (_last_rh != TH02_UNINITIALIZED_RH) {
00425         // now we're float restore real value RH value
00426         rhvalue = (float) _last_rh / 100.0 ;
00427 
00428         // apply linear compensation
00429         rhlinear = rhvalue - ((rhvalue*rhvalue) * TH02_A2 + rhvalue * TH02_A1 + TH02_A0);
00430 
00431         // correct value
00432         rhvalue = rhlinear;
00433 
00434         // do we have a initialized temperature value ?
00435         if (_last_temp != TH02_UNINITIALIZED_TEMP ) {
00436             // Apply Temperature compensation
00437             // remember last temp was stored * 100
00438             rhvalue += ((_last_temp/100.0) - 30.0) * (rhlinear * TH02_Q1 + TH02_Q0);
00439         }
00440 
00441         // now get back * 100 to have int with 2 digit precision
00442         rhvalue *= 100;
00443 
00444         // do we need to round to 1 digit ?
00445         if (round) {
00446             // remember result value is multiplied by 10 to avoid float calculation later
00447             // so humidity of 45.6% is 456
00448             ret = roundInt(rhvalue/10.0f);
00449         } else {
00450             ret = (int16_t) rhvalue;
00451         }
00452     }
00453 
00454     return ret;
00455 }
00456 
00457 /* ======================================================================
00458 Function: getLastRawRH
00459 Purpose : return the raw humidity * 100
00460 Input   :
00461 Output  : int value (ie 4123 for 41.23%)
00462 Comments:
00463 ====================================================================== */
00464 int32_t TH02::getLastRawRH(void)
00465 {
00466     return _last_rh;
00467 }
00468 
00469 /* ======================================================================
00470 Function: getLastRawTemp
00471 Purpose : return the raw temperature value * 100
00472 Input   :
00473 Output  : int value (ie 2124 for 21.24 C)
00474 Comments:
00475 ====================================================================== */
00476 int32_t TH02::getLastRawTemp(void)
00477 {
00478     return _last_temp;
00479 }