// ----------------------------------------------------------------------------- // HDC1080 / 831R Sensor over I2C // Based on SI7021 / HTU21D Sensor over I2C // Copyright (C) 2017-2019 by Xose PĂ©rez // Copyright (C) 2020 by Alexander Kolesnikov // ----------------------------------------------------------------------------- #if SENSOR_SUPPORT && HDC1080_SUPPORT #pragma once #include "I2CSensor.h" #include "../utils.h" #define HDC1080_SCL_FREQUENCY 200 // ref. http://www.ti.com/lit/ds/symlink/hdc1080.pdf // Device ID. Should be the same for every device. #define HDC1080_DEVICE_ID 0x1050 #define HDC1080_CMD_TMP 0x00 #define HDC1080_CMD_HUM 0x01 class HDC1080Sensor : public I2CSensor<> { public: // --------------------------------------------------------------------- // Public // --------------------------------------------------------------------- HDC1080Sensor() { _sensor_id = SENSOR_HDC1080_ID; } // --------------------------------------------------------------------- // Sensor API // --------------------------------------------------------------------- // Initialization method, must be idempotent void begin() { if (!_dirty) return; _init(); _dirty = !_ready; } // Descriptive name of the sensor String description() { char buffer[25]; snprintf_P(buffer, sizeof(buffer), PSTR("HDC1080 @ I2C (0x%02X)"), _address); return String(buffer); } // Descriptive name of the slot # index String description(unsigned char index) { return description(); }; // Type for slot # index unsigned char type(unsigned char index) { if (index == 0) return MAGNITUDE_TEMPERATURE; if (index == 1) return MAGNITUDE_HUMIDITY; return MAGNITUDE_NONE; } // Pre-read hook (usually to populate registers with up-to-date data) void pre() { _error = SENSOR_ERROR_OK; double value; value = _read(HDC1080_CMD_TMP); if (_error != SENSOR_ERROR_OK) return; _temperature = (165 * value / 65536) - 40; value = _read(HDC1080_CMD_HUM); if (_error != SENSOR_ERROR_OK) return; value = (value / 65536)*100; _humidity = constrain(value, 0, 100); } // Current value for slot # index double value(unsigned char index) { if (index == 0) return _temperature; if (index == 1) return _humidity; return 0; } protected: // --------------------------------------------------------------------- // Protected // --------------------------------------------------------------------- void _init() { // I2C auto-discover unsigned char addresses[] = {0x40}; _address = _begin_i2c(_address, sizeof(addresses), addresses); if (_address == 0) return; // Check device ID before doing anything else // ref. https://github.com/xoseperez/espurna/issues/2270#issuecomment-639239944 // > Also there are clones of HDC1080 and they may have different Device ID // > values. You need to check it by reading and debug output this bytes. i2c_write_uint8(_address, 0xFF); _device_id = i2c_read_uint16(_address); if (_device_id == HDC1080_DEVICE_ID) { _ready = true; _count = 2; return; } DEBUG_MSG_P(PSTR("[HDC1080] ERROR: Expected Device ID %04X, received %04X\n"), HDC1080_DEVICE_ID, _device_id); _count = 0; i2cReleaseLock(_address); _previous_address = 0; _error = SENSOR_ERROR_UNKNOWN_ID; // Setting _address to 0 forces auto-discover // This might be necessary at this stage if there is a // different sensor in the hardcoded address _address = 0; _ready = false; } unsigned int _read(uint8_t command) { // Request measurement i2c_write_uint8(_address, command); // When not using clock stretching (*_NOHOLD commands) delay here // is needed to wait for the measurement. // According to datasheet the max. conversion time is ~22ms nice_delay(50); // Clear the last to bits of LSB to 00. // According to datasheet LSB of Temp and RH is always xxxxxx00 unsigned int value = i2c_read_uint16(_address) & 0xFFFC; // We should be checking there are no pending bytes in the buffer // and raise a CRC error if there are _error = SENSOR_ERROR_OK; return value; } uint16_t _device_id = 0; double _temperature = 0; double _humidity = 0; }; #endif // SENSOR_SUPPORT && HDC1080_SUPPORT