/* SHT2x - Humidity Library for Arduino. Get humidity and temperature from the HTU21D/SHT2x sensors. Hardware Setup: Attach the SDA pin to A4, SCL to A5. Software: Call SHT2x.Begin() in setup. SHT2x.ReadHumidity() will return a float containing the humidity. Ex: 54.7 SHT2x.ReadTemperature() will return a float containing the temperature in Celsius. Ex: 24.1 SHT2x.SetResolution(byte: 0b.76543210) sets the resolution of the readings. Copyright (C) 2015 Nuno Chaveiro nchaveiro[at]gmail.com Lisbon, Portugal Copyright (C) 2020 Thomas Buck */ #include #include "SHT2x.h" SHT2x::SHT2x(uint8_t _addr, TwoWire* _wire) { addr = _addr; wire = _wire; } void SHT2x::begin(void) { wire->begin(); } bool SHT2x::GetAlive(void) { uint16_t r = readSensor(TRIGGER_TEMP_MEASURE_HOLD); if ((r == ERROR_TIMEOUT) || (r == ERROR_CRC)) { return false; } return true; } /********************************************************** * GetHumidity * Gets the current humidity from the sensor. * * @return float - The relative humidity in %RH **********************************************************/ float SHT2x::GetHumidity(void) { return (-6.0 + 125.0 / 65536.0 * (float)(readSensor(TRIGGER_HUMD_MEASURE_HOLD))); } /********************************************************** * GetTemperature * Gets the current temperature from the sensor. * * @return float - The temperature in Deg C **********************************************************/ float SHT2x::GetTemperature(void) { return (-46.85 + 175.72 / 65536.0 * (float)(readSensor(TRIGGER_TEMP_MEASURE_HOLD))); } /********************************************************** * Sets the sensor resolution to one of four levels: * 0/0 = 12bit RH, 14bit Temp * 0/1 = 8bit RH, 12bit Temp * 1/0 = 10bit RH, 13bit Temp * 1/1 = 11bit RH, 11bit Temp * Power on default is 0/0 **********************************************************/ void SHT2x::setResolution(uint8_t resolution) { uint8_t userRegister = read_user_register(); //Go get the current register state userRegister &= B01111110; //Turn off the resolution bits resolution &= B10000001; //Turn off all other bits but resolution bits userRegister |= resolution; //Mask in the requested resolution bits //Request a write to user register wire->beginTransmission(addr); wire->write(WRITE_USER_REG); //Write to the user register wire->write(userRegister); //Write the new resolution bits wire->endTransmission(); } uint8_t SHT2x::read_user_register(void) { uint8_t userRegister; //Request the user register wire->beginTransmission(addr); wire->write(READ_USER_REG); //Read the user register wire->endTransmission(); //Read result wire->requestFrom(addr, 1); userRegister = wire->read(); return userRegister; } uint16_t SHT2x::readSensor(uint8_t command) { uint16_t result; wire->beginTransmission(addr); //begin wire->write(command); //send the pointer location wire->endTransmission(); //end //Hang out while measurement is taken. 50mS max, page 4 of datasheet. delay(55); //Comes back in three bytes, data(MSB) / data(LSB) / Checksum wire->requestFrom(addr, 3); //Wait for data to become available int counter = 0; while (wire->available() < 3) { counter++; delay(1); if(counter > 100) return ERROR_TIMEOUT; //Error timout } //Store the result result = ((wire->read()) << 8); result |= wire->read(); //Check validity uint8_t checksum = wire->read(); if(check_crc(result, checksum) != 0) return(ERROR_CRC); //Error checksum //sensorStatus = rawTemperature & 0x0003; //get status bits result &= ~0x0003; // clear two low bits (status bits) return result; } //Give this function the 2 byte message (measurement) and the check_value byte from the HTU21D //If it returns 0, then the transmission was good //If it returns something other than 0, then the communication was corrupted //From: http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html //POLYNOMIAL = 0x0131 = x^8 + x^5 + x^4 + 1 : http://en.wikipedia.org/wiki/Computation_of_cyclic_redundancy_checks #define SHIFTED_DIVISOR 0x988000 // This is the 0x0131 polynomial shifted to farthest left of three bytes uint8_t SHT2x::check_crc(uint16_t message_from_sensor, uint8_t check_value_from_sensor) { // Pad with 8 bits because we have to add in the check value uint32_t remainder = (uint32_t)message_from_sensor << 8; // Add on the check value remainder |= check_value_from_sensor; uint32_t divsor = (uint32_t)SHIFTED_DIVISOR; // Operate on only 16 positions of max 24. // The remaining 8 are our remainder and should be zero when we're done. for (int i = 0; i < 16; i++) { // Check if there is a one in the left position if (remainder & ((uint32_t)1 << (23 - i))) { remainder ^= divsor; } // Rotate the divsor max 16 times so that we have 8 bits left of a remainder divsor >>= 1; } return (uint8_t)remainder; }