Loading...

One class for both DHT11 and DHT22.

remarks & comments

Intro

The DHT11 and DHT 22 are relative cheap sensors for measuring temperature and humidity. This article describes a library for reading both values from these sensors. Recently I wrote a library for the DHT11 only, see - http://arduino.cc/playground/Main/DHT11Lib - It has a smaller footprint so if you only use DHT11 it might be preferred.

I contacted the manufacturer to get the details of the differences between the two DHT sensors to build a lib that supports both. The DHT22 is quite similar to the DHT11 and has a greater accuracy and range (temperature). The hardware pins and handshake are identical but it uses a different dataformat.

The library is confirmed to work on a MEGA2560 by SimKard

- update: The lib works on Arduino 2009 and UNO too.

- update: 0.1.05 fixes negative temperatures for DHT22 (Gave CRC error)

(NOTE: There is another library for the DHT22 that is known to work with Arduino 1.0 on ATmega328 Uno boards: https://github.com/ringerc/Arduino-DHT22 ; it is based on earlier work by nethoncho.)

Connection (hardware)

The DHT11/22 has three lines, GND, +5V and a single dataline. By means of a handshake the values are clocked out over the single digital line. Details about the protocol see datasheet: http://www.micro4you.com/files/sensor/DHT11.pdf (handshake for DHT 22 is identical, dataformat differs)

Simkard added a picture for the pinlayout which is not in the datasheet, see => http://arduino.cc/forum/index.php/topic,58531.msg421787.html#msg421787

From left to right

  • 1 : VCC (5V)
  • 2 : SIGnal
  • 3 : NC Not connected
  • 4 : GND

There have been reports that some sensors have pin 3 and 4 reversed, probably as a quality control/manufacturing issue. If you have issues, consider grounding both pins 3 and 4.

DHT library

The library at the end of this article is rewritten from scratch although inspired by earlier work of George Hadjikyriacou. While I wrote, Simkard did the testing so we can say it is an international library ;).

The library is not compatible with earlier DHT libraries to be able to support both DHT's and stay as simple as possible and to minimize footprint.

The interface of the class supports only one function for reading the humidity and temperature from the sensors and store it in two members of the class. The read() function verifies the checksum of the datatransmission and it has a timeout function.

The class has two read functions read11(PIN) and read22(PIN) which have the same interface. They read the DHT connected to PIN, and fill the two class members temperature and humidity.

The readXX() functions return:

  • DHTLIB_OK (0) : if the sensor sample and its checksum is OK.
  • DHTLIB_ERROR_CHECKSUM (-1) : if the checksum test failed. This means that data was received but may be incorrect.
  • DHTLIB_ERROR_TIMEOUT (-2) : if a timeout occured, communication failed.

In case of a DHTLIB_ERROR_TIMEOUT, humidity and temperature will both get the value DHTLIB_INVALID_VALUE. In case of DHTLIB_ERROR_CHECKSUM the values of humidity and temperature are left unchanged as it is impossible to determine which byte failed in the checksum. The programmer should decide based upon previous readings.

The class is kept simple and with one instance it is possible to read multiple sensors, provided each sensor has a separate pin. Please note that the values of temperature and humidity will be overwritten with every call. So either copy those values asap of use an instance of the class per sensor. Since version 0.1.04 the temperature and humidity are set to DHTLIB_INVALID_VALUE if there is a DHTLIB_ERROR_TIMEOUT to make explicit there is something wrong.

If one only needs the DHT22 part one could comment/remove the read11() function in the .cpp and .h files so the footprint is a few bytes smaller.

Usage

A sketch shows how the library can be used to read the sensor. --- Note: the max frequency the sensor can be sampled is about once per 2 seconds

//
//   FILE:  dht_test.pde
// PURPOSE: DHT library test sketch for Arduino
//

#include <dht.h>

dht DHT;

#define DHT11_PIN 4
#define DHT22_PIN 5

