Class for DHT11, DHT21 and DHT22 (temperature & humidity)

DHT lib outputs humidity and temperature values from the point in time of the reading before

I did some tests with a longer delay (20 min) between the DHT sensor readings, I noticed a significant offset between the DHT values and some DS18B20 temp sensors readings in parallel. After a rain shower I noticed also some implausible data values: It starts to rain but the next reading about 10 minutes after did report very "dry" values and only the next reading reports correct "wet" values.

So I did some tests with the sketch below. It reads values every 10 seconds but also a "control reading" 500 ms after the first reading. To trigger sensor changes I breathe upon the sensor to increase humidity, this is directly after last reading, around 9 seconds before next reading. So the sensor has enough time to "warm up" / catch the change.

I got the same results as in my 20 minutes setting (detailed output see below after the code): The reading is NOT the value for the current time but represents the situation of the last measurement. It seams with "DHT.readxx" is done a reading but this reading will be outputted not in the following Serial.print(DHT.temperature, 1); but in outputs just after that, so "one data point too late".

Is this the way the DHT works??--I did not see any comment about that?? Or is there an error in the lib or in my code (a modification of the lib example)?

#include 
dht DHT;
#define DHT33_PIN 7

struct{
    uint32_t total;
    uint32_t ok;
    uint32_t crc_error;
    uint32_t time_out;
    uint32_t connect;
    uint32_t ack_l;
    uint32_t ack_h;
    uint32_t unknown;
} stat = { 0,0,0,0,0,0,0,0};

void setup(){
    Serial.begin(9600);
    Serial.print("LIBRARY VERSION: ");
    Serial.println(DHT_LIB_VERSION);
    Serial.println();
    Serial.println("Type,\tstatus,\tHumidity (%),\tTemperature (C)\tTime (us)");
}

void loop(){
    readData();
    Serial.print("\t");
    Serial.print("delay 500");
    Serial.println();
    delay(500);
    
    readData();
    Serial.print("\t");
    Serial.print("delay 10000");
    Serial.println();
    delay(10000);
    Serial.println();
}

void readData(){
    // READ DATA
    Serial.print("DHT33, \t");

    uint32_t start = micros();
    int chk = DHT.read33(DHT33_PIN);
    uint32_t stop = micros();

    stat.total++;
    switch (chk)
    {
    case DHTLIB_OK:
        stat.ok++;
        Serial.print("OK,\t");
        break;
    case DHTLIB_ERROR_CHECKSUM:
        stat.crc_error++;
        Serial.print("Checksum error,\t");
        break;
    case DHTLIB_ERROR_TIMEOUT:
        stat.time_out++;
        Serial.print("Time out error,\t");
        break;
    default:
        stat.unknown++;
        Serial.print("Unknown error,\t");
        break;
    }
    // DISPLAY DATA
    Serial.print(DHT.humidity, 1);
    Serial.print(",\t");
    Serial.print(DHT.temperature, 1);
    Serial.print(",\t");
    Serial.print(stop - start);

    if (stat.total % 20 == 0)    {
        Serial.println("\nTOT\tOK\tCRC\tTO\tUNK");
        Serial.print(stat.total);
        Serial.print("\t");
        Serial.print(stat.ok);
        Serial.print("\t");
        Serial.print(stat.crc_error);
        Serial.print("\t");
        Serial.print(stat.time_out);
        Serial.print("\t");
        Serial.print(stat.connect);
        Serial.print("\t");
        Serial.print(stat.ack_l);
        Serial.print("\t");
        Serial.print(stat.ack_h);
        Serial.print("\t");
        Serial.print(stat.unknown);
        Serial.println("\n");
    }
}

What I get is this

LIBRARY VERSION: 0.1.13

Type, status, Humidity (%), Temperature (C) Time (us)
DHT33, OK, 28.4, 23.5, 5096 delay 500
DHT33, OK, 28.3, 23.5, 5240 delay 10000

DHT33, OK, 28.3, 23.5, 5232 delay 500
DHT33, Time out error, -999.0, -999.0, 6936 delay 10000

DHT33, OK, 28.3, 23.5, 5240 delay 500
DHT33, OK, 29.4, 23.5, 5160 delay 10000

=> directly after last reading breathing upon the sensor to  
=> increse humidity, this is around 9 seconds before next reading

