diff --git a/docs/images/htu21d.jpeg b/docs/images/htu21d.jpeg new file mode 100644 index 00000000..a76649d4 Binary files /dev/null and b/docs/images/htu21d.jpeg differ diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f021c46b..d6548391 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -42,6 +42,7 @@ add_executable (joystick12-example joystick12-example.cxx) add_executable (lol-example lol-example.cxx) add_executable (nrf_ble_broadcast-example ble_broadcast.cxx) add_executable (tsl2561-example tsl2561.cxx) +add_executable (htu21d-example htu21d.cxx) include_directories (${PROJECT_SOURCE_DIR}/src/hmc5883l) include_directories (${PROJECT_SOURCE_DIR}/src/grove) @@ -75,6 +76,7 @@ include_directories (${PROJECT_SOURCE_DIR}/src/lsm303) include_directories (${PROJECT_SOURCE_DIR}/src/joystick12) include_directories (${PROJECT_SOURCE_DIR}/src/lol) include_directories (${PROJECT_SOURCE_DIR}/src/tsl2561) +include_directories (${PROJECT_SOURCE_DIR}/src/htu21d) target_link_libraries (hmc5883l-example hmc5883l ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (groveled-example grove ${CMAKE_THREAD_LIBS_INIT}) @@ -120,3 +122,4 @@ target_link_libraries (joystick12-example joystick12 ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (lol-example lol ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (nrf_ble_broadcast-example nrf24l01 ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (tsl2561-example tsl2561 ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (htu21d-example htu21d ${CMAKE_THREAD_LIBS_INIT}) diff --git a/examples/htu21d.cxx b/examples/htu21d.cxx new file mode 100755 index 00000000..bf8f2248 --- /dev/null +++ b/examples/htu21d.cxx @@ -0,0 +1,72 @@ +/* + * Author: William Penner + * 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: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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 +#include +#include "htu21d.h" +#include + +int doWork = 0; +upm::HTU21D *sensor = NULL; + +void +sig_handler(int signo) +{ + printf("got signal\n"); + if (signo == SIGINT) { + printf("exiting application\n"); + doWork = 1; + } +} + +int +main(int argc, char **argv) +{ + //! [Interesting] + int32_t humidity = 0; + int32_t temperature = 0; + int32_t compRH = 0; + + sensor = new upm::HTU21D(0, HTU21D_I2C_ADDRESS); + + while (!doWork) { + humidity = sensor->getRHumidity(&temperature); + compRH = sensor->getCompRH(); + + std::cout << "humidity value = " << + (float)humidity / 1000.0 << + ", temperature value = " << + (float)temperature / 1000.0 << + ", compensated RH value = " << + (float)compRH / 1000.0 << std::endl; + usleep (100000); + } + //! [Interesting] + + std::cout << "exiting application" << std::endl; + + delete sensor; + + return 0; +} diff --git a/src/htu21d/CMakeLists.txt b/src/htu21d/CMakeLists.txt new file mode 100644 index 00000000..4385a1f9 --- /dev/null +++ b/src/htu21d/CMakeLists.txt @@ -0,0 +1,5 @@ +set (libname "htu21d") +set (libdescription "libupm Humidity Sensor") +set (module_src ${libname}.cpp) +set (module_h ${libname}.h) +upm_module_init() diff --git a/src/htu21d/htu21d.cpp b/src/htu21d/htu21d.cpp new file mode 100644 index 00000000..0794d43b --- /dev/null +++ b/src/htu21d/htu21d.cpp @@ -0,0 +1,243 @@ +/* + * 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 + * + * 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. + * + * 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. + */ + +#include +#include +#include + +#include "htu21d.h" + +using namespace upm; + +HTU21D::HTU21D(int bus, int devAddr) { + m_temperature = 0; + m_humidity = 0; + + m_name = HTU21D_NAME; + + m_controlAddr = devAddr; + m_bus = bus; + + m_i2ControlCtx = mraa_i2c_init(m_bus); + + mraa_result_t ret = mraa_i2c_address(m_i2ControlCtx, m_controlAddr); + if (ret != MRAA_SUCCESS) { + fprintf(stderr, "Error accessing i2c bus\n"); + } +} + +HTU21D::~HTU21D() { + mraa_i2c_stop(m_i2ControlCtx); +} + +int32_t +HTU21D::htu21_temp_ticks_to_millicelsius(int ticks) +{ + 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; +} + +int32_t +HTU21D::htu21_rh_ticks_to_per_cent_mille(int ticks) +{ + 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; +} + +int +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_RH_MEASUREMENT_HM); + m_humidity = htu21_rh_ticks_to_per_cent_mille(itemp); + + return 0; +} + +int32_t +HTU21D::getTemperature(void) +{ + return m_temperature; +} + +int32_t +HTU21D::getHumidity(void) +{ + 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; +} + +/* + * Use the compensation equation from the datasheet to correct the + * current reading + * RHcomp = RHactualT + (25 - Tactual) * CoeffTemp + * RHcomp is in units of %RH * 1000 + */ +int32_t +HTU21D::getCompRH(void) +{ + return m_humidity + (25000 - m_temperature) * 3 / 20; +} + + +/* + * Test function: when reading the HTU21D many times rapidly should + * result in a temperature increase. This test will verify that the + * value is changing from read to read + */ + +int +HTU21D::testSensor(void) +{ + int iError = 0; + int i, j; + int32_t iTemp, iHum; + int32_t iTempMax, iTempMin; + int32_t iHumMax, iHumMin; + int32_t iHumFirst, iTempFirst; + + fprintf(stdout, "Executing Sensor Test.\n Reading registers 100 times to look for operation\n" ); + + iHum = getRHumidity(&iTemp); + iTempFirst = iTempMax = iTempMin = iTemp; + iHumFirst = iHumMax = iHumMin = iHum; + + 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); + } + + if ((iTemp - iTempFirst) <= 0) { + fprintf(stdout, "! Temperature should have increased, but didn't\n" ); + iError++; + } + + if (iHumMin == iHumMax) { + fprintf(stdout, "! Humidity was unchanged - not working?\n" ); + iError++; + } + + if (iTempMin == iTempMax) { + fprintf(stdout, "! Temperature was unchanged - not working?\n" ); + iError++; + } + + if (iError == 0) { + fprintf(stdout, " Device appears functional\n" ); + } + + fprintf(stdout, " Test complete\n" ); + + return iError; +} + +/* + * 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); + 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; + mraa_i2c_address(m_i2ControlCtx, m_controlAddr); + data = (uint16_t)mraa_i2c_read_byte_data(m_i2ControlCtx, reg) << 8; + data |= (uint16_t)mraa_i2c_read_byte_data(m_i2ControlCtx, reg+1); + 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); + return mraa_i2c_read_byte_data(m_i2ControlCtx, reg); +} + diff --git a/src/htu21d/htu21d.h b/src/htu21d/htu21d.h new file mode 100644 index 00000000..2b2a6a6a --- /dev/null +++ b/src/htu21d/htu21d.h @@ -0,0 +1,169 @@ +/* + * 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. + * + * 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. + * + * 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. + */ + +#pragma once + +#include +#include +#include + +#define HTU21D_NAME "htu21d" +#define HTU21D_I2C_ADDRESS 0x40 + +/* HTU21 Commands */ +#define HTU21D_T_MEASUREMENT_HM 0xE3 +#define HTU21D_RH_MEASUREMENT_HM 0xE5 + +namespace upm { + +/** + * @brief HTU21D humidity sensor library + * @defgroup htu21d libupm-htu21 + */ + +/** + * @brief C++ API for HTU21D chip (Atmospheric Pressure Sensor) + * + * Measurement Specialties [HTU21D] + * (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 + * + * @ingroup htu21d i2c + * @snippet htu21d.cxx Interesting + * @image html htu21d.jpeg + */ +class HTU21D { + public: + /** + * Instanciates a HTU21D object + * + * @param bus number of used bus + * @param devAddr address of used i2c device + * @param mode HTU21D oversampling + */ + HTU21D (int bus=0, int devAddr=HTU21D_I2C_ADDRESS); + + /** + * HTU21D object destructor, basicaly it close i2c connection. + */ + ~HTU21D (); + + /** + * Initiate a temp/pressure mesasurement and wait for function + * to complete. The humidity and temp registers can be read + * 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 + */ + int32_t getTemperature(void); + + /** + * 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 + */ + int32_t getRHumidity(int32_t* iTemperature); + + /** + * Using the current humidity and temperature the function + * will calculate the compensated RH using the equation from + * the datasheet. + */ + int32_t getCompRH(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 + * + * @param reg address of a register + * @param value byte to be written + */ + mraa_result_t i2cWriteReg (uint8_t reg, uint8_t value); + + /** + * Read one byte register + * + * @param reg address of a register + */ + uint8_t i2cReadReg_8 (int reg); + + private: + + /** + * Convert temp register to value * 1000 + */ + int32_t htu21_temp_ticks_to_millicelsius(int ticks); + + /** + * Convert temp register to value * 1000 + */ + int32_t htu21_rh_ticks_to_per_cent_mille(int ticks); + + std::string m_name; + + int m_controlAddr; + int m_bus; + mraa_i2c_context m_i2ControlCtx; + + int32_t m_temperature; + int32_t m_humidity; +}; + +} diff --git a/src/htu21d/jsupm_htu21d.i b/src/htu21d/jsupm_htu21d.i new file mode 100644 index 00000000..e6d9c9d4 --- /dev/null +++ b/src/htu21d/jsupm_htu21d.i @@ -0,0 +1,8 @@ +%module jsupm_htu21d +%include "../upm.i" + +%{ + #include "htu21d.h" +%} + +%include "htu21d.h" diff --git a/src/htu21d/pyupm_htu21d.i b/src/htu21d/pyupm_htu21d.i new file mode 100644 index 00000000..dcacae37 --- /dev/null +++ b/src/htu21d/pyupm_htu21d.i @@ -0,0 +1,13 @@ +%module pyupm_htu21d +%include "../upm.i" + +%feature("autodoc", "3"); + +#ifdef DOXYGEN +%include "htu21d_doc.i" +#endif + +%include "htu21d.h" +%{ + #include "htu21d.h" +%}