Internet of Greens. Mini automated greenhouse, with an internet of sensors.

Dependencies:   HC_SR04_Ultrasonic_Library PixelArrayBuffer Servo TSL2561 mbed-rtos mbed

Fork of Final_project by Jackson Sheu

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