Adafruit_SHT4x.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /*!
  2. * @file Adafruit_SHT4x.cpp
  3. *
  4. * @mainpage Adafruit SHT4x Digital Humidity & Temp Sensor
  5. *
  6. * @section intro_sec Introduction
  7. *
  8. * This is a library for the SHT4x Digital Humidity & Temp Sensor
  9. *
  10. * Designed specifically to work with the SHT4x Digital sensor from Adafruit
  11. *
  12. * Pick one up today in the adafruit shop!
  13. * ------> https://www.adafruit.com/product/4885
  14. *
  15. * These sensors use I2C to communicate, 2 pins are required to interface
  16. *
  17. * Adafruit invests time and resources providing this open source code,
  18. * please support Adafruit andopen-source hardware by purchasing products
  19. * from Adafruit!
  20. *
  21. * @section author Author
  22. *
  23. * Limor Fried/Ladyada (Adafruit Industries).
  24. *
  25. * @section license License
  26. *
  27. * BSD license, all text above must be included in any redistribution
  28. */
  29. #include "Adafruit_SHT4x.h"
  30. static uint8_t crc8(const uint8_t *data, int len);
  31. /*!
  32. * @brief SHT4x constructor
  33. */
  34. Adafruit_SHT4x::Adafruit_SHT4x(void) {}
  35. /*!
  36. * @brief SHT4x destructor
  37. */
  38. Adafruit_SHT4x::~Adafruit_SHT4x(void) {
  39. if (i2c_dev) {
  40. delete i2c_dev; // remove old interface
  41. }
  42. if (temp_sensor) {
  43. delete temp_sensor;
  44. }
  45. if (humidity_sensor) {
  46. delete humidity_sensor;
  47. }
  48. }
  49. /**
  50. * Initialises the I2C bus, and assigns the I2C address to us.
  51. *
  52. * @param theWire The I2C bus to use, defaults to &Wire
  53. *
  54. * @return True if initialisation was successful, otherwise False.
  55. */
  56. bool Adafruit_SHT4x::begin(TwoWire *theWire) {
  57. if (i2c_dev) {
  58. delete i2c_dev; // remove old interface
  59. }
  60. if (temp_sensor) {
  61. delete temp_sensor;
  62. }
  63. if (humidity_sensor) {
  64. delete humidity_sensor;
  65. }
  66. i2c_dev = new Adafruit_I2CDevice(SHT4x_DEFAULT_ADDR, theWire);
  67. if (!i2c_dev->begin()) {
  68. return false;
  69. }
  70. if (!reset()) {
  71. return false;
  72. }
  73. humidity_sensor = new Adafruit_SHT4x_Humidity(this);
  74. temp_sensor = new Adafruit_SHT4x_Temp(this);
  75. return true;
  76. }
  77. /**
  78. * Gets the ID register contents.
  79. *
  80. * @return The 32-bit ID register.
  81. */
  82. uint32_t Adafruit_SHT4x::readSerial(void) {
  83. uint8_t cmd = SHT4x_READSERIAL;
  84. uint8_t reply[6];
  85. if (!i2c_dev->write(&cmd, 1)) {
  86. return false;
  87. }
  88. delay(10);
  89. if (!i2c_dev->read(reply, 6)) {
  90. return false;
  91. }
  92. if ((crc8(reply, 2) != reply[2]) || (crc8(reply + 3, 2) != reply[5])) {
  93. return false;
  94. }
  95. uint32_t serial = 0;
  96. serial = reply[0];
  97. serial <<= 8;
  98. serial |= reply[1];
  99. serial <<= 8;
  100. serial |= reply[3];
  101. serial <<= 8;
  102. serial |= reply[4];
  103. return serial;
  104. }
  105. /**
  106. * Performs a soft reset of the sensor to put it into a known state.
  107. * @returns True on success, false if could not communicate with chip
  108. */
  109. bool Adafruit_SHT4x::reset(void) {
  110. uint8_t cmd = SHT4x_SOFTRESET;
  111. if (!i2c_dev->write(&cmd, 1)) {
  112. return false;
  113. }
  114. delay(1);
  115. return true;
  116. }
  117. /**************************************************************************/
  118. /*!
  119. @brief Sets the precision rating - more precise takes longer!
  120. @param prec The desired precision setting, will be used during reads
  121. */
  122. /**************************************************************************/
  123. void Adafruit_SHT4x::setPrecision(sht4x_precision_t prec) { _precision = prec; }
  124. /**************************************************************************/
  125. /*!
  126. @brief Gets the precision rating - more precise takes longer!
  127. @returns The current precision setting, will be used during reads
  128. */
  129. /**************************************************************************/
  130. sht4x_precision_t Adafruit_SHT4x::getPrecision(void) { return _precision; }
  131. /**************************************************************************/
  132. /*!
  133. @brief Sets the heating setting - more heating uses more power and takes
  134. longer
  135. @param heat The desired heater setting, will be used during reads
  136. */
  137. /**************************************************************************/
  138. void Adafruit_SHT4x::setHeater(sht4x_heater_t heat) { _heater = heat; }
  139. /**************************************************************************/
  140. /*!
  141. @brief Gets the heating setting - more heating uses more power and takes
  142. longer
  143. @returns The current heater setting, will be used during reads
  144. */
  145. /**************************************************************************/
  146. sht4x_heater_t Adafruit_SHT4x::getHeater(void) { return _heater; }
  147. /**************************************************************************/
  148. /*!
  149. @brief Gets the humidity sensor and temperature values as sensor events
  150. @param humidity Sensor event object that will be populated with humidity
  151. data
  152. @param temp Sensor event object that will be populated with temp data
  153. @returns true if the event data was read successfully
  154. */
  155. /**************************************************************************/
  156. bool Adafruit_SHT4x::getEvent(sensors_event_t *humidity,
  157. sensors_event_t *temp) {
  158. uint32_t t = millis();
  159. uint8_t readbuffer[6];
  160. uint8_t cmd = SHT4x_NOHEAT_HIGHPRECISION;
  161. uint16_t duration = 10;
  162. if (_heater == SHT4X_NO_HEATER) {
  163. if (_precision == SHT4X_HIGH_PRECISION) {
  164. cmd = SHT4x_NOHEAT_HIGHPRECISION;
  165. duration = 10;
  166. }
  167. if (_precision == SHT4X_MED_PRECISION) {
  168. cmd = SHT4x_NOHEAT_MEDPRECISION;
  169. duration = 5;
  170. }
  171. if (_precision == SHT4X_LOW_PRECISION) {
  172. cmd = SHT4x_NOHEAT_LOWPRECISION;
  173. duration = 2;
  174. }
  175. }
  176. if (_heater == SHT4X_HIGH_HEATER_1S) {
  177. cmd = SHT4x_HIGHHEAT_1S;
  178. duration = 1100;
  179. }
  180. if (_heater == SHT4X_HIGH_HEATER_100MS) {
  181. cmd = SHT4x_HIGHHEAT_100MS;
  182. duration = 110;
  183. }
  184. if (_heater == SHT4X_MED_HEATER_1S) {
  185. cmd = SHT4x_MEDHEAT_1S;
  186. duration = 1100;
  187. }
  188. if (_heater == SHT4X_MED_HEATER_100MS) {
  189. cmd = SHT4x_MEDHEAT_100MS;
  190. duration = 110;
  191. }
  192. if (_heater == SHT4X_LOW_HEATER_1S) {
  193. cmd = SHT4x_LOWHEAT_1S;
  194. duration = 1100;
  195. }
  196. if (_heater == SHT4X_LOW_HEATER_100MS) {
  197. cmd = SHT4x_LOWHEAT_100MS;
  198. duration = 110;
  199. }
  200. if (!i2c_dev->write(&cmd, 1)) {
  201. return false;
  202. }
  203. delay(duration);
  204. if (!i2c_dev->read(readbuffer, 6)) {
  205. return false;
  206. }
  207. if (readbuffer[2] != crc8(readbuffer, 2) ||
  208. readbuffer[5] != crc8(readbuffer + 3, 2))
  209. return false;
  210. float t_ticks = (uint16_t)readbuffer[0] * 256 + (uint16_t)readbuffer[1];
  211. float rh_ticks = (uint16_t)readbuffer[3] * 256 + (uint16_t)readbuffer[4];
  212. _temperature = -45 + 175 * t_ticks / 65535;
  213. _humidity = -6 + 125 * rh_ticks / 65535;
  214. _humidity = min(max(_humidity, (float)0.0), (float)100.0);
  215. // use helpers to fill in the events
  216. if (temp)
  217. fillTempEvent(temp, t);
  218. if (humidity)
  219. fillHumidityEvent(humidity, t);
  220. return true;
  221. }
  222. void Adafruit_SHT4x::fillTempEvent(sensors_event_t *temp, uint32_t timestamp) {
  223. memset(temp, 0, sizeof(sensors_event_t));
  224. temp->version = sizeof(sensors_event_t);
  225. temp->sensor_id = _sensorid_temp;
  226. temp->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
  227. temp->timestamp = timestamp;
  228. temp->temperature = _temperature;
  229. }
  230. void Adafruit_SHT4x::fillHumidityEvent(sensors_event_t *humidity,
  231. uint32_t timestamp) {
  232. memset(humidity, 0, sizeof(sensors_event_t));
  233. humidity->version = sizeof(sensors_event_t);
  234. humidity->sensor_id = _sensorid_humidity;
  235. humidity->type = SENSOR_TYPE_RELATIVE_HUMIDITY;
  236. humidity->timestamp = timestamp;
  237. humidity->relative_humidity = _humidity;
  238. }
  239. /**
  240. * @brief Gets the Adafruit_Sensor object for the SHT4x's humidity sensor
  241. *
  242. * @return Adafruit_Sensor*
  243. */
  244. Adafruit_Sensor *Adafruit_SHT4x::getHumiditySensor(void) {
  245. return humidity_sensor;
  246. }
  247. /**
  248. * @brief Gets the Adafruit_Sensor object for the SHT4x's temperature sensor
  249. *
  250. * @return Adafruit_Sensor*
  251. */
  252. Adafruit_Sensor *Adafruit_SHT4x::getTemperatureSensor(void) {
  253. return temp_sensor;
  254. }
  255. /**
  256. * @brief Gets the sensor_t object describing the SHT4x's humidity sensor
  257. *
  258. * @param sensor The sensor_t object to be populated
  259. */
  260. void Adafruit_SHT4x_Humidity::getSensor(sensor_t *sensor) {
  261. /* Clear the sensor_t object */
  262. memset(sensor, 0, sizeof(sensor_t));
  263. /* Insert the sensor name in the fixed length char array */
  264. strncpy(sensor->name, "SHT4x_H", sizeof(sensor->name) - 1);
  265. sensor->name[sizeof(sensor->name) - 1] = 0;
  266. sensor->version = 1;
  267. sensor->sensor_id = _sensorID;
  268. sensor->type = SENSOR_TYPE_RELATIVE_HUMIDITY;
  269. sensor->min_delay = 0;
  270. sensor->min_value = 0;
  271. sensor->max_value = 100;
  272. sensor->resolution = 2;
  273. }
  274. /**
  275. @brief Gets the humidity as a standard sensor event
  276. @param event Sensor event object that will be populated
  277. @returns True
  278. */
  279. bool Adafruit_SHT4x_Humidity::getEvent(sensors_event_t *event) {
  280. _theSHT4x->getEvent(event, NULL);
  281. return true;
  282. }
  283. /**
  284. * @brief Gets the sensor_t object describing the SHT4x's tenperature sensor
  285. *
  286. * @param sensor The sensor_t object to be populated
  287. */
  288. void Adafruit_SHT4x_Temp::getSensor(sensor_t *sensor) {
  289. /* Clear the sensor_t object */
  290. memset(sensor, 0, sizeof(sensor_t));
  291. /* Insert the sensor name in the fixed length char array */
  292. strncpy(sensor->name, "SHT4x_T", sizeof(sensor->name) - 1);
  293. sensor->name[sizeof(sensor->name) - 1] = 0;
  294. sensor->version = 1;
  295. sensor->sensor_id = _sensorID;
  296. sensor->type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
  297. sensor->min_delay = 0;
  298. sensor->min_value = -40;
  299. sensor->max_value = 85;
  300. sensor->resolution = 0.3; // depends on calibration data?
  301. }
  302. /*!
  303. @brief Gets the temperature as a standard sensor event
  304. @param event Sensor event object that will be populated
  305. @returns true
  306. */
  307. bool Adafruit_SHT4x_Temp::getEvent(sensors_event_t *event) {
  308. _theSHT4x->getEvent(NULL, event);
  309. return true;
  310. }
  311. /**
  312. * Internal function to perform an I2C write.
  313. *
  314. * @param cmd The 16-bit command ID to send.
  315. */
  316. bool Adafruit_SHT4x::writeCommand(uint16_t command) {
  317. uint8_t cmd[2];
  318. cmd[0] = command >> 8;
  319. cmd[1] = command & 0xFF;
  320. return i2c_dev->write(cmd, 2);
  321. }
  322. /**
  323. * Internal function to perform an I2C read.
  324. *
  325. * @param cmd The 16-bit command ID to send.
  326. */
  327. bool Adafruit_SHT4x::readCommand(uint16_t command, uint8_t *buffer,
  328. uint8_t num_bytes) {
  329. uint8_t cmd[2];
  330. cmd[0] = command >> 8;
  331. cmd[1] = command & 0xFF;
  332. return i2c_dev->write_then_read(cmd, 2, buffer, num_bytes);
  333. }
  334. /**
  335. * Performs a CRC8 calculation on the supplied values.
  336. *
  337. * @param data Pointer to the data to use when calculating the CRC8.
  338. * @param len The number of bytes in 'data'.
  339. *
  340. * @return The computed CRC8 value.
  341. */
  342. static uint8_t crc8(const uint8_t *data, int len) {
  343. /*
  344. *
  345. * CRC-8 formula from page 14 of SHT spec pdf
  346. *
  347. * Test data 0xBE, 0xEF should yield 0x92
  348. *
  349. * Initialization data 0xFF
  350. * Polynomial 0x31 (x8 + x5 +x4 +1)
  351. * Final XOR 0x00
  352. */
  353. const uint8_t POLYNOMIAL(0x31);
  354. uint8_t crc(0xFF);
  355. for (int j = len; j; --j) {
  356. crc ^= *data++;
  357. for (int i = 8; i; --i) {
  358. crc = (crc & 0x80) ? (crc << 1) ^ POLYNOMIAL : (crc << 1);
  359. }
  360. }
  361. return crc;
  362. }