Updated version for LoraWan GEII IUT
Dependencies: Servo Cayenne-LPP
Diff: th02.cpp
- Revision:
- 58:81c66fac6476
diff -r 5ec0379d69d6 -r 81c66fac6476 th02.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/th02.cpp Tue Oct 22 08:45:41 2019 +0000 @@ -0,0 +1,479 @@ +// ********************************************************************************** +// Driver definition for HopeRF TH02 temperature and humidity sensor +// ********************************************************************************** +// Creative Commons Attrib Share-Alike License +// You are free to use/extend this library but please abide with the CC-BY-SA license: +// http://creativecommons.org/licenses/by-sa/4.0/ +// +// For any explanation see TH02 sensor information at +// http://www.hoperf.com/sensor/app/TH02.htm +// +// Code based on following datasheet +// http://www.hoperf.com/upload/sensor/TH02_V1.1.pdf +// +// Written by Charles-Henri Hallard (http://hallard.me) +// +// History : V1.00 2014-07-14 - First release +// V1.10 2015-04-13 - changed to Wire library instead of m_I2C +// +// All text above must be included in any redistribution. +// +// ********************************************************************************** +#include "th02.h" +#include "mbed.h" +#include "math.h" + +// Class Constructor + +TH02::TH02(PinName sda,PinName scl,uint8_t address): m_I2C(sda, scl) +{ + _address = address; // m_I2C Module Address + _last_temp = TH02_UNINITIALIZED_TEMP; // Last measured temperature (for linearization) + _last_rh = TH02_UNINITIALIZED_RH; // Last measured RH +//m_I2C.frequency(10000); //set 10khz i2c frequency + +} + +TH02::~TH02() +{ + +} + + + +/* ====================================================================== +Function: writeCommand +Purpose : write the "register address" value on m_I2C bus +Input : register address + true if we need to release the bus after (default yes) +Output : Arduino Wire library return code (0 if ok) +Comments: +====================================================================== */ +uint8_t TH02::writeCommand(uint8_t command, bool release) +{ + int iError; + (void) m_I2C.start(); + //Wire.beginTransmission(_address); + iError=m_I2C.write(_address);// send adress of i2c slave + + if (iError==1) { // ack received +// Wire.write(command) ; + iError= m_I2C.write(command); + + + if (release==true) { + m_I2C.stop();// return stop error code + } + } + + if (iError==1) iError=0;// ack received + else iError=1;// no ack + return iError; +} + +/* ====================================================================== +Function: writeRegister +Purpose : write a value on the designed register address on m_I2C bus +Input : register address + value to write +Output : Arduino Wire library return code (0 if ok) +Comments: +====================================================================== */ +uint8_t TH02::writeRegister(uint8_t reg, uint8_t value) +{ + int iError; + + bool ret = false; + + //Wire.beginTransmission(_address); + (void) m_I2C.start(); + iError=m_I2C.write(_address);// send adress of i2c slave +// Wire.write(reg); + if (iError==1) { + + iError= m_I2C.write(reg); + +// Wire.write(value); + (void) m_I2C.write(value); + } +// return Wire.endTransmission(); + m_I2C.stop();// return stop error code + if (iError==1) iError=0;// ack received + else iError=1;// no ack + wait_ms(1); + return iError; +} + +/* ====================================================================== +Function: readRegister +Purpose : read a register address value on m_I2C bus +Input : register address + pointer where the return value will be filled +Output : Arduino Wire library return code (0 if ok) +Comments: +====================================================================== */ +uint8_t TH02::readRegister(uint8_t reg, uint8_t * value) +{ + uint8_t ret ; + int iAck,iRedVal,iError; + // Send a register reading command + // but DO NOT release the m_I2C bus +// (void) m_I2C.start(); + //iError=m_I2C.write(_address);// send adress of i2c slave + + //if (iError==1) // ack received + //{ + ret = writeCommand(reg, false);// no stop + + if ( ret == 0) { //if command ok + // Wire.requestFrom( (uint8_t) _address, (uint8_t) 1); + (void) m_I2C.start(); + iError=m_I2C.write(_address+0x01);// send adress of i2c slave in read mode + *value =m_I2C.read(0);//send non ack + // if (Wire.available() != 1) + /*if (iAck != 1) + + // Other error as Wire library + ret = 4; + else + // grab the value*/ + // *value = iRedVal; // return Red value by ref + + //} + + // Ok now we have finished +// Wire.endTransmission(); + + } + (void) m_I2C.stop();// return stop error code + wait_ms(1); + return ret; +} + +/* ====================================================================== +Function: getId +Purpose : Get device ID register +Input : pointer where the return value will be filled +Output : Arduino Wire library return code (0 if ok) +Comments: - +====================================================================== */ +uint8_t TH02::getId(uint8_t * pvalue) +{ + return (readRegister(TH02_ID, pvalue)); +} + +/* ====================================================================== +Function: getStatus +Purpose : Get device status register +Input : pointer where the return value will be filled +Output : Arduino Wire library return code (0 if ok) +Comments: +====================================================================== */ +uint8_t TH02::getStatus(uint8_t * pvalue) +{ + return (readRegister(TH02_STATUS, pvalue)); +} + +/* ====================================================================== +Function: isConverting +Purpose : Indicate if a temperature or humidity conversion is in progress +Input : - +Output : true if conversion in progress false otherwise +Comments: +====================================================================== */ +bool TH02::isConverting(void) +{ + uint8_t status; + // Get status and check RDY bit + if ( getStatus(&status) == 0) + + { + // printf("\n lecture status %x",status); + if ( (status & TH02_STATUS_RDY) ==1 ) + return true; + } + return false; +} + +/* ====================================================================== +Function: getConfig +Purpose : Get device configuration register +Input : pointer where the return value will be filled +Output : Arduino Wire library return code (0 if ok) +Comments: +====================================================================== */ +uint8_t TH02::getConfig(uint8_t * pvalue) +{ + return (readRegister(TH02_CONFIG, pvalue)); +} + +/* ====================================================================== +Function: setConfig +Purpose : Set device configuration register +Input : value to set +Output : true if succeded, false otherwise +Comments: +====================================================================== */ +uint8_t TH02::setConfig(uint8_t config) +{ + return (writeRegister(TH02_CONFIG, config)); +} + +/* ====================================================================== +Function: startTempConv +Purpose : Start a temperature conversion +Input : - fastmode true to enable fast conversion + - heater true to enable heater +Output : true if succeded, false otherwise +Comments: if heater enabled, it will not be auto disabled +====================================================================== */ +uint8_t TH02::startTempConv(bool fastmode, bool heater) +{ + // init configuration register to start and temperature + uint8_t config = TH02_CONFIG_START | TH02_CONFIG_TEMP; + + // set fast mode and heater if asked + if (fastmode) config |= TH02_CONFIG_FAST; + if (heater) config |= TH02_CONFIG_HEAT; + + // write to configuration register + return ( setConfig( config ) ); +} + +/* ====================================================================== +Function: startRHConv +Purpose : Start a relative humidity conversion +Input : - fastmode true to enable fast conversion + - heater true to enable heater +Output : true if succeded, false otherwise +Comments: if heater enabled, it will not be auto disabled +====================================================================== */ +uint8_t TH02::startRHConv(bool fastmode, bool heater) +{ + // init configuration register to start and no temperature (so RH) + uint8_t config = TH02_CONFIG_START; + + // set fast mode and heater if asked + if (fastmode) config |= TH02_CONFIG_FAST; + if (heater) config |= TH02_CONFIG_HEAT; + + // write to configuration register + return ( setConfig( config ) ); +} + +/* ====================================================================== +Function: waitEndConversion +Purpose : wait for a temperature or RH conversion is done +Input : +Output : delay in ms the process took. +Comments: if return >= TH02_CONVERSION_TIME_OUT, time out occured +====================================================================== */ +uint8_t TH02::waitEndConversion(void) +{ + // okay this is basic approach not so accurate + // but avoid using long and millis() + uint8_t time_out = 0; + + // loop until conversion done or duration >= time out + while (isConverting() && (time_out <= TH02_CONVERSION_TIME_OUT) ) { + ++time_out; + wait_ms(2); + } + + // return approx time of conversion + return (time_out); +} + +/* ====================================================================== +Function: roundInt +Purpose : round a float value to int +Input : float value +Output : int value rounded +Comments: +====================================================================== */ +int16_t TH02::roundInt(float value) +{ + + // check positive number and do round + if (value >= 0.0f) + value = floor(value + 0.5f); + else + value = ceil(value - 0.5f); + + // return int value + return (static_cast<int16_t>(value)); +} + +/* to avoid math library may I need to test something + like that +float TH02::showDecimals(float x, int numDecimals) +{ + int y=x; + double z=x-y; + double m=pow(10,numDecimals); + double q=z*m; + double r=round(q); + return static_cast<double>(y)+(1.0/m)*r; +} +*/ + + +/* ====================================================================== +Function: getConversionValue +Purpose : return the last converted value to int * 10 to have 1 digit prec. +Input : float value +Output : value rounded but multiplied per 10 or TH02_UNDEFINED_VALUE on err +Comments: - temperature and rh raw values (*100) are stored for raw purpose + - the configuration register is checked to see if last conv was + a temperature or humidity conversion +====================================================================== */ +int16_t TH02::getConversionValue(void) +{ + char cMaChaine[4]; + int iError; + int32_t result=0 ; + uint8_t config; + int16_t ret = TH02_UNDEFINED_VALUE; + + // Prepare reading address of ADC data result + /*if ( writeCommand(TH02_DATAh, false) == 0 ) // no stop + {*/ + // Read 2 bytes adc data result MSB and LSB from TH02 + //Wire.requestFrom( (uint8_t) _address, (uint8_t) 2); + writeCommand(TH02_DATAh, false); + + // read of two register + (void) m_I2C.start(); + iError=m_I2C.write(_address+1);// send adress of i2c slave read mode + if (iError==1) { + cMaChaine[0]= m_I2C.read(1);// read first byte with ack + cMaChaine[1]=m_I2C.read(0);// read first byte without ack + + m_I2C.stop();// rperform stop + + + + //iError= m_I2C.read (_address,cMaChaine,4,false);// send stop at end + // printf (" \n\r lecture I2C: %02x %02x",cMaChaine[0],cMaChaine[1]); + //} + result=(cMaChaine[0]<<8 )|cMaChaine[1]; + // Get configuration to know what was asked last time + + if (getConfig(&config)==0) { + // last conversion was temperature ? + if( config & TH02_CONFIG_TEMP) { + result >>= 2; // remove 2 unused LSB bits + result *= 100; // multiply per 100 to have int value with 2 decimal + result /= 32; // now apply datasheet formula + if(result >= 5000) { + result -= 5000; + } else { + result -= 5000; + result = -result; + } + + // now result contain temperature * 100 + // so 2134 is 21.34 C + + // Save raw value + _last_temp = result; + } + // it was RH conversion + else { + result >>= 4; // remove 4 unused LSB bits + result *= 100; // multiply per 100 to have int value with 2 decimal + result /= 16; // now apply datasheet formula + result -= 2400; + + // now result contain humidity * 100 + // so 4567 is 45.67 % RH + _last_rh = result; + } + + // remember result value is multiplied by 10 to avoid float calculation later + // so humidity of 45.6% is 456 and temp of 21.3 C is 213 + ret = roundInt(result/10.0f); + } + } + + else{ + + m_I2C.stop();// rperform stop + } + return ret; +} + + + + + +/* ====================================================================== +Function: getConpensatedRH +Purpose : return the compensated calulated humidity +Input : true if we want to round value to 1 digit precision, else 2 +Output : the compensed RH value (rounded or not) +Comments: +====================================================================== */ +int16_t TH02::getConpensatedRH(bool round) +{ + float rhvalue ; + float rhlinear ; + int16_t ret = TH02_UNDEFINED_VALUE; + + // did we had a previous measure RH + if (_last_rh != TH02_UNINITIALIZED_RH) { + // now we're float restore real value RH value + rhvalue = (float) _last_rh / 100.0 ; + + // apply linear compensation + rhlinear = rhvalue - ((rhvalue*rhvalue) * TH02_A2 + rhvalue * TH02_A1 + TH02_A0); + + // correct value + rhvalue = rhlinear; + + // do we have a initialized temperature value ? + if (_last_temp != TH02_UNINITIALIZED_TEMP ) { + // Apply Temperature compensation + // remember last temp was stored * 100 + rhvalue += ((_last_temp/100.0) - 30.0) * (rhlinear * TH02_Q1 + TH02_Q0); + } + + // now get back * 100 to have int with 2 digit precision + rhvalue *= 100; + + // do we need to round to 1 digit ? + if (round) { + // remember result value is multiplied by 10 to avoid float calculation later + // so humidity of 45.6% is 456 + ret = roundInt(rhvalue/10.0f); + } else { + ret = (int16_t) rhvalue; + } + } + + return ret; +} + +/* ====================================================================== +Function: getLastRawRH +Purpose : return the raw humidity * 100 +Input : +Output : int value (ie 4123 for 41.23%) +Comments: +====================================================================== */ +int32_t TH02::getLastRawRH(void) +{ + return _last_rh; +} + +/* ====================================================================== +Function: getLastRawTemp +Purpose : return the raw temperature value * 100 +Input : +Output : int value (ie 2124 for 21.24 C) +Comments: +====================================================================== */ +int32_t TH02::getLastRawTemp(void) +{ + return _last_temp; +}