diff --git a/examples/htu21d.cxx b/examples/htu21d.cxx old mode 100755 new mode 100644 index bf8f2248..63d6fdf6 --- a/examples/htu21d.cxx +++ b/examples/htu21d.cxx @@ -24,18 +24,19 @@ #include #include -#include "htu21d.h" #include -int doWork = 0; +#include "htu21d.h" + +volatile int doWork = 0; + upm::HTU21D *sensor = NULL; void sig_handler(int signo) { - printf("got signal\n"); if (signo == SIGINT) { - printf("exiting application\n"); + printf("\nCtrl-C received.\n"); doWork = 1; } } @@ -43,24 +44,30 @@ sig_handler(int signo) int main(int argc, char **argv) { + // Register signal handler + signal(SIGINT, sig_handler); + //! [Interesting] - int32_t humidity = 0; - int32_t temperature = 0; - int32_t compRH = 0; + float humidity = 0.0; + float temperature = 0.0; + float compRH = 0.0; sensor = new upm::HTU21D(0, HTU21D_I2C_ADDRESS); + sensor->testSensor(); + while (!doWork) { - humidity = sensor->getRHumidity(&temperature); - compRH = sensor->getCompRH(); + compRH = sensor->getCompRH(true); + humidity = sensor->getHumidity(false); + temperature = sensor->getTemperature(false); std::cout << "humidity value = " << - (float)humidity / 1000.0 << + humidity << ", temperature value = " << - (float)temperature / 1000.0 << + temperature << ", compensated RH value = " << - (float)compRH / 1000.0 << std::endl; - usleep (100000); + compRH << std::endl; + usleep (500000); } //! [Interesting] diff --git a/src/htu21d/htu21d.cpp b/src/htu21d/htu21d.cpp index 0794d43b..3f68d4c7 100644 --- a/src/htu21d/htu21d.cpp +++ b/src/htu21d/htu21d.cpp @@ -2,23 +2,23 @@ * Author: William Penner * Copyright (c) 2014 Intel Corporation. * - * This driver supports the HTU21D digital humidity and temperature - * sensor. The datasheet is available from: - * http://www.meas-spec.com/downloads/HTU21D.pdf + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. */ #include @@ -44,32 +44,38 @@ HTU21D::HTU21D(int bus, int devAddr) { if (ret != MRAA_SUCCESS) { fprintf(stderr, "Error accessing i2c bus\n"); } + resetSensor(); } HTU21D::~HTU21D() { mraa_i2c_stop(m_i2ControlCtx); } -int32_t -HTU21D::htu21_temp_ticks_to_millicelsius(int ticks) +int +HTU21D::resetSensor(void) { - ticks &= ~0x0003; /* clear status bits */ - /* - * Formula T = -46.85 + 175.72 * ST / 2^16 from datasheet p14, - * optimized for integer fixed point (3 digits) arithmetic - */ - return ((21965 * (int32_t)ticks) >> 13) - 46850; + uint8_t data; + mraa_i2c_address (m_i2ControlCtx, m_controlAddr); + mraa_i2c_write (m_i2ControlCtx, &data, 1); + usleep(20000); } +/* + * Convert register value to degC * 1000 + */ int32_t -HTU21D::htu21_rh_ticks_to_per_cent_mille(int ticks) +HTU21D::convertTemp(int32_t regval) { - ticks &= ~0x0003; /* clear status bits */ - /* - * Formula RH = -6 + 125 * SRH / 2^16 from datasheet p14, - * optimized for integer fixed point (3 digits) arithmetic - */ - return ((15625 * (int32_t)ticks) >> 13) - 6000; + return ((21965 * (regval & 0xFFFC)) >> 13) - 46850; +} + +/* + * Convert register value to %RH * 1000 + */ +int32_t +HTU21D::convertRH(int regval) +{ + return ((15625 * (regval & 0xFFFC)) >> 13) - 6000; } int @@ -77,40 +83,31 @@ HTU21D::sampleData(void) { uint32_t itemp; - itemp = i2cReadReg_16(HTU21D_T_MEASUREMENT_HM); - m_temperature = htu21_temp_ticks_to_millicelsius(itemp); + itemp = i2cReadReg_16(HTU21D_READ_TEMP_HOLD); + m_temperature = convertTemp(itemp); - itemp = i2cReadReg_16(HTU21D_RH_MEASUREMENT_HM); - m_humidity = htu21_rh_ticks_to_per_cent_mille(itemp); + itemp = i2cReadReg_16(HTU21D_READ_HUMIDITY_HOLD); + m_humidity = convertRH(itemp); return 0; } -int32_t -HTU21D::getTemperature(void) +float +HTU21D::getTemperature(int bSampleData) { - return m_temperature; + if (bSampleData) { + sampleData(); + } + return (float)m_temperature / 1000; } -int32_t -HTU21D::getHumidity(void) +float +HTU21D::getHumidity(int bSampleData) { - return m_humidity; -} - -/* - * This is the primary function to read the data. It will initiate - * a measurement cycle and will then return both the humidity and - * temperature values. piTemperature can be NULL. - */ - -int32_t -HTU21D::getRHumidity(int32_t* piTemperature) -{ - sampleData(); - if (NULL != piTemperature) - *piTemperature = m_temperature; - return m_humidity; + if (bSampleData) { + sampleData(); + } + return (float)m_humidity / 1000; } /* @@ -119,12 +116,30 @@ HTU21D::getRHumidity(int32_t* piTemperature) * RHcomp = RHactualT + (25 - Tactual) * CoeffTemp * RHcomp is in units of %RH * 1000 */ -int32_t -HTU21D::getCompRH(void) +float +HTU21D::getCompRH(int bSampleData) { - return m_humidity + (25000 - m_temperature) * 3 / 20; + if (bSampleData) { + sampleData(); + } + return (float)(m_humidity + (25000 - m_temperature) * 3 / 20) / 1000; } +int +HTU21D::setHeater(int bEnable) +{ + uint8_t userreg; + + userreg = i2cReadReg_8(HTU21D_READ_USER_REG); + if (bEnable) + userreg |= HTU21D_HEATER_ENABLE; + else + userreg &= ~HTU21D_HEATER_ENABLE; + if (i2cWriteReg(HTU21D_WRITE_USER_REG, userreg) < 0) + return -1; + + return 0; +} /* * Test function: when reading the HTU21D many times rapidly should @@ -135,43 +150,50 @@ HTU21D::getCompRH(void) int HTU21D::testSensor(void) { + int i; int iError = 0; - int i, j; - int32_t iTemp, iHum; - int32_t iTempMax, iTempMin; - int32_t iHumMax, iHumMin; - int32_t iHumFirst, iTempFirst; + float fTemp, fHum; + float fTempMax, fTempMin; + float fHumMax, fHumMin; + float fHumFirst, fTempFirst; - fprintf(stdout, "Executing Sensor Test.\n Reading registers 100 times to look for operation\n" ); + fprintf(stdout, "Executing Sensor Test\n" ); - iHum = getRHumidity(&iTemp); - iTempFirst = iTempMax = iTempMin = iTemp; - iHumFirst = iHumMax = iHumMin = iHum; + fHum = getHumidity(true); + fTemp = getTemperature(false); + fTempFirst = fTempMax = fTempMin = fTemp; + fHumFirst = fHumMax = fHumMin = fHum; - for (i=0; i < 100; i++) { - iHum = getRHumidity(&iTemp); - if (iHum < iHumMin) iHumMin = iHum; - if (iHum > iHumMax) iHumMax = iHum; - if (iTemp < iTempMin) iTempMin = iTemp; - if (iTemp > iTempMax) iTempMax = iTemp; -// fprintf(stdout, "Temp: %d Humidity: %d\n", iTemp, iHum); + // Turn on the heater to make a sensor change + setHeater(true); + + // Then sample the sensor a few times + for (i=0; i < 10; i++) { + fHum = getHumidity(true); + fTemp = getTemperature(false); + if (fHum < fHumMin) fHumMin = fHum; + if (fHum > fHumMax) fHumMax = fHum; + if (fTemp < fTempMin) fTempMin = fTemp; + if (fTemp > fTempMax) fTempMax = fTemp; + usleep(50000); } - if ((iTemp - iTempFirst) <= 0) { - fprintf(stdout, "! Temperature should have increased, but didn't\n" ); + // Turn off the heater + setHeater(false); + + // Now check the results + if ((fTemp - fTempFirst) <= 0) { + fprintf(stdout, " Temperature should have increased, but didn't\n" ); iError++; } - - if (iHumMin == iHumMax) { - fprintf(stdout, "! Humidity was unchanged - not working?\n" ); + if (fHumMin == fHumMax) { + fprintf(stdout, " Humidity reading was unchanged - warning\n" ); iError++; } - - if (iTempMin == iTempMax) { - fprintf(stdout, "! Temperature was unchanged - not working?\n" ); + if (fTempMin == fTempMax) { + fprintf(stdout, " Temperature reading was unchanged - warning\n" ); iError++; } - if (iError == 0) { fprintf(stdout, " Device appears functional\n" ); } @@ -185,42 +207,17 @@ HTU21D::testSensor(void) * Functions to read and write data to the i2c device */ -mraa_result_t -HTU21D::i2cReadRegValue(int reg, uint32_t* puint32, int ibytes) { - uint32_t data = 0; - - if (ibytes > 4) - ibytes = 4; - - mraa_i2c_address(m_i2ControlCtx, m_controlAddr); - mraa_i2c_write_byte(m_i2ControlCtx, reg); - - mraa_i2c_address(m_i2ControlCtx, m_controlAddr); - mraa_i2c_read(m_i2ControlCtx, (uint8_t *)&data, ibytes); - - fprintf(stdout, "reg data = %08x\n", data); - *puint32 = be32toh(data) >> ((4-ibytes) * 8); - fprintf(stdout, "reg return = %08x\n", *puint32); - - return MRAA_SUCCESS; -} - mraa_result_t HTU21D::i2cWriteReg (uint8_t reg, uint8_t value) { mraa_result_t error = MRAA_SUCCESS; uint8_t data[2] = { reg, value }; - error = mraa_i2c_address (m_i2ControlCtx, m_controlAddr); + mraa_i2c_address (m_i2ControlCtx, m_controlAddr); error = mraa_i2c_write (m_i2ControlCtx, data, 2); return error; } -/* - * Function to read 16 bits starting at reg. This function - * was replaced due to functionality of using read() to - * access i2c data. - */ uint16_t HTU21D::i2cReadReg_16 (int reg) { uint16_t data; @@ -230,11 +227,6 @@ HTU21D::i2cReadReg_16 (int reg) { return data; } -/* - * Function to read 8 bits starting at reg. This function - * was replaced due to functionality of using read() to - * access i2c data. - */ uint8_t HTU21D::i2cReadReg_8 (int reg) { mraa_i2c_address(m_i2ControlCtx, m_controlAddr); diff --git a/src/htu21d/htu21d.h b/src/htu21d/htu21d.h index 2b2a6a6a..374dd719 100644 --- a/src/htu21d/htu21d.h +++ b/src/htu21d/htu21d.h @@ -2,23 +2,23 @@ * Author: William Penner * Copyright (c) 2014 Intel Corporation. * - * Based on code adapted from the kernel HTU21 driver and - * code by: Yevgeniy Kiveisha - * Copyright (c) 2014 Intel Corporation. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. */ #pragma once @@ -27,12 +27,24 @@ #include #include -#define HTU21D_NAME "htu21d" -#define HTU21D_I2C_ADDRESS 0x40 +#define HTU21D_NAME "htu21d" +#define HTU21D_I2C_ADDRESS 0x40 -/* HTU21 Commands */ -#define HTU21D_T_MEASUREMENT_HM 0xE3 -#define HTU21D_RH_MEASUREMENT_HM 0xE5 +/* HTU21D Commands */ +#define HTU21D_READ_TEMP_HOLD 0xE3 +#define HTU21D_READ_HUMIDITY_HOLD 0xE5 +#define HTU21D_WRITE_USER_REG 0xE6 +#define HTU21D_READ_USER_REG 0xE7 +#define HTU21D_SOFT_RESET 0xFE + +/* User Register Bit Definition */ +#define HTU21D_DISABLE_OTP 0x02 +#define HTU21D_HEATER_ENABLE 0x04 +#define HTU21D_END_OF_BATTERY 0x40 +#define HTU21D_RESO_RH12_T14 0x00 +#define HTU21D_RESO_RH8_T12 0x01 +#define HTU21D_RESO_RH10_T13 0x80 +#define HTU21D_RESO_RH11_T11 0x81 namespace upm { @@ -48,7 +60,13 @@ namespace upm { * (http://www.meas-spec.com/downloads/HTU21D.pdf) * is a digital humidity sensor with temperature output. * RH will report between 0 and 100% and temperature range is - * -40 to +125 degC + * -40 to +125 degC. Note that the getCompRH is the preferred + * function below (passing true to cause a measurement cycle). If + * the actual values used for the compensated ready are necessary, use + * the getHumidity(false) and getTemperature(false) functions following + * the getCompRH call. + * Also note that the sensor should not perform more than a couple of + * measurements per second to limit the heating of the sensor. * * @ingroup htu21d i2c * @snippet htu21d.cxx Interesting @@ -63,7 +81,7 @@ class HTU21D { * @param devAddr address of used i2c device * @param mode HTU21D oversampling */ - HTU21D (int bus=0, int devAddr=HTU21D_I2C_ADDRESS); + HTU21D (int bus, int devAddr=HTU21D_I2C_ADDRESS); /** * HTU21D object destructor, basicaly it close i2c connection. @@ -76,58 +94,47 @@ class HTU21D { * after this call. */ int sampleData(void); - - /** - * Get the current measured humidity [RH * 1000] - * To convert to Relative Humidity, divide by 1000 - * - */ - int32_t getHumidity(void); /** - * Get the humidity cell temperature [degC * 1000] - * To convert to Temperature, divide by 1000 + * Get the current measured humidity [RH] */ - int32_t getTemperature(void); - + float getHumidity(int bSampleData = false); + /** - * Reads both temperature and humidity together - * To convert to Relative Humidity, divide by 1000 - * To convert to Temperature, divide by 1000 - * - * @param pointer to int32_t buffer for temp + * Get the humidity cell temperature [degC] */ - int32_t getRHumidity(int32_t* iTemperature); - + float getTemperature(int bSampleData = false); + /** * Using the current humidity and temperature the function * will calculate the compensated RH using the equation from * the datasheet. */ - int32_t getCompRH(void); - + float getCompRH(int bSampleData = true); + + /** + * Set the heater state. The heater is used to either test + * the sensor functionality since the temp should increase + * 0.5 to 1.5 degC and the humidity should decrease. The + * testSensor() function below will use the heater. + * + * @param bEnable Set to non-zero to turn on heater + */ + int setHeater(int bEnable = false); + + /** + * Perform a soft RESET of the MPL3115A2 device to ensure + * it is in a known state. This function can be used to reset + * the min/max temperature and pressure values. + */ + int resetSensor(void); + /** * Function intended to test the device and verify it * is correctly operating. * */ int testSensor(void); - - /** - * Read 1 to 4 bytes from i2c registers - * - * @param reg address of a register - * @param puint32 pointer to buffer for register data - * @param ibytes number of bytes to be returned - */ - mraa_result_t i2cReadRegValue (int reg, uint32_t* puint32, int ibytes); - - /** - * Read two bytes register - * - * @param reg address of a register - */ - uint16_t i2cReadReg_16 (int reg); /** * Write to one byte register @@ -137,6 +144,13 @@ class HTU21D { */ mraa_result_t i2cWriteReg (uint8_t reg, uint8_t value); + /** + * Read two bytes register + * + * @param reg address of a register + */ + uint16_t i2cReadReg_16 (int reg); + /** * Read one byte register * @@ -147,21 +161,21 @@ class HTU21D { private: /** - * Convert temp register to value * 1000 + * Convert temp register to degC * 1000 */ - int32_t htu21_temp_ticks_to_millicelsius(int ticks); + int32_t convertTemp(int32_t regval); /** - * Convert temp register to value * 1000 + * Convert RH register to %RH * 1000 */ - int32_t htu21_rh_ticks_to_per_cent_mille(int ticks); + int32_t convertRH(int32_t regval); std::string m_name; int m_controlAddr; int m_bus; mraa_i2c_context m_i2ControlCtx; - + int32_t m_temperature; int32_t m_humidity; };