Adafruit_SHTC3/Adafruit_SHTC3.cpp
2020-05-28 17:24:30 -04:00

338 lines
8.5 KiB
C++

/*!
* @file Adafruit_SHTC3.cpp
*
* @mainpage Adafruit SHTC3 Digital Humidity & Temp Sensor
*
* @section intro_sec Introduction
*
* This is a library for the SHTC3 Digital Humidity & Temp Sensor
*
* Designed specifically to work with the SHTC3 Digital sensor from Adafruit
*
* Pick one up today in the adafruit shop!
* ------> https://www.adafruit.com/product/4636
*
* These sensors use I2C to communicate, 2 pins are required to interface
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit andopen-source hardware by purchasing products
* from Adafruit!
*
* @section author Author
*
* Limor Fried/Ladyada (Adafruit Industries).
*
* @section license License
*
* BSD license, all text above must be included in any redistribution
*/
#include "Adafruit_SHTC3.h"
/*!
* @brief SHTC3 constructor
*/
Adafruit_SHTC3::Adafruit_SHTC3(void) {}
/*!
* @brief SHTC3 destructor
*/
Adafruit_SHTC3::~Adafruit_SHTC3(void) {
if (temp_sensor) {
delete temp_sensor;
}
if (humidity_sensor) {
delete humidity_sensor;
}
}
/**
* Initialises the I2C bus, and assigns the I2C address to us.
*
* @param theWire The I2C bus to use, defaults to &Wire
*
* @return True if initialisation was successful, otherwise False.
*/
bool Adafruit_SHTC3::begin(TwoWire *theWire) {
if (i2c_dev) {
delete i2c_dev; // remove old interface
}
i2c_dev = new Adafruit_I2CDevice(SHTC3_DEFAULT_ADDR, theWire);
if (!i2c_dev->begin()) {
return false;
}
reset();
sleep(false);
// read the ID
if ((readID() & 0x083F) != 0x807) {
return false;
}
humidity_sensor = new Adafruit_SHTC3_Humidity(this);
temp_sensor = new Adafruit_SHTC3_Temp(this);
return true;
}
/**
* @brief Brings the SHTC3 in or out of sleep mode
*
* @param sleepmode If true, go into sleep mode. Else, wakeup
*/
void Adafruit_SHTC3::sleep(bool sleepmode) {
if (sleepmode) {
writeCommand(SHTC3_SLEEP);
} else {
writeCommand(SHTC3_WAKEUP);
delayMicroseconds(250);
}
}
/**
* @brief Tells the SHTC3 to read future data in low power (fast) or normal
* (precise)
*
* @param readmode If true, use low power mode for reads
*/
void Adafruit_SHTC3::lowPowerMode(bool readmode) { _lpMode = readmode; }
/**
* Gets the ID register contents.
*
* @return The 16-bit ID register.
*/
uint16_t Adafruit_SHTC3::readID(void) {
uint8_t data[3];
readCommand(SHTC3_READID, data, 3);
uint16_t id = data[0];
id <<= 8;
id |= data[1];
return id;
}
/**
* Performs a reset of the sensor to put it into a known state.
*/
void Adafruit_SHTC3::reset(void) {
writeCommand(SHTC3_SOFTRESET);
delay(1);
}
/**************************************************************************/
/*!
@brief Gets the humidity sensor and temperature values as sensor events
@param humidity Sensor event object that will be populated with humidity
data
@param temp Sensor event object that will be populated with temp data
@returns true if the event data was read successfully
*/
/**************************************************************************/
bool Adafruit_SHTC3::getEvent(sensors_event_t *humidity,
sensors_event_t *temp) {
uint32_t t = millis();
uint8_t readbuffer[6];
sleep(false);
if (_lpMode) {
// low power
writeCommand(SHTC3_LOWPOW_MEAS_TFIRST);
delay(1);
} else {
writeCommand(SHTC3_NORMAL_MEAS_TFIRST);
delay(13);
}
while (!i2c_dev->read(readbuffer, sizeof(readbuffer))) {
delay(1);
}
if (readbuffer[2] != crc8(readbuffer, 2) ||
readbuffer[5] != crc8(readbuffer + 3, 2))
return false;
int32_t stemp = (int32_t)(((uint32_t)readbuffer[0] << 8) | readbuffer[1]);
// simplified (65536 instead of 65535) integer version of:
// temp = (stemp * 175.0f) / 65535.0f - 45.0f;
stemp = ((4375 * stemp) >> 14) - 4500;
_temperature = (float)stemp / 100.0f;
uint32_t shum = ((uint32_t)readbuffer[3] << 8) | readbuffer[4];
// simplified (65536 instead of 65535) integer version of:
// humidity = (shum * 100.0f) / 65535.0f;
shum = (625 * shum) >> 12;
_humidity = (float)shum / 100.0f;
sleep(true);
// use helpers to fill in the events
if (temp)
fillTempEvent(temp, t);
if (humidity)
fillHumidityEvent(humidity, t);
return true;
}
void Adafruit_SHTC3::fillTempEvent(sensors_event_t *temp, uint32_t timestamp) {
memset(temp, 0, sizeof(sensors_event_t));
temp->version = sizeof(sensors_event_t);
temp->sensor_id = _sensorid_temp;
temp->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
temp->timestamp = timestamp;
temp->temperature = _temperature;
}
void Adafruit_SHTC3::fillHumidityEvent(sensors_event_t *humidity,
uint32_t timestamp) {
memset(humidity, 0, sizeof(sensors_event_t));
humidity->version = sizeof(sensors_event_t);
humidity->sensor_id = _sensorid_humidity;
humidity->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
humidity->timestamp = timestamp;
humidity->relative_humidity = _humidity;
}
/**
* @brief Gets the Adafruit_Sensor object for the SHTC3's humidity sensor
*
* @return Adafruit_Sensor*
*/
Adafruit_Sensor *Adafruit_SHTC3::getHumiditySensor(void) {
return humidity_sensor;
}
/**
* @brief Gets the Adafruit_Sensor object for the SHTC3's humidity sensor
*
* @return Adafruit_Sensor*
*/
Adafruit_Sensor *Adafruit_SHTC3::getTemperatureSensor(void) {
return temp_sensor;
}
/**
* @brief Gets the sensor_t object describing the SHTC3's humidity sensor
*
* @param sensor The sensor_t object to be populated
*/
void Adafruit_SHTC3_Humidity::getSensor(sensor_t *sensor) {
/* Clear the sensor_t object */
memset(sensor, 0, sizeof(sensor_t));
/* Insert the sensor name in the fixed length char array */
strncpy(sensor->name, "SHTC3_H", sizeof(sensor->name) - 1);
sensor->name[sizeof(sensor->name) - 1] = 0;
sensor->version = 1;
sensor->sensor_id = _sensorID;
sensor->type = SENSOR_TYPE_RELATIVE_HUMIDITY;
sensor->min_delay = 0;
sensor->min_value = 0;
sensor->max_value = 100;
sensor->resolution = 2;
}
/**
@brief Gets the humidity as a standard sensor event
@param event Sensor event object that will be populated
@returns True
*/
bool Adafruit_SHTC3_Humidity::getEvent(sensors_event_t *event) {
_theSHTC3->getEvent(event, NULL);
return true;
}
/**
* @brief Gets the sensor_t object describing the SHTC3's tenperature sensor
*
* @param sensor The sensor_t object to be populated
*/
void Adafruit_SHTC3_Temp::getSensor(sensor_t *sensor) {
/* Clear the sensor_t object */
memset(sensor, 0, sizeof(sensor_t));
/* Insert the sensor name in the fixed length char array */
strncpy(sensor->name, "SHTC3_T", sizeof(sensor->name) - 1);
sensor->name[sizeof(sensor->name) - 1] = 0;
sensor->version = 1;
sensor->sensor_id = _sensorID;
sensor->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
sensor->min_delay = 0;
sensor->min_value = -40;
sensor->max_value = 85;
sensor->resolution = 0.3; // depends on calibration data?
}
/*!
@brief Gets the temperature as a standard sensor event
@param event Sensor event object that will be populated
@returns true
*/
bool Adafruit_SHTC3_Temp::getEvent(sensors_event_t *event) {
_theSHTC3->getEvent(NULL, event);
return true;
}
/**
* Internal function to perform and I2C write.
*
* @param cmd The 16-bit command ID to send.
*/
bool Adafruit_SHTC3::writeCommand(uint16_t command) {
uint8_t cmd[2];
cmd[0] = command >> 8;
cmd[1] = command & 0xFF;
return i2c_dev->write(cmd, 2);
}
/**
* Internal function to perform an I2C read.
*
* @param cmd The 16-bit command ID to send.
*/
bool Adafruit_SHTC3::readCommand(uint16_t command, uint8_t *buffer,
uint8_t num_bytes) {
uint8_t cmd[2];
cmd[0] = command >> 8;
cmd[1] = command & 0xFF;
return i2c_dev->write_then_read(cmd, 2, buffer, num_bytes);
}
/**
* Performs a CRC8 calculation on the supplied values.
*
* @param data Pointer to the data to use when calculating the CRC8.
* @param len The number of bytes in 'data'.
*
* @return The computed CRC8 value.
*/
static uint8_t crc8(const uint8_t *data, int len) {
/*
*
* CRC-8 formula from page 14 of SHT spec pdf
*
* Test data 0xBE, 0xEF should yield 0x92
*
* Initialization data 0xFF
* Polynomial 0x31 (x8 + x5 +x4 +1)
* Final XOR 0x00
*/
const uint8_t POLYNOMIAL(0x31);
uint8_t crc(0xFF);
for (int j = len; j; --j) {
crc ^= *data++;
for (int i = 8; i; --i) {
crc = (crc & 0x80) ? (crc << 1) ^ POLYNOMIAL : (crc << 1);
}
}
return crc;
}