diff --git a/DHT_Sensor/README.md b/DHT_Sensor/README.md index 5ed7e80..ce14d08 100644 --- a/DHT_Sensor/README.md +++ b/DHT_Sensor/README.md @@ -1,4 +1,34 @@ -# DHT Sensor +# DHT Sensor Library -This project reads from a Digital humidity temperature sensor of type (DHT11/21/22) -Root mode should be enabled to get readings from sensor +A Raspberry Pi C++ based library for the series of low cost Digital humidity temperature sensors(DHT11/21/22) + +## Usage + +Root mode should be enabled to get readings from sensor. The GPIO pin must be given as a run parameter + +Wrapper and Test driver already provided to run basic reading tests for convenience. To run:- + +``` +mkdir build +cd build +g++ -DPI_BUILD -o dht ../src/*.cpp -lwiringPi +./dht +``` + +Alternatively, to compile the library and run with your created main program(don't forget to setup the Pi in your program code): + +``` +mkdir build +cd build +g++ -DPI_BUILD -c ../src/DHT.cpp --lwiringPi +ar rvs DHT.a DHT.o +g++ DHT.a +``` + +## Contributing + +Pull requests are always welcome. For major changes, please open an issue first to discuss proposed changes. + +## Licence + +[MIT](https://choosealicense.com/licenses/mit/) diff --git a/DHT_Sensor/bin/doc/DHTSensor.jpg b/DHT_Sensor/doc/DHTSensor.jpg similarity index 100% rename from DHT_Sensor/bin/doc/DHTSensor.jpg rename to DHT_Sensor/doc/DHTSensor.jpg diff --git a/DHT_Sensor/bin/doc/DHT_Timing.png b/DHT_Sensor/doc/DHT_Timing.png similarity index 100% rename from DHT_Sensor/bin/doc/DHT_Timing.png rename to DHT_Sensor/doc/DHT_Timing.png diff --git a/DHT_Sensor/bin/doc/Sensor_To_RPi.jpg b/DHT_Sensor/doc/Sensor_To_RPi.jpg similarity index 100% rename from DHT_Sensor/bin/doc/Sensor_To_RPi.jpg rename to DHT_Sensor/doc/Sensor_To_RPi.jpg diff --git a/DHT_Sensor/src/DHT.cpp b/DHT_Sensor/src/DHT.cpp index 16e911d..9a6c2c6 100644 --- a/DHT_Sensor/src/DHT.cpp +++ b/DHT_Sensor/src/DHT.cpp @@ -1,79 +1,59 @@ #include "DHT.h" +#include -// global reference definition for the static variables -uint8_t DHT::data[5]; -float DHT::t = 0.0; -float DHT::h = 0.0; -DHT *DHT::_instance = NULL; -uint16_t DHT::_pin; -#ifdef PI_BUILD - -#include +DHT::DHT(const uint16_t pin) : m_pin(pin) +{ +} -// pointer constructor. Should be used in any class that calls needs a dht -// object -// e.g in main -> DHT * dhtobject = DHT::getInstance(); -DHT *DHT::getInstance(uint16_t pin) +DHT& DHT::getInstance(const uint16_t pin) { - if (_instance == NULL) - { - _instance = new DHT(); - } - _pin = pin; - return _instance; + static DHT instance(pin); + return instance; } +#ifdef PI_BUILD +#include + bool DHT::pulse_setter() { - int pulseCounts[DHT_PULSES * 2] = {0}; - pinMode(_pin, OUTPUT); + uint16_t pulseCounts[DHT_PULSES * 2] = {0}; + pinMode(m_pin, OUTPUT); int priority = piHiPri(2); - digitalWrite(_pin, HIGH); + digitalWrite(m_pin, HIGH); delay(500); - digitalWrite(_pin, LOW); + digitalWrite(m_pin, LOW); delay(20); - pinMode(_pin, INPUT); - pullUpDnControl(_pin, PUD_UP); - for (volatile int i = 0; i < 50; ++i) - { + pinMode(m_pin, INPUT); + pullUpDnControl(m_pin, PUD_UP); + for (volatile int i = 0; i < 50; ++i) { } - uint32_t count = 0; + uint8_t count = 0; // wait for dht to pull pin low - while (digitalRead(_pin) == HIGH) - { - if (++count >= DHT_MAXCOUNT) - { + while (digitalRead(m_pin) == HIGH) { + if (++count >= DHT_MAXCOUNT) { priority = piHiPri(0); - std::cout << "time out waiting for low" << std::endl; return false; } } // Record pulse widths for the expected result bits. - for (int i = 0; i < DHT_PULSES * 2; i += 2) - { + for (uint16_t i = 0; i < DHT_PULSES * 2; i += 2) { // count how long pin is low and store in pulseCounts - while (digitalRead(_pin) == LOW) - { - if (++pulseCounts[i] >= DHT_MAXCOUNT) - { + while (digitalRead(m_pin) == LOW) { + if (++pulseCounts[i] >= DHT_MAXCOUNT) { priority = piHiPri(0); - std::cout << "time out waiting for high" << std::endl; return false; } } // count how long pin is high and store in pulse counts - while (digitalRead(_pin) == HIGH) - { - if (++pulseCounts[i + 1] >= DHT_MAXCOUNT) - { + while (digitalRead(m_pin) == HIGH) { + if (++pulseCounts[i + 1] >= DHT_MAXCOUNT) { priority = piHiPri(0); - std::cout << "time out waiting for low" << std::endl; return false; } } @@ -85,9 +65,8 @@ bool DHT::pulse_setter() // threshold. // Ignore the first two readings because they are a constant 80 microsecond // pulse. - uint32_t threshold = 0; - for (int i = 2; i < DHT_PULSES * 2; i += 2) - { + uint16_t threshold = 0; + for (uint16_t i = 2; i < DHT_PULSES * 2; i += 2) { threshold += pulseCounts[i]; } @@ -98,146 +77,92 @@ bool DHT::pulse_setter() // If the count is less than 50us it must be a ~28us 0 pulse, and if it's // higher // then it must be a ~70us 1 pulse. - data[5] = {0}; - for (int i = 3; i < DHT_PULSES * 2; i += 2) - { - int index = (i - 3) / 16; - data[index] <<= 1; - if (pulseCounts[i] >= threshold) - { + for (uint16_t i = 3; i < DHT_PULSES * 2; i += 2) { + uint8_t index = (i - 3) / 16; + m_data[index] <<= 1; + if (pulseCounts[i] >= threshold) { // One bit for long pulse. - data[index] |= 1; + m_data[index] |= 1; } // Else zero bit for short pulse. } // Verify checksum of received data. - if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) - { - return true; - } - else - { - std::cout << "Check sum failure" << std::endl; + if (!(m_data[4] == ((m_data[0] + m_data[1] + m_data[2] + m_data[3]) & 0xFF))) { return false; } + + return true; } void DHT::read_sensor() { - float div; - if (pulse_setter() == true) - { - temperature = &t; - humidity = &h; - h = ((float)(data[0] * 256 + data[1])) / 10.0; - if (data[2] & 0x80) - { // for minus temperature values - div = -10.0; - } - else - div = 10.0; + if (pulse_setter()) { + m_humidity = static_cast((m_data[0] * 256 + m_data[1]) / 10.0); - t = ((float)((data[2] & 0x7F) * 256 + data[3])) / div; + const auto divisor = m_data[2] & 0x80 ? -10.0F : 10.0F; // -10 for negative temperature values + m_temperature = static_cast(((m_data[2] & 0x7F) * 256 + m_data[3]) / divisor); } - else if (!pulse_setter()) - { + else { std::cout << "bad data, last good read will be returned" << std::endl; } } +#else // empty implementation for build on windows +bool DHT::pulse_setter() { return false; } +void DHT::read_sensor() {} +#endif + float DHT::get_heatIndex() { - float temperature; - float percentHumidity; - float hi; - temperature = *temperature; - percentHumidity = *humidity; - temperature = convertCtoF(temperature); - hi = 0.5 * (temperature + 61.0 + ((temperature - 68.0) * 1.2) + - (percentHumidity * 0.094)); - if (hi > 79) - { - hi = -42.379 + 2.04901523 * temperature + - 10.14333127 * percentHumidity + - -0.22475541 * temperature * percentHumidity + - -0.00683783 * pow(temperature, 2) + + const float hi = compute_heat_index(); + return hi; +} + +const float DHT::compute_heat_index() +{ + float percentHumidity = m_humidity; + float temperature = convertCtoF(m_temperature); + float hi = + 0.5 * (temperature + 61.0 + ((temperature - 68.0) * 1.2) + (percentHumidity * 0.094)); + if (hi > 79) { + hi = -42.379 + 2.04901523 * temperature + 10.14333127 * percentHumidity + + -0.22475541 * temperature * percentHumidity + -0.00683783 * pow(temperature, 2) + -0.05481717 * pow(percentHumidity, 2) + 0.00122874 * pow(temperature, 2) * percentHumidity + 0.00085282 * temperature * pow(percentHumidity, 2) + -0.00000199 * pow(temperature, 2) * pow(percentHumidity, 2); - if ((percentHumidity < 13) && (temperature >= 80.0) && - (temperature <= 112.0)) + if ((percentHumidity < 13) && (temperature >= 80.0) && (temperature <= 112.0)) hi -= ((13.0 - percentHumidity) * 0.25) * sqrt((17.0 - abs(temperature - 95.0)) * 0.05882); - else if ((percentHumidity > 85.0) && (temperature >= 80.0) && - (temperature <= 87.0)) - hi += - ((percentHumidity - 85.0) * 0.1) * ((87.0 - temperature) * 0.2); + else if ((percentHumidity > 85.0) && (temperature >= 80.0) && (temperature <= 87.0)) + hi += ((percentHumidity - 85.0) * 0.1) * ((87.0 - temperature) * 0.2); } return convertFtoC(hi); } -float DHT::convertCtoF(float c) +const float DHT::convertCtoF(const float c) { return c * 1.8 + 32; } -float DHT::convertFtoC(float f) +const float DHT::convertFtoC(const float f) { return (f - 32) * 0.55555; } float DHT::get_temperature() { - if (temperature == NULL) - read_sensor(); - if (temperature != NULL) - return *temperature; - else - return 0.0; + read_sensor(); + const float temperature = (m_temperature != 0.0F) ? m_temperature : 0.0F; + return temperature; } float DHT::get_humidity() { - if (humidity == NULL) - read_sensor(); - if (humidity != NULL) - return *humidity; - else - return 0.0; -} -#else -// empty implementation for build on windows -float DHT::convertCtoF(float c) -{ - return -1; + read_sensor(); + const float humidity = (m_humidity != 0.0F) ? m_humidity : 0.0F; + return humidity; } -float DHT::convertFtoC(float f) -{ - return -1; -} -bool DHT::pulse_setter() -{ - return false; -} -DHT *DHT::getInstance(uint16_t pin) -{ - return NULL; -} -float DHT::get_temperature() -{ - return -1; -} -float DHT::get_humidity() -{ - return -1; -} -float DHT::get_heatIndex() -{ - return -1; -} - -#endif diff --git a/DHT_Sensor/src/DHT.h b/DHT_Sensor/src/DHT.h index a16ee61..0861210 100644 --- a/DHT_Sensor/src/DHT.h +++ b/DHT_Sensor/src/DHT.h @@ -1,58 +1,45 @@ -/** heat Index was computed - * Using both Rothfusz and Steadman's equations +/** + * @brief C++ library for DHT22 / DHT21 / DHT11 sensor + * @author Abidemi Shobayo-Eniola + * @copyright Copyright (c) 2016-2020 Abidemi Shobayo-Eniola - All Rights + * Reserved + * heat Index was computed using both Rothfusz and Steadman's equations * http://www.wpc.ncep.noaa.gov/html/heatindex_equation.shtml * the constructor is set as private following the Singleton design pattern. * This project uses the BCM NATIVE HARDWARE NUMBERING FOR Setupmode. * In main, wiringPiSetupGpio() mode is used - * The project should also be runned as root for it to work - * for test purpose Gpio17 was used, so pin was declared as 17 + * The project should be run as root. For test purposes, Gpio17 was used */ - #ifndef DHT_H #define DHT_H -#endif -// standard includes -#include -#include -#include -#include #include -// defines -#define DHT_MAXCOUNT 32000 -#define DHT_PULSES 41 - -class DHT -{ - private: - static DHT *_instance; - float *temperature; - float *humidity; - static float t, h; - float convertCtoF(float c); - float convertFtoC(float f); - bool pulse_setter(); - void read_sensor(); - static uint8_t data[5]; - uint8_t laststate; - static uint16_t _pin; - float start; - - protected: - DHT() - { - start = 0.0; - temperature = &start; - humidity = &start; - } - - public: - static DHT *getInstance(uint16_t pin); +class DHT { +public: + static DHT& getInstance(const uint16_t pin); + float get_temperature(); float get_humidity(); float get_heatIndex(); + +private: + DHT(const uint16_t pin); + ~DHT() = default; + + bool pulse_setter(); + void read_sensor(); + const float compute_heat_index(); + const float convertCtoF(const float c); + const float convertFtoC(const float f); + + float m_temperature = 0.0F; + float m_humidity = 0.0F; + uint8_t m_data[5] = {0}; + uint16_t m_pin; + static constexpr uint16_t DHT_MAXCOUNT = 32000; + static constexpr uint16_t DHT_PULSES = 41; }; #endif diff --git a/DHT_Sensor/src/DHTWrapper.cpp b/DHT_Sensor/src/DHTWrapper.cpp index 65b0cd9..e3184b7 100644 --- a/DHT_Sensor/src/DHTWrapper.cpp +++ b/DHT_Sensor/src/DHTWrapper.cpp @@ -1,19 +1,13 @@ #include "DHTWrapper.h" -#include DHTWrapper::DHTWrapper(uint16_t pin) { - dht = DHT::getInstance(pin); + m_dht = &DHT::getInstance(pin); } void DHTWrapper::manual_reading() { - // Read temperature twice to make sure reading is accurate - dht->get_temperature(); - wait(READ_INTERVAL); - std::cout << "Temperature: " << dht->get_temperature() << (char)167 << "C" - << " "; - std::cout << "(Real feel: " << dht->get_heatIndex() << (char)167 << "C)" - << std::endl; - std::cout << "Humidity: " << dht->get_humidity() << (char)37 << std::endl; + std::cout << "Humidity = " << m_dht->get_humidity() << "% " + << "Temperature = " << m_dht->get_temperature() << "*C " + << "(Real feel: " << m_dht->get_heatIndex() << "*C)" << std::endl; } diff --git a/DHT_Sensor/src/DHTWrapper.h b/DHT_Sensor/src/DHTWrapper.h index b413d80..9c102bd 100644 --- a/DHT_Sensor/src/DHTWrapper.h +++ b/DHT_Sensor/src/DHTWrapper.h @@ -1,17 +1,13 @@ -#include "DHT.h" - #ifndef DHTWrapper_H #define DHTWrapper_H -#endif - -#define READ_INTERVAL 3000 - -class DHTWrapper : private DHT -{ - private: - DHT *dht; +#include "DHT.h" - public: - DHTWrapper(uint16_t pin); +class DHTWrapper { +public: + explicit DHTWrapper(const uint16_t pin); void manual_reading(); + +private: + DHT* m_dht = nullptr; }; +#endif diff --git a/DHT_Sensor/src/Test_Driver.cpp b/DHT_Sensor/src/Test_Driver.cpp index 13841b0..b3d8f9e 100644 --- a/DHT_Sensor/src/Test_Driver.cpp +++ b/DHT_Sensor/src/Test_Driver.cpp @@ -8,19 +8,36 @@ #include #include "DHTWrapper.h" -int main(int argc, char *argv[]) +#ifdef PI_BUILD +#include +#endif + +int main(int argc, char* argv[]) { - unsigned long pin = std::strtoul(argv[1], NULL, 0); - if (argc > 1 && pin > 0) - { - DHTWrapper dht = DHTWrapper((uint16_t)pin); - dht.manual_reading(); +#ifdef PI_BUILD + if (wiringPiSetupGpio() == -1) { + std::cout << "Pi GPIO Must be set up" << std::endl; + return EXIT_FAILURE; } - else - { - std::cout << "ERROR: GPIO Pin number must be passed as a command line " - "argument" +#endif + + const auto pin = std::strtoul(argv[1], NULL, 0); + if (!(argc > 1 && pin > 0)) { + std::cout << "ERROR: GPIO Pin number must be passed as a command line argument" << std::endl; + return EXIT_FAILURE; } - return 0; + + /* run test n times */ + int n = 1; + do { + DHTWrapper dht = DHTWrapper(static_cast(pin)); + dht.manual_reading(); + ++n; +#ifdef PI_BUILD + delay(1000); /* wait 1 second before next read */ +#endif + } while (n < 201); + + return EXIT_SUCCESS; }