DHT33, OK, 29.4, 23.5, 5152 delay 500    ??? why is this value (29.4) so low ??? 
DHT33, OK, 74.4, 23.5, 5336 delay 10000  !!! 74.4 is now ok and "wet", but environment did not change in 500 ms !!!   

DHT33, OK, 74.6, 23.5, 5416 delay 500
DHT33, OK, 69.4, 24.3, 5392 delay 10000

DHT33, OK, 68.8, 24.3, 5240 delay 500
DHT33, OK, 55.8, 24.2, 5152 delay 10000

DHT33, OK, 55.2, 24.2, 5112 delay 500
DHT33, OK, 42.0, 23.8, 5232 delay 10000

DHT33, OK, 41.6, 23.8, 5240 delay 500
DHT33, OK, 36.0, 23.8, 5288 delay 10000

=> again: directly after last reading breathing upon the sensor to  
=> increse humidity, this is around 9 seconds before next reading

DHT33, OK, 35.9, 23.8, 5336 delay 500    ??? same behavior, why is this value (35.9) so low ??? 
DHT33, OK, 87.1, 23.9, 5432 delay 10000 !!! 87.1 is now ok and "wet", but environment did not change in the last 500 ms !!!   

DHT33, OK, 87.9, 23.9, 5424 delay 500
DHT33, OK, 86.1, 24.2, 5288
TOT OK CRC TO UNK
20 19 0 1 0 0 0 0

 delay 10000

DHT33, OK, 84.6, 24.2, 5248 delay 500
DHT33, OK, 48.6, 24.1, 5288 delay 10000

DHT33, OK, 47.5, 24.1, 5384 delay 500
DHT33, OK, 35.9, 24.1, 5296 delay 10000

The offset problem in my last post was tested with two different DHT33 sensors. To be sure not the sensors types are the problem I tested with DHT22 sensors also: Same result, always this one reading point offset!

The only software fix that is working is reading the sensor twice with a 500 ms delay between:

    DHT.read22(DHT22_PIN);
    delay(500); 
    int chk = DHT.read22(DHT22_PIN);

But this is not the way I want to go. My nodes are optimized for battery powering and so this is not really a good solution.

I tested it also with the Adafruit DHT lib and the results gone more worse: The update of a "reality" value happened two or three datapoints after the breathing event.

I have the 4k7 resistor (between data and Vcc) on the shield, then a 50 cm cable connects the sensor with the shield, but I have also tested with 10 cm cable also with no better results. Could this have any influence of the offset / delay or additional capacitors I saw on some breakouts? I think not - because I got a reading, but perhaps someone out has better ideas?

I still do not know: it's a hardware problem / knowing issue for the DHT or a software problem on the library?

Ok, I have the answer, it's a hardware "problem" but obviously intended by the designers, see http://www.kandrsmith.org/RJS/Misc/Hygrometers/calib_dht22_dht11_sht71.html

However, the DHT22 caches a reading in memory and returns it whenever a value is next requested.

FYI, I just connected a DHT11 to Arduino NANO, using the LIB file and sketch dht_test1 from Arduino site and it works good.

Thanks MetzgerM for this feedback!

Arduino: 1.8.2 (Windows 8.1), Board: "Arduino/Genuino Uno"

C:\Users\Admin\AppData\Local\Temp\cc5ZtX3e.ltrans0.ltrans.o: In function `loop':

C:\Users\Admin\Desktop\testing/testing.ino:13: undefined reference to `dht::read11(unsigned char)'

collect2.exe: error: ld returned 1 exit status

exit status 1 Error compiling for board Arduino/Genuino Uno.

This report would have more information with "Show verbose output during compilation" option enabled in File -> Preferences.

I am getting this dreaded compile error:

D:\Temp\W7Temp\ccHsEcYa.ltrans0.ltrans.o: In function `read22':
D:\MaxG_MyDocuments\Arduino\libraries\DHT/dht.h:63: undefined reference to `dht::read(unsigned char)'
collect2.exe: error: ld returned 1 exit status
exit status 1
Error compiling.

dht.h and dht.cpp are in a folder DHT in libraries (where all other libraries are)

A different IDE gives me this error:

D:\Temp\W7Temp\ccSTkO5j.ltrans0.ltrans.o: In function `read22':
D:\Prog\sloeber\arduinoPlugin\libraries_added\DHT/dht.h:63: undefined reference to `dht::read(unsigned char)'
collect2.exe: error: ld returned 1 exit status
make: *** [makefile:92: RoomControllerV0.elf] Error 1