void setup()
{
  Serial.begin(115200);
  Serial.println("DHT TEST PROGRAM ");
  Serial.print("LIBRARY VERSION: ");
  Serial.println(DHT_LIB_VERSION);
  Serial.println();
  Serial.println("Type,\tstatus,\tHumidity (%),\tTemperature (C)");
}

void loop()
{
  // READ DATA
  Serial.print("DHT22, \t");
  int chk = DHT.read22(DHT22_PIN);
  switch (chk)
  {
    case DHTLIB_OK:  
                Serial.print("OK,\t");
                break;
    case DHTLIB_ERROR_CHECKSUM:
                Serial.print("Checksum error,\t");
                break;
    case DHTLIB_ERROR_TIMEOUT:
                Serial.print("Time out error,\t");
                break;
    default:
                Serial.print("Unknown error,\t");
                break;
  }
  // DISPLAY DATA
  Serial.print(DHT.humidity, 1);
  Serial.print(",\t");
  Serial.println(DHT.temperature, 1);

  delay(1000);

  // READ DATA
  Serial.print("DHT11, \t");
  chk = DHT.read11(DHT11_PIN);
  switch (chk)
  {
    case DHTLIB_OK:  
                Serial.print("OK,\t");
                break;
    case DHTLIB_ERROR_CHECKSUM:
                Serial.print("Checksum error,\t");
                break;
    case DHTLIB_ERROR_TIMEOUT:
                Serial.print("Time out error,\t");
                break;
    default:
                Serial.print("Unknown error,\t");
                break;
  }
 // DISPLAT DATA
  Serial.print(DHT.humidity,1);
  Serial.print(",\t");
  Serial.println(DHT.temperature,1);

  delay(1000);
}
//
// END OF FILE
//

In setup() The version of the library (a define) is displayed. This is for debugging purpose only.

In loop() a DHT22 and a DHT11 sensor are read and the fields temperature and humidity are filled. The return value of the readXX function is checked and displayed. Then the temperature and humidity are shown.

Notes

To use the library, make a folder in your SKETCHBOOKPATH\libaries with the name DHT and put the .h and .cpp there. Optionally make a examples subdirectory to place the sample app.

  • DHT22 and multiplexing is discussed here

Todo

  • test test test test and ...
  • test humidity range
  • test temperature range esp negative temp for DHT22
  • investigate non blocking version ? as current version is blocking while reading;

Enjoy tinkering,

rob.tillaart@removethisgmail.com

dht.h

//
//    FILE: dht.h
// VERSION: 0.1.05
// PURPOSE: DHT Temperature & Humidity Sensor library for Arduino
//
//     URL: http://arduino.cc/playground/Main/DHTLib
//
// HISTORY:
// see dht.cpp file
//

#ifndef dht_h
#define dht_h

#if ARDUINO < 100
#include <WProgram.h>
#else
#include <Arduino.h>
#endif

#define DHT_LIB_VERSION "0.1.05"

#define DHTLIB_OK                               0
#define DHTLIB_ERROR_CHECKSUM   -1
#define DHTLIB_ERROR_TIMEOUT    -2
#define DHTLIB_INVALID_VALUE    -999

class dht
{
public:
        int read11(uint8_t pin);
    int read22(uint8_t pin);
        double humidity;
        double temperature;

private:
        uint8_t bits[5];  // buffer to receive data
        int read(uint8_t pin);
};
#endif
//
// END OF FILE
//

dht.cpp

//
//    FILE: dht.cpp
// VERSION: 0.1.05
// PURPOSE: DHT Temperature & Humidity Sensor library for Arduino
//
// DATASHEET:
//
// HISTORY:
// 0.1.05 fixed negative temperature bug (thanks to Roseman)
// 0.1.04 improved readability of code using DHTLIB_OK in code
// 0.1.03 added error values for temp and humidity when read failed
// 0.1.02 added error codes
// 0.1.01 added support for Arduino 1.0, fixed typos (31/12/2011)
// 0.1.0 by Rob Tillaart (01/04/2011)
// inspired by DHT11 library
//

