From eee6f5a0efb589bf672f540e4aec380205c0e0e5 Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Sat, 17 Sep 2022 13:46:56 +0200 Subject: [PATCH] improve performance read() (#6) * improve performance read() * refactor --- DHT20.cpp | 180 ++++++++++++++++----- DHT20.h | 46 +++--- README.md | 43 +++-- examples/DHT20/DHT20.ino | 6 + examples/DHT20/performance_0.1.2.txt | 15 ++ examples/DHT20/performance_0.1.3.txt | 15 ++ examples/DHT20_test_esp/DHT20_test_esp.ino | 6 + keywords.txt | 7 +- library.json | 2 +- library.properties | 2 +- test/unit_test_001.cpp | 4 +- 11 files changed, 234 insertions(+), 92 deletions(-) create mode 100644 examples/DHT20/performance_0.1.2.txt create mode 100644 examples/DHT20/performance_0.1.3.txt diff --git a/DHT20.cpp b/DHT20.cpp index e4c970e..3fa1570 100644 --- a/DHT20.cpp +++ b/DHT20.cpp @@ -1,7 +1,7 @@ // // FILE: DHT20.cpp // AUTHOR: Rob Tillaart -// VERSION: 0.1.2 +// VERSION: 0.1.3 // PURPOSE: Arduino library for DHT20 I2C temperature and humidity sensor. // // HISTORY: @@ -12,15 +12,16 @@ // fix keywords // add readStatus() fix _readStatus() // add setWireTimeout(250000, true); // in comments +// 0.1.3 2022-09-xx add wrapper status functions +// improve performance read() +// refactor, update readme.md #include "DHT20.h" -#define DHT20_ACQUISITION_TIME 85 // milliseconds - // set DHT20_WIRE_TIME_OUT to 0 to disable. -#define DHT20_WIRE_TIME_OUT 250000 // microseconds +#define DHT20_WIRE_TIME_OUT 250000 // microseconds const uint8_t DHT20_ADDRESS = 0x38; @@ -70,20 +71,28 @@ bool DHT20::isConnected() } +//////////////////////////////////////////////// +// +// READ THE SENSOR +// int DHT20::read() { - // READ SENSOR ==> uses the async interface! - // check lastRead! - int status = _requestData(); + // do not read to fast + if (millis() - _lastRead < 1000) + { + return DHT20_ERROR_LASTREAD; + } + + int status = requestData(); if (status < 0) return status; // wait for measurement ready - while ((millis() - _lastRequest) <= DHT20_ACQUISITION_TIME) + while (isMeasuring()) { yield(); delay(1); } // read the measurement - status = _readData(); + status = readData(); if (status < 0) return status; // convert it to meaningfull data @@ -91,36 +100,7 @@ int DHT20::read() } -int DHT20::convert() -{ - // CONVERT AND STORE - _status = _bits[0]; - uint32_t tmp = _bits[1]; - tmp <<= 8; - tmp += _bits[2]; - tmp <<= 4; - tmp += (_bits[3] >> 4); - _humidity = tmp * 9.5367431640625e-5; // ==> / 1048576.0 * 100%; - - tmp = (_bits[3] & 0x0F); - tmp <<= 8; - tmp += _bits[4]; - tmp <<= 8; - tmp += _bits[5]; - _temperature = tmp * 1.9073486328125e-4 - 50; // ==> / 1048576.0 * 200 - 50; - - // TEST CHECKSUM - uint8_t _crc = _crc8(_bits, 6); - // Serial.print(_crc, HEX); - // Serial.print("\t"); - // Serial.println(_bits[6], HEX); - if (_crc != _bits[6]) return DHT20_ERROR_CHECKSUM; - - return DHT20_OK; -} - - -int DHT20::_requestData() +int DHT20::requestData() { // GET CONNECTION _wire->beginTransmission(DHT20_ADDRESS); @@ -134,7 +114,7 @@ int DHT20::_requestData() } -int DHT20::_readData() +int DHT20::readData() { // GET DATA const uint8_t length = 7; @@ -160,17 +140,133 @@ int DHT20::_readData() } -uint8_t DHT20::_readStatus() +int DHT20::convert() +{ + // CONVERT AND STORE + _status = _bits[0]; + uint32_t raw = _bits[1]; + raw <<= 8; + raw += _bits[2]; + raw <<= 4; + raw += (_bits[3] >> 4); + _humidity = raw * 9.5367431640625e-5; // ==> / 1048576.0 * 100%; + + raw = (_bits[3] & 0x0F); + raw <<= 8; + raw += _bits[4]; + raw <<= 8; + raw += _bits[5]; + _temperature = raw * 1.9073486328125e-4 - 50; // ==> / 1048576.0 * 200 - 50; + + // TEST CHECKSUM + uint8_t _crc = _crc8(_bits, 6); + // Serial.print(_crc, HEX); + // Serial.print("\t"); + // Serial.println(_bits[6], HEX); + if (_crc != _bits[6]) return DHT20_ERROR_CHECKSUM; + + return DHT20_OK; +} + + +//////////////////////////////////////////////// +// +// TEMPERATURE & HUMIDITY & OFFSET +// +float DHT20::getHumidity() +{ + return _humidity + _humOffset; +}; + + +float DHT20::getTemperature() +{ + return _temperature + _tempOffset; +}; + + +void DHT20::setHumOffset(float offset) +{ + _humOffset = offset; +}; + + +void DHT20::setTempOffset(float offset) +{ + _tempOffset = offset; +}; + + +float DHT20::getHumOffset() +{ + return _humOffset; +}; + + +float DHT20::getTempOffset() +{ + return _tempOffset; +}; + + +//////////////////////////////////////////////// +// +// STATUS +// +uint8_t DHT20::readStatus() { _wire->beginTransmission(DHT20_ADDRESS); _wire->write(0x71); _wire->endTransmission(); - _wire->requestFrom(DHT20_ADDRESS, (uint8_t)1); return (uint8_t) _wire->read(); } +bool DHT20::isCalibrated() +{ + return (readStatus() & 0x08) == 0x08; +} + + +bool DHT20::isMeasuring() +{ + return (readStatus() & 0x80) == 0x80; +} + + +bool DHT20::isIdle() +{ + return (readStatus() & 0x80) == 0x00; +} + + +int DHT20::internalStatus() +{ + return _status; +}; + + +//////////////////////////////////////////////// +// +// OTHER +// +uint32_t DHT20::lastRead() +{ + return _lastRead; +}; + + +uint32_t DHT20::lastRequest() +{ + return _lastRequest; +}; + + +//////////////////////////////////////////////// +// +// PRIVATE +// uint8_t DHT20::_crc8(uint8_t *ptr, uint8_t len) { uint8_t crc = 0xFF; diff --git a/DHT20.h b/DHT20.h index 07f74c6..6f97f7a 100644 --- a/DHT20.h +++ b/DHT20.h @@ -3,7 +3,7 @@ // FILE: DHT20.h // AUTHOR: Rob Tillaart // PURPOSE: Arduino library for DHT20 I2C temperature and humidity sensor. -// VERSION: 0.1.2 +// VERSION: 0.1.3 // HISTORY: See DHT20.cpp // URL: https://github.com/RobTillaart/DHT20 // @@ -21,13 +21,15 @@ #include "Arduino.h" #include "Wire.h" -#define DHT20_LIB_VERSION (F("0.1.2")) +#define DHT20_LIB_VERSION (F("0.1.3")) #define DHT20_OK 0 #define DHT20_ERROR_CHECKSUM -10 #define DHT20_ERROR_CONNECT -11 #define DHT20_MISSING_BYTES -12 #define DHT20_ERROR_BYTES_ALL_ZERO -13 +#define DHT20_ERROR_READ_TIMEOUT -14 +#define DHT20_ERROR_LASTREAD -15 #define DHT20_ACQUISITION_TIME 85 @@ -45,40 +47,42 @@ class DHT20 bool isConnected(); // ASYNCHRONUOUS CALL - int requestData() { return _requestData(); }; - int readData() { return _readData(); }; + int requestData(); + int readData(); int convert(); // SYNCHRONUOUS CALL int read(); - float getHumidity() { return _humidity + _humOffset; }; - float getTemperature() { return _temperature + _tempOffset; }; - - // allows 1st order calibration - void setHumOffset(float offset) { _humOffset = offset; }; - void setTempOffset(float offset) { _tempOffset = offset; }; - float getHumOffset() { return _humOffset; }; - float getTempOffset() { return _tempOffset; }; + float getHumidity(); + float getTemperature(); + + // CALIBRATION 1st order + void setHumOffset(float offset); + void setTempOffset(float offset); + float getHumOffset(); + float getTempOffset(); + + // READ STATUS + uint8_t readStatus(); + bool isCalibrated(); + bool isMeasuring(); + bool isIdle(); + int internalStatus(); // OTHER - uint32_t lastRead() { return _lastRead; }; - uint32_t lastRequest() { return _lastRequest; }; - int internalStatus() { return _status; }; - // forced read status - uint8_t readStatus() { return _readStatus(); }; + uint32_t lastRead(); + uint32_t lastRequest(); + private: float _humidity; float _temperature; float _humOffset; float _tempOffset; + uint8_t _status; uint32_t _lastRequest; uint32_t _lastRead; - - int _requestData(); - int _readData(); - uint8_t _readStatus(); uint8_t _bits[7]; uint8_t _crc8(uint8_t *ptr, uint8_t len); diff --git a/README.md b/README.md index 2c78196..4ecb823 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,8 @@ Calling these latter again will return the same values until a new **read()** is The **read()** call of this sensor is blocking for 80+ milliseconds (datasheet 7.4) so the library also has a asynchronous interface. See below. +Verified to work with Arduino UNO and ESP32. + ## Connection @@ -94,19 +96,14 @@ Note there must be at least 1000 milliseconds between requests! See the example **DHT20_async.ino** -In the .h file there is a line -```cpp -#define DHT20_ACQUISITION_TIME 85 -``` -This can be used to optimize performance a bit. Use with care. - -### Miscellaneous +### Status -- **uint32_t lastRead()** last time the sensor is read in milliseconds since start. -- **uint32_t lastRequest()** last time a request is made to make a measurement. -- **int internalStatus()** returns the internal status of the sensor. (debug ). - **uint8_t readStatus()** forced read of the status only. +- **bool isCalibrated()** idem, wrapper around **readStatus()** +- **bool isMeasuring()** idem, wrapper around **readStatus()** +- **bool isIdle()** idem, wrapper around **readStatus()** +- **int internalStatus()** returns the internal status of the sensor. (debug ). | status bit | meaning | |:------------:|:---------------------------| @@ -116,9 +113,13 @@ This can be used to optimize performance a bit. Use with care. | 2 - 0 | unknown | -### Return codes +### Timing -TODO: fix incomplete list +- **uint32_t lastRead()** last time the sensor is read in milliseconds since start. +- **uint32_t lastRequest()** last time a request is made to make a measurement. + + +### Return codes | name | value | notes | |:----------------------------|:-------:|:--------| @@ -127,6 +128,8 @@ TODO: fix incomplete list | DHT20_ERROR_CONNECT | -11 | check connection | DHT20_MISSING_BYTES | -12 | check connection | DHT20_ERROR_BYTES_ALL_ZERO | -13 | check connection +| DHT20_ERROR_READ_TIMEOUT | -14 | +| DHT20_ERROR_LASTREAD | -15 | ## Operation @@ -139,29 +142,19 @@ See examples #### must - update documentation -- improve the code - - check return codes etc. - - add missing error codes - - **read()** should check lastRead() and return ERROR_LASTREAD -- add status shortcuts - - add **bool isCalibrated()** - - add **bool isMeasuring()** - - add **bool isIdle()** - +- comments in .h file #### should - add examples - - asynchronous +- check TODO's in code. + #### could - improve unit tests. - investigate - sensor calibration (website aosong?) -- check for optimizations. - - mainly for asynchronous - - 85 ms wait time? #### won't diff --git a/examples/DHT20/DHT20.ino b/examples/DHT20/DHT20.ino index e50aceb..f3b0d7f 100644 --- a/examples/DHT20/DHT20.ino +++ b/examples/DHT20/DHT20.ino @@ -80,6 +80,12 @@ void loop() case DHT20_ERROR_BYTES_ALL_ZERO: Serial.print("All bytes read zero"); break; + case DHT20_ERROR_READ_TIMEOUT: + Serial.print("Read time out"); + break; + case DHT20_ERROR_LASTREAD: + Serial.print("Error read too fast"); + break; default: Serial.print("Unknown error"); break; diff --git a/examples/DHT20/performance_0.1.2.txt b/examples/DHT20/performance_0.1.2.txt new file mode 100644 index 0000000..6757222 --- /dev/null +++ b/examples/DHT20/performance_0.1.2.txt @@ -0,0 +1,15 @@ +...Arduino\libraries\DHT20\examples\DHT20\DHT20.ino +DHT20 LIBRARY VERSION: 0.1.2 + + +Type Humidity (%) Temp (°C) Time (µs) Status +DHT20 70.8 21.4 86701 OK +DHT20 71.7 21.4 86702 OK +DHT20 69.2 21.4 86701 OK +DHT20 66.4 21.4 86702 OK +DHT20 64.4 21.4 86701 OK +DHT20 62.8 21.4 86701 OK +DHT20 61.7 21.4 86702 OK +DHT20 60.7 21.4 86701 OK +DHT20 60.1 21.4 86702 OK +DHT20 59.6 21.4 86702 OK \ No newline at end of file diff --git a/examples/DHT20/performance_0.1.3.txt b/examples/DHT20/performance_0.1.3.txt new file mode 100644 index 0000000..585ae53 --- /dev/null +++ b/examples/DHT20/performance_0.1.3.txt @@ -0,0 +1,15 @@ +...Arduino\libraries\DHT20\examples\DHT20\DHT20.ino +DHT20 LIBRARY VERSION: 0.1.3 + + +Type Humidity (%) Temp (°C) Time (µs) Status +DHT20 61.4 21.5 54684 OK +DHT20 61.4 21.5 54692 OK +DHT20 61.4 21.5 54692 OK +DHT20 61.4 21.5 54688 OK +DHT20 61.4 21.5 54704 OK +DHT20 61.4 21.5 54692 OK +DHT20 61.4 21.5 54692 OK +DHT20 61.4 21.5 46496 OK +DHT20 69.7 22.2 46492 OK +DHT20 79.9 22.3 54688 OK \ No newline at end of file diff --git a/examples/DHT20_test_esp/DHT20_test_esp.ino b/examples/DHT20_test_esp/DHT20_test_esp.ino index 2552016..b4eec7c 100644 --- a/examples/DHT20_test_esp/DHT20_test_esp.ino +++ b/examples/DHT20_test_esp/DHT20_test_esp.ino @@ -60,6 +60,12 @@ void loop() case DHT20_ERROR_BYTES_ALL_ZERO: Serial.print("All bytes read zero"); break; + case DHT20_ERROR_READ_TIMEOUT: + Serial.print("Read time out"); + break; + case DHT20_ERROR_LASTREAD: + Serial.print("Error read too fast"); + break; default: Serial.print("Unknown error,\t"); break; diff --git a/keywords.txt b/keywords.txt index 6ef109a..c6c8ac5 100644 --- a/keywords.txt +++ b/keywords.txt @@ -24,7 +24,9 @@ lastRead KEYWORD2 lastRequest KEYWORD2 internalStatus KEYWORD2 readStatus KEYWORD2 - +isCalibrated KEYWORD2 +isMeasuring KEYWORD2 +isIdle KEYWORD2 # Constants (LITERAL1) DHT20_LIB_VERSION LITERAL2 @@ -34,4 +36,7 @@ DHT20_ERROR_CHECKSUM LITERAL1 DHT20_ERROR_CONNECT LITERAL1 DHT20_MISSING_BYTES LITERAL1 DHT20_ERROR_BYTES_ALL_ZERO LITERAL1 +DHT20_ERROR_READ_TIMEOUT LITERAL1 +DHT20_ERROR_LASTREAD LITERAL1 + diff --git a/library.json b/library.json index f7ef905..6ee3139 100644 --- a/library.json +++ b/library.json @@ -15,7 +15,7 @@ "type": "git", "url": "https://github.com/RobTillaart/DHT20.git" }, - "version": "0.1.2", + "version": "0.1.3", "license": "MIT", "frameworks": "arduino", "platforms": "*", diff --git a/library.properties b/library.properties index 86fc08b..d7cd5bd 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=DHT20 -version=0.1.2 +version=0.1.3 author=Rob Tillaart maintainer=Rob Tillaart sentence=Arduino library for I2C DHT20 temperature and humidity sensor. diff --git a/test/unit_test_001.cpp b/test/unit_test_001.cpp index 7a1efcd..908cd15 100644 --- a/test/unit_test_001.cpp +++ b/test/unit_test_001.cpp @@ -46,6 +46,8 @@ unittest(test_constants) assertEqual(-11, DHT20_ERROR_CONNECT); assertEqual(-12, DHT20_MISSING_BYTES); assertEqual(-13, DHT20_ERROR_BYTES_ALL_ZERO); + assertEqual(-14, DHT20_ERROR_READ_TIMEOUT); + assertEqual(-15, DHT20_ERROR_LASTREAD); } @@ -59,7 +61,7 @@ unittest(test_constructor) assertEqualFloat(0, DHT.getHumOffset(), 0.001); DHT.begin(); - assertEqual(DHT20_ERROR_CONNECT, DHT.read()); + assertEqual(DHT20_ERROR_LASTREAD, DHT.read()); // assertEqualFloat(0, DHT.getTemperature(), 0.001); // assertEqualFloat(0, DHT.getHumidity(), 0.001);