No idea how to fix it... :(

Any hints appreciated...

Have you tried the example sketches that come with the library?

Which board are you using?

What version of the IDE?

Can you post the sketch you use?

Sorry for being unspecific... and thank you for your reply.

I used the github files and example... Arduino IDE 1.6.7 -- which I only use to verify and validate any problem(s); e.g. like this I encounter, otherwise I use the Sloeber IDE for my UNO developments.

As I said before create folder DHT, create file dht.cpp, dht.h, create example folder, create dht_test.ino; open Arduino IDE; open dht_test.ino, change DHT pin; at first leave the file intact; then deleted all but the DHT22 section -- same result = error msg when compiling. When I googled this error, I found quite a few of the same problem, but no resolution.

As such, not so promising outlook and needing an immediate solution, I deleted the DHT library and downloaded/used the AdaFruit DHT library, which worked spot on.

OK good to hear you have it woirking

For my information, do you recall which version of the lib you were using, as I want to keep it as stable as possible.

Thx

Hi Rob,

No disrespect... I appreciate putting your work out there for others to use!

I took the files from GitHub as they were yesterday... Proceeded as described; got the same compile error in both IDEs... Looked for an alternative, tested the AdaFruit library... worked, done.

Cheers, Max

Thanks,

The latest version is an expirimental version,

The latest stable is - https://github.com/RobTillaart/Arduino/tree/master/libraries/DHTstable

Updated the DHTlib and DHTstable to support DHT12 and AM23XX.

Comments and remarks as always welcome

So, I have just gotten the DHT11 to work and display values on an OLED, but the sketch I am using helpfully puts an "F" after the temperature, but only displays the temp in Celcius. I have been digging through posts and websites for the last couple of hours, but have been unsuccessful. I keep seeing people say use float, but I have no clue what that means, others say it is part of the library, but they must be using a different library than I am. Using this library, how can I make it display the temperature in Farenheit?

#include   // U8glib library
#include      // DHT library

#define dht_dpin 2  //  pin to which the sensor is connected
dht DHT;
               /*Uncomment and comment*/
//U8GLIB_SH1106_128X64 u8g(13, 11, 10, 9, 8);  // CLK=13, DIN=11, CS=10, DC=9, Reset=8
//U8GLIB_SSD1306_128X32 u8g(13, 11, 10, 9, 8); // CLK=13, DIN=11, CS=10, DC=9, Reset=8
U8GLIB_SSD1306_128X64 u8g(13, 11, 10, 9, 8); // CLK=13, DIN=11, CS=10, DC=9, Reset=8

void draw(void) 
{
   u8g.setFont(u8g_font_fub11r);   // select font
   u8g.drawStr(0, 11, "Temp: ");   // put string of display at position X, Y
   u8g.drawStr(80, 11, "Humi: ");
   u8g.setFont(u8g_font_fub14r);
   u8g.setPrintPos(10, 45);        // set position
   u8g.print(DHT.temperature, 0);  // display temperature from DHT11 in Celsius
   u8g.println("F"); 
   u8g.setPrintPos(72, 45);        // set position
   u8g.print(DHT.humidity, 0);     // display humidity from DHT11
   u8g.println("%");
}
void setup(void) 
{

}

void loop(void)
{
   DHT.read11(dht_dpin);  // Read dpin on DHT11
   u8g.firstPage();  
   do 
{
   draw();
}  while( u8g.nextPage() );
   delay(5000);  // Delay of 2 sec before accessing DHT11 (min - 2sec)
}
                           /*END OF FILE*/

Using this library, how can I make it display the temperature in Farenheit?

You can convert any Celsius temperature to Fahrenheit, that does not depend on the sensor.

float Tc = someObject.getTemperatureC(…);

float Tf = Tc * 1.8 + 32;

you should add this formula into your sketch.

Some interesting temperature is -40C as that is also -40F; And 100F is about human body temperature.

The Celsius scale is based on the physics of water (melting/boiling) @ 1013 hPa or 1 atmosphere or sea level pressure.

More fun is the Kelvin scale as it has no negative temperatures in practice.

After some trial and error, it seems that float is mostly working, but now it displays 32F all the time. I changed the formula to add 33 in the conversion, and it displays 33. Seems the float is being set to the last number in the conversion formula?

/Uncomment and comment/ //U8GLIB_SH1106_128X64 u8g(13, 11, 10, 9, 8); // CLK=13, DIN=11, CS=10, DC=9, Reset=8 //U8GLIB_SSD1306_128X32 u8g(13, 11, 10, 9, 8); // CLK=13, DIN=11, CS=10, DC=9, Reset=8 U8GLIB_SSD1306_128X64 u8g(13, 11, 10, 9, 8); // CLK=13, DIN=11, CS=10, DC=9, Reset=8

float Tc = DHT.temperature; float Tf = (Tc*1.8+32);

void draw(void) { u8g.setFont(u8g_font_fub11r); // select font u8g.drawStr(0, 11, "Temp: "); // put string of display at position X, Y u8g.drawStr(80, 11, "Humi: "); u8g.setFont(u8g_font_fub14r); u8g.setPrintPos(10, 45); // set position u8g.print(Tf, 0); // u8g.print(DHT.temperature, 0); // display temperature from DHT11 in Celsius u8g.println("F"); u8g.setPrintPos(72, 45); // set position u8g.print(DHT.humidity, 0); // display humidity from DHT11 u8g.println("%");

After more searching and work, it seems I just don't understand float. I finally got it working with the code below. A few notes. If I tried to print Tc, it shows 0. If I print Tf, it shows 32.

#include   // U8glib library
#include      // DHT library

#define dht_dpin 2  //  pin to which the sensor is connected
dht DHT;
               /*Uncomment and comment*/
//U8GLIB_SH1106_128X64 u8g(13, 11, 10, 9, 8);  // CLK=13, DIN=11, CS=10, DC=9, Reset=8
//U8GLIB_SSD1306_128X32 u8g(13, 11, 10, 9, 8); // CLK=13, DIN=11, CS=10, DC=9, Reset=8
U8GLIB_SSD1306_128X64 u8g(13, 11, 10, 9, 8); // CLK=13, DIN=11, CS=10, DC=9, Reset=8

//float Tc = DHT.temperature;
//float Tf = Tc * 1.8 + 32;
//float Tf = (32 + (DHT.temperature * 1.8));

void draw(void) 
{
   u8g.setFont(u8g_font_fub11r);   // select font
   u8g.drawStr(0, 11, "Temp: ");   // put string of display at position X, Y
   u8g.drawStr(80, 11, "Humi: ");
   u8g.setFont(u8g_font_fub14r);
   u8g.setPrintPos(10, 45);        // set position
//   u8g.print(Tc, 0);
//   u8g.print(Tf, 0);
   u8g.print((DHT.temperature * 1.8 + 32), 0);  // display temperature from DHT11 in Fahreneit
   u8g.println("F"); 
   u8g.setPrintPos(72, 45);        // set position
   u8g.print(DHT.humidity, 0);     // display humidity from DHT11
   u8g.println("%");
}
void setup(void) 
{

}

void loop(void)
{
   DHT.read11(dht_dpin);  // Read dpin on DHT11
   u8g.firstPage();  
   do 
{
   draw();
}  while( u8g.nextPage() );
   delay(5000);  // Delay of 2 sec before accessing DHT11 (min - 2sec)
}
                           /*END OF FILE*/

Replace

u8g.print((DHT.temperature * 1.8 + 32), 0);  // display temperature from DHT11 in Fahreneit

by

float f = DHT.temperature * 1.8 + 32;
int whole = (int)f;  // take the whole part of the float
int decimal = (int) ((f-whole)*10);   // first decimal
u8g.print(whole);
u8g.print(".");
u8g.print(decimal);

splitting it up in pieces can help.


footnote: The DHT11 has only integer values for temperature and humidity, so no need to use floats there.

It looks like my problem was putting the float and calculations between lines 9 and 11, and then trying to print them later. Once I moved your code all together inside the "void draw(void) " section, it works fine.

Thank you for the help, now I am off to see how to log this somewhere. I have a dirt floor and cinder-block room under my brick porch on my new house that I want to use as a root cellar. I am looking to log the data every x minutes (maybe ten, maybe 30) and keep those values so I can track it throughout the year. I will also be putting a second dht11 outside of the root cellar to record the differences between the two.

Merry Christmas!

Better use a DHT22 as it more accurate and supports below zero (Celsius) temperatures.

did you do the storage math?

1 sample == 50 bytes? (including timestamp)

every 10 seconds → 6 / minute → 360 / hour → 9000 /day → 3.300.000 / year ==> 165 MB