#include "dht.h"

#define TIMEOUT 10000

/////////////////////////////////////////////////////
//
// PUBLIC
//


// return values:
// DHTLIB_OK
// DHTLIB_ERROR_CHECKSUM
// DHTLIB_ERROR_TIMEOUT
int dht::read11(uint8_t pin)
{
        // READ VALUES
        int rv = read(pin);
        if (rv != DHTLIB_OK)
    {
                humidity    = DHTLIB_INVALID_VALUE; // or is NaN prefered?
                temperature = DHTLIB_INVALID_VALUE;
                return rv;
        }

        // CONVERT AND STORE
        humidity    = bits[0];  // bit[1] == 0;
        temperature = bits[2];  // bits[3] == 0;

        // TEST CHECKSUM
        uint8_t sum = bits[0] + bits[2]; // bits[1] && bits[3] both 0
        if (bits[4] != sum) return DHTLIB_ERROR_CHECKSUM;

        return DHTLIB_OK;
}

// return values:
// DHTLIB_OK
// DHTLIB_ERROR_CHECKSUM
// DHTLIB_ERROR_TIMEOUT
int dht::read22(uint8_t pin)
{
        // READ VALUES
        int rv = read(pin);
        if (rv != DHTLIB_OK)
    {
                humidity    = DHTLIB_INVALID_VALUE;  // invalid value, or is NaN prefered?
                temperature = DHTLIB_INVALID_VALUE;  // invalid value
                return rv;
        }

        // CONVERT AND STORE
        humidity    = word(bits[0], bits[1]) * 0.1;

        if (bits[2] & 0x80) // negative temperature
        {
                        temperature = word(bits[2]&0x7F, bits[3]) * 0.1;
                        temperature *= -1.0;
        }
        else
        {
                        temperature = word(bits[2], bits[3]) * 0.1;
        }

        // TEST CHECKSUM
        uint8_t sum = bits[0] + bits[1] + bits[2] + bits[3];
        if (bits[4] != sum) return DHTLIB_ERROR_CHECKSUM;

        return DHTLIB_OK;
}

/////////////////////////////////////////////////////
//
// PRIVATE
//

// return values:
// DHTLIB_OK
// DHTLIB_ERROR_TIMEOUT
int dht::read(uint8_t pin)
{
        // INIT BUFFERVAR TO RECEIVE DATA
        uint8_t cnt = 7;
        uint8_t idx = 0;

        // EMPTY BUFFER
        for (int i=0; i< 5; i++) bits[i] = 0;

        // REQUEST SAMPLE
        pinMode(pin, OUTPUT);
        digitalWrite(pin, LOW);
        delay(20);
        digitalWrite(pin, HIGH);
        delayMicroseconds(40);
        pinMode(pin, INPUT);

        // GET ACKNOWLEDGE or TIMEOUT
        unsigned int loopCnt = TIMEOUT;
        while(digitalRead(pin) == LOW)
                if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

        loopCnt = TIMEOUT;
        while(digitalRead(pin) == HIGH)
                if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

        // READ THE OUTPUT - 40 BITS => 5 BYTES
        for (int i=0; i<40; i++)
        {
                loopCnt = TIMEOUT;
                while(digitalRead(pin) == LOW)
                        if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

                unsigned long t = micros();

                loopCnt = TIMEOUT;
                while(digitalRead(pin) == HIGH)
                        if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

                if ((micros() - t) > 40) bits[idx] |= (1 << cnt);
                if (cnt == 0)   // next byte?
                {
                        cnt = 7;  
                        idx++;      
                }
                else cnt--;
        }

        return DHTLIB_OK;
}
//
// END OF FILE
//