Library for the Measurement Specialties' HTU21D Humidity and Temperature sensor. Code includes device's heater on/off control, serial number access, dew point calculations and RTOS hooks. To date, code tested on GR-PEACH, K64F and KL25Z boards with and w/o RTOS, SDFlash and USB serial Rx interrupts.

Dependents:   BLE_soil_humidity

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers htu21d.cpp Source File

htu21d.cpp

00001 /**
00002 HTU21D / HPP828E031 driver for mbed.
00003 - Includes RTOS hooks if RTOS is detected during compile.
00004 Author: Kevin Braun
00005 **/
00006 
00007 #include "htu21d.h"
00008 
00009 double theTempIs = 0.0;
00010 double theHumIs = 0.0;
00011 
00012 #if not defined HTU21Di2cLOWLEVEL
00013 char htuBuffer[8];
00014 #endif
00015 
00016 //--------------------------------------------------------------------------------------------------------------------------------------//
00017 //Contstructor
00018 
00019 htu21d::htu21d(PinName sda, PinName scl) : _i2c(sda, scl) {
00020     _i2c.frequency(400000);
00021 }
00022 
00023 htu21d::htu21d(PinName sda, PinName scl, int i2cFrequency) : _i2c(sda, scl) {
00024     _i2c.frequency(i2cFrequency);
00025 }
00026 
00027 //--------------------------------------------------------------------------------------------------------------------------------------//
00028 //Destructor
00029 
00030 htu21d::~htu21d() {
00031 }
00032 
00033 //--------------------------------------------------------------------------------------------------------------------------------------//
00034 //Perform a soft reset on the HTU21D. REturn of 1 = ok, 0 = timeout.
00035 
00036 int htu21d::softReset() {
00037     int htu21 = 0;
00038 #if defined HTU21Di2cLOWLEVEL
00039     _i2c.start();
00040     htu21 = _i2c.write(HTU21Di2cWRITE);     //i2c, 1 = ack
00041     if(htu21 == 1) {
00042         _i2c.write(HTU21DRESET);            //soft reset, must wait 15mS
00043         _i2c.stop();
00044         wait_ms(16);                        //must wait a least 15mS for reset to finish
00045         htu21d::getSNReg();                 //go load up the s/n registers
00046     }
00047     return(htu21);
00048 #else
00049     htuBuffer[0] = HTU21DRESET;
00050     htu21 = _i2c.write(HTU21Di2cWRITE, htuBuffer, 1, false);
00051     wait_ms(16);
00052     htu21d::getSNReg();
00053     return(!(htu21));
00054 #endif
00055 }
00056 
00057 //--------------------------------------------------------------------------------------------------------------------------------------//
00058 //Get the HTU21D user register. Returns 8 bit register.
00059 
00060 uint8_t htu21d::getUserReg() {
00061 #if defined HTU21Di2cLOWLEVEL
00062     int htu21 = 0;
00063     uint8_t htu21data = 0;
00064     _i2c.start();
00065     htu21 = _i2c.write(HTU21Di2cWRITE);     //i2c, 1 = ack
00066     if(htu21 == 1) {
00067         _i2c.write(HTU21DREADUSER);
00068         _i2c.start();
00069         htu21 = _i2c.write(HTU21Di2cREAD);
00070         htu21data = _i2c.read(0);
00071         _i2c.stop();
00072     }
00073     return(htu21data);
00074 #else
00075     htuBuffer[0] = HTU21DREADUSER;
00076     _i2c.write(HTU21Di2cWRITE, htuBuffer, 1, true);
00077     if(!(_i2c.read(HTU21Di2cREAD, htuBuffer, 1, false))) {
00078         return(htuBuffer[0]);
00079     } else {
00080         return(0);
00081     }
00082 #endif
00083 }
00084 
00085 //--------------------------------------------------------------------------------------------------------------------------------------//
00086 //Turn ON the heater the HTU21D user register. 
00087 
00088 int htu21d::heaterOn() {
00089     uint8_t htu21data = htu21d::getUserReg();
00090     htu21data |= HTU21DHEATER;
00091 #if defined HTU21Di2cLOWLEVEL
00092     int htu21 = 0;
00093     _i2c.start();
00094     htu21 = _i2c.write(HTU21Di2cWRITE);     //i2c, 1 = ack
00095     if(htu21 == 1) {
00096         _i2c.write(HTU21DWRITEUSER);
00097         htu21 = _i2c.write(htu21data);
00098         _i2c.stop();
00099     }
00100     return(htu21);
00101 #else
00102     htuBuffer[0] = HTU21DWRITEUSER;
00103     htuBuffer[1] = htu21data;
00104     return(_i2c.write(HTU21Di2cWRITE, htuBuffer, 2, false));
00105 #endif
00106 }
00107 
00108 //--------------------------------------------------------------------------------------------------------------------------------------//
00109 //Turn OFF the heater the HTU21D user register. 
00110 
00111 int htu21d::heaterOff() {
00112     uint8_t htu21data = htu21d::getUserReg();
00113     htu21data &= ~HTU21DHEATER;
00114 #if defined HTU21Di2cLOWLEVEL
00115     int htu21 = 0;
00116     _i2c.start();
00117     htu21 = _i2c.write(HTU21Di2cWRITE);     //i2c, 1 = ack
00118     if(htu21 == 1) {
00119         _i2c.write(HTU21DWRITEUSER);
00120         htu21 = _i2c.write(htu21data);
00121         _i2c.stop();
00122     }
00123     return(htu21);
00124 #else
00125     htuBuffer[0] = HTU21DWRITEUSER;
00126     htuBuffer[1] = htu21data;
00127     return(_i2c.write(HTU21Di2cWRITE, htuBuffer, 2, false));
00128 #endif
00129 
00130 }
00131 
00132 //--------------------------------------------------------------------------------------------------------------------------------------//
00133 //Get the status of the heater the HTU21D user register. 0 = off, 4 = on.
00134 
00135 uint8_t htu21d::getHeater() {
00136     uint8_t htu21data = htu21d::getUserReg();
00137     htu21data &= HTU21DHEATER;
00138     return(htu21data);
00139 }
00140     
00141 //--------------------------------------------------------------------------------------------------------------------------------------//
00142 //generic routine to get temp or humidity from HTU21D. 
00143 //Returns 14 bits of data (anded 0xFFFC) or 0000 if i2c timeout occurs.
00144 //After a read temp or humidity command, HTU21D responds with NACKs until data is ready.
00145 //NOTE: Use non-hold commands
00146 
00147 uint16_t htu21d::getData(uint8_t reg) {
00148     int htu21cnt = 0;           //number of NACKs before ACK or timeout 
00149 #if defined HTU21Di2cLOWLEVEL
00150     uint16_t htu21data = 0;     //returned data
00151     int htu21 = 0;              //ACK flag
00152     _i2c.start();
00153     htu21 = _i2c.write(HTU21Di2cWRITE);
00154     _i2c.write(reg);            //read temp, no hold
00155     _i2c.stop();
00156     if(htu21 == 0) return 0;    //HTU21T not responding
00157     do {
00158         htu21cnt++;
00159         _i2c.start();
00160         htu21 = _i2c.write(HTU21Di2cREAD);
00161         if(htu21 == 1) {
00162             htu21data = _i2c.read(1) << 8;
00163             htu21data |= _i2c.read(0) & 0xFC;
00164             _i2c.stop();
00165         }
00166         wait_us(1000);
00167     } while((htu21cnt < 100) && (htu21 == 0));  //htu21cnt takes 55 to get temp, 16 for humidity (at 1mS loops)
00168         
00169     if(htu21 == 0) return 0;    //HTU21D ACK response timed out
00170     return(htu21data);          //return 14 bit value
00171 #else
00172     htuBuffer[0] = reg;
00173     _i2c.write(HTU21Di2cWRITE, htuBuffer, 1, false);
00174     do {
00175         htu21cnt++;
00176         if(!(_i2c.read(HTU21Di2cREAD, htuBuffer, 2, false))) {
00177             return((htuBuffer[0] << 8) | htuBuffer[1]);
00178         }
00179         wait_us(1000);
00180     } while(htu21cnt < 100);
00181     return 0;
00182 #endif
00183 }
00184 
00185 //--------------------------------------------------------------------------------------------------------------------------------------//
00186 //get temperature from HTU21D in degrees C. Returns with 255.0 if HTU21D had timed out.
00187 
00188 float htu21d::getTemp() {
00189     uint16_t getData = htu21d::getData(HTU21DtempNOHOLD);
00190     if (getData == 0) return(255.0);                        //return with error
00191     double tempData = (double)getData / 65536.0;
00192     theTempIs = -46.85 + (175.72 * tempData);
00193     return(theTempIs);
00194 }
00195 
00196 //--------------------------------------------------------------------------------------------------------------------------------------//
00197 //get humidity from HTU21D in percentage. Returns with 255.0 if HTU21D had timed out.
00198 
00199 float htu21d::getHum() {
00200     uint16_t getData = htu21d::getData(HTU21DhumNOHOLD);
00201     if (getData == 0) return(255.0);                        //return with error
00202     double tempData = (double)getData / 65536.0;
00203     theHumIs = -6.0 + (125.0 * tempData);
00204     return(theHumIs);
00205 }
00206 
00207 //--------------------------------------------------------------------------------------------------------------------------------------//
00208 //Calculate the Dew Point from getTemp and getHum. User must first execute both getTemp and getHum for an accurate result.
00209 //Calculations come from DHT library
00210 /*  Copyright (C) Wim De Roeve
00211  *                based on DHT22 sensor library by HO WING KIT
00212  *                Arduino DHT11 library
00213 */
00214 
00215 float htu21d::getDewPt() {
00216     // dewPoint function NOAA
00217     // reference: http://wahiduddin.net/calc/density_algorithms.htm    
00218     double A0= 373.15/(273.15 + (double)theTempIs);
00219     double SUM = -7.90298 * (A0-1);
00220     SUM += 5.02808 * log10(A0);
00221     SUM += -1.3816e-7 * (pow(10, (11.344*(1-1/A0)))-1) ;
00222     SUM += 8.1328e-3 * (pow(10,(-3.49149*(A0-1)))-1) ;
00223     SUM += log10(1013.246);
00224     double VP = pow(10, SUM-3) * theHumIs;
00225     double T = log(VP/0.61078);   // temp var
00226     return (241.88 * T) / (17.558-T);
00227 }
00228 
00229 float htu21d::getDewPtFast() {
00230     // delta max = 0.6544 wrt dewPoint()
00231     // 5x faster than dewPoint()
00232     // reference: http://en.wikipedia.org/wiki/Dew_point
00233     double h21DtzA = 17.271;
00234     double h21DtzB = 237.7;
00235     double h21DtzC = (h21DtzA * theTempIs) / (h21DtzB + theTempIs) + log(theHumIs/100);
00236     double h21DtzD = (h21DtzB * h21DtzC) / (h21DtzA - h21DtzC);
00237     return (h21DtzD);
00238 }
00239 
00240 //--------------------------------------------------------------------------------------------------------------------------------------//
00241 //Get the HTU21D serial number registers. Returns 64 bit register.
00242 //should return 0x4854 00xx xxxx 32xx
00243 
00244 void htu21d::getSNReg() {
00245     //get 16 bit SNC register, 8 bit SNC-CRC, 16 bit SNA register, 8 bit SNA-CRC
00246 #if defined HTU21Di2cLOWLEVEL
00247     int htu21 = 0;
00248     _i2c.start();
00249     htu21 = _i2c.write(HTU21Di2cWRITE);     //i2c, 1 = ack
00250     if(htu21 == 1) {
00251         _i2c.write(HTU21SNAC1);
00252         _i2c.write(HTU21SNAC2);
00253         _i2c.start();
00254         htu21 = _i2c.write(HTU21Di2cREAD);
00255         HTU21sn.HTU21D_snc = _i2c.read(1) << 8;
00256         HTU21sn.HTU21D_snc |= _i2c.read(1);
00257         HTU21sn.HTU21D_crcc = _i2c.read(1);
00258         HTU21sn.HTU21D_sna = _i2c.read(1) << 8;
00259         HTU21sn.HTU21D_sna |= _i2c.read(1);
00260         HTU21sn.HTU21D_crca = _i2c.read(0);
00261         _i2c.stop();
00262     } else {
00263         HTU21sn.HTU21D_snc = HTU21sn.HTU21D_crcc = HTU21sn.HTU21D_sna = HTU21sn.HTU21D_crca = 0;
00264     }
00265 #else
00266     htuBuffer[0] = HTU21SNAC1;
00267     htuBuffer[1] = HTU21SNAC2;
00268     _i2c.write(HTU21Di2cWRITE, htuBuffer, 2, true);
00269     if(!(_i2c.read(HTU21Di2cREAD, htuBuffer, 6, false))) {
00270         HTU21sn.HTU21D_snc = (htuBuffer[0] << 8) | htuBuffer[1];
00271         HTU21sn.HTU21D_crcc = htuBuffer[2];
00272         HTU21sn.HTU21D_sna = (htuBuffer[3] << 8) | htuBuffer[4];
00273         HTU21sn.HTU21D_crca = htuBuffer[5];
00274     } else {
00275         HTU21sn.HTU21D_snc = HTU21sn.HTU21D_crcc = HTU21sn.HTU21D_sna = HTU21sn.HTU21D_crca = 0;
00276     }
00277 #endif
00278     
00279     //get 32 bit SNB register, 32 bit SNB-CRC - regs are intermixed
00280 #if defined HTU21Di2cLOWLEVEL
00281     htu21 = 0;
00282     _i2c.start();
00283     htu21 = _i2c.write(HTU21Di2cWRITE);     //i2c, 1 = ack
00284     if(htu21 == 1) {
00285         _i2c.write(HTU21SNB1);
00286         _i2c.write(HTU21SNB2);
00287         _i2c.start();
00288         htu21 = _i2c.write(HTU21Di2cREAD);
00289         HTU21sn.HTU21D_snb = _i2c.read(1) << 24;
00290         HTU21sn.HTU21D_crcb = _i2c.read(1) << 24;
00291         HTU21sn.HTU21D_snb |= _i2c.read(1) << 16;
00292         HTU21sn.HTU21D_crcb |= _i2c.read(1) << 16;
00293         HTU21sn.HTU21D_snb |= _i2c.read(1) << 8;
00294         HTU21sn.HTU21D_crcb |= _i2c.read(1) << 8;
00295         HTU21sn.HTU21D_snb |= _i2c.read(1);
00296         HTU21sn.HTU21D_crcb |= _i2c.read(0);
00297         _i2c.stop();
00298     } else {
00299         HTU21sn.HTU21D_snb = HTU21sn.HTU21D_crcb = 0;
00300     }
00301 #else
00302     htuBuffer[0] = HTU21SNB1;
00303     htuBuffer[1] = HTU21SNB2;
00304     _i2c.write(HTU21Di2cWRITE, htuBuffer, 2, true);
00305     if(!(_i2c.read(HTU21Di2cREAD, htuBuffer, 8, false))) {
00306         HTU21sn.HTU21D_snb = (htuBuffer[0] << 24) | (htuBuffer[2] << 16) | (htuBuffer[4] << 8) | htuBuffer[6];
00307         HTU21sn.HTU21D_crcb = (htuBuffer[1] << 24) | (htuBuffer[3] << 16) | (htuBuffer[5] << 8) | htuBuffer[7];
00308     } else {
00309         HTU21sn.HTU21D_snb = HTU21sn.HTU21D_crcb = 0;
00310     }
00311 #endif
00312 }
00313