Go Down

Topic: Class for DHT11, DHT21 and DHT22 (temperature & humidity) (Read 66731 times) previous topic - next topic

robtillaart

#30
Jul 09, 2012, 08:50 pm Last Edit: Jul 09, 2012, 08:54 pm by robtillaart Reason: 1
updated the code to 0.1.03;

+ added code to reflect faulty reading in temperature (-999)  and humidity (-999)  if there is a timeout. So if a sketch does not test the return value of read11() or read22() you will still see it clearly.

As allways comments still welcome
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

tochinet

One suggestion for the code is to replace or augment the read11 and read22 routines by one unique read routine that would detect which one it is and return 11 or 22 in chk.

I'm not sure it is _so_ easy, but for example, having both [2] and [4] zero with a DHT22 should almost never happen, right ?

They are the lsB if I get it right, so humidity has to be 25.6, 51.2 or 76.8 for byte[4] to be zero.
Then in that case temperature has to be precisely 25.6 etc.
Pretty unusual.

To be even more confident, there could be a "confidence" variable based on previous measurements:
increase/decrease  a uint8_t counter for every non/zero value with saturation @ +127/-128, so DHT11 goes from zero @reset to -128 and DHT22 to +127.

Another thing is to replace the double by an int in tenths of degrees. So for DHT11 it would return array[0]*10;

robtillaart

#32
Oct 14, 2012, 02:44 pm Last Edit: Oct 14, 2012, 02:47 pm by robtillaart Reason: 1
Quote
One suggestion for the code is to replace or augment the read11 and read22 routines by one unique read routine that would detect which one it is and return 11 or 22 in chk

Don't mix error state with configuration information. That said, one could make a function int determine() that does just that. Typically it is called just once and remembered - you just needs one byte to keep the 11/22 flag of 8 sensors.

Quote
I'm not sure it is _so_ easy, but for example, having both [2] and [4] zero with a DHT22 should almost never happen, right ?

possible but one could only account readings for which [2] and [4] are zero AND the checksum is OK.

Assuming a valid reading, both numbers have one decimal place 0..9 =>10 possible values. This implies that the chance would be about one in hundred for an individual reading to have two 0's as decimal. That is a small chance but too big imho to make a reliable determine() function, it is definitely not deterministic. Multiple readings with will improve this number but as the device needs 2 seconds between readings so determine() function becomes quite time consuming.

Note that especially for the DHT11 one can use a (running) average to get a higher precision - and thus decimal places ).
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

jrbenito

Hi robtllaart


updated the code to 0.1.03;

+ added code to reflect faulty reading in temperature (-999)  and humidity (-999)  if there is a timeout. So if a sketch does not test the return value of read11() or read22() you will still see it clearly.

As allways comments still welcome


I would change the follow code in read22() and read11() functions from

Code: [Select]

int rv = read(pin);
        if (rv != 0)
    {


to

Code: [Select]

int rv = read(pin);
        if (rv != DHTLIB_OK)
    {


No functionally change but improves readability.


robtillaart

That is very keen eye!  I will change it asap

Thanks,
Rob
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

updated on the playground to version 0.1.04

+ added the rv != DHTLIB_OK as suggested by jrbenito (thanks)
+ added #define DHTLIB_INVALID_VALUE  -999  to remove that magic number from the lib too.

Rob
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

jrbenito



+ added #define DHTLIB_INVALID_VALUE  -999  to remove that magic number from the lib too.

Rob


Wow! Very good too.

Thanks for this code and best regards,
Benito.

RoseMan

Hi,

Nice library.  However, it does not work correctly for negative temperatures.  I'm using version 0.1.04.  When a negative temperature is measured the class will return DHTLIB_ERROR_CHECKSUM.  The problem is at line 74 in dht.cpp.  Here bits[2] is modified, which makes the checksum calculation incorrect.  There are, of course, many ways to fix the problem.  I have fixed it by changing the code in the following way.

Old Code:
Code: [Select]
        int sign = 1;
        if (bits[2] & 0x80) // negative temperature
        {
                bits[2] = bits[2] & 0x7F;
                sign = -1;
        }
        temperature = sign * word(bits[2], bits[3]) * 0.1;


New Code:
Code: [Select]

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


Thanks for the library, and with this fix it is just perfect for me!

robtillaart

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

- http://playground.arduino.cc//Main/DHTLib -

updated the playground article to include the patch above.

Thanks again!
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Mark Ruys

No idea why someone wants to write code if there already exists a perfectly fine library... but... I just checked in a DHT library with the following features:
  - Support for DHT11 and DHT22, AM2302, RHT03
  - Auto detect sensor model
  - Very low memory footprint
  - Very small code

https://github.com/markruys/arduino-DHT

Maybe useful for someone - feel free to report bugs.

robtillaart

#41
Jun 11, 2013, 07:04 pm Last Edit: Jun 11, 2013, 07:06 pm by robtillaart Reason: 1
Well done Mark,

Looked at your code and it looks like a decent piece of work. It is similar to a version I'm working on and yes I better stop with that version ;)

The difference between your code and mine is that your code encapsulated an individual sensor while mine encapsulates the handshake so multiple sensors use one instance.
Footprint will differ too but not measured. I like the auto-detect functionality, well done

There is one improvement I want to propose to your class which I had build in my draft. If there is a time-out I would return the previous values instead of NaN. The error flag should still be the same. To do this the results temperature & humidity should have class scope.

If the program requests the temperature too fast it just gets the prev value which is seldom far from the actual value (instead of a NaN)

something like this
Code: [Select]


DHT::DHT_t DHT::read()
{
 // don't poll the sensor too often
 // - Max sample rate DHT11 is 1 Hz   (duty cycle 1000 ms)
 // - Max sample rate DHT22 is 0.5 Hz (duty cycle 2000 ms)

 unsigned long startTime = millis();
 if ( (startTime - lastReadTime) < getMinimalDelay()  )   // use the internal function
 {
  results.error = ERROR_TOO_QUICK;
  return results;  // returns previous temperature and humidity
 }
 lastReadTime = startTime;

 results.error = ERROR_NONE;
 results.temperature = NAN;
 results.humidity = NAN;
 // Request sample
 ...


the way I coded the interface was 3 public functions

Code: [Select]

float DHT::getHumidity()
{
 if ( millis() - lastReadTime > 2000 || status != ERROR_NONE )  // time to refresh or to retry
 {
   status = read();  // fetch new hum & temp
 }
 else
 {
   lastReadTime  = millis();
 }
 return humidity;
}


float DHT::getTemperature()
{
 if ( millis() - lastReadTime > 2000 || status != ERROR_NONE )
 {
   status = read(); // status and read() are private
 }
 else
 {
   lastReadTime  = millis();
 }
 return temperature;  // private member
}

float DHT::getStatus()
{
  status = read();  // fetch new data
}


typing this you could also add the "retry" condition.

my 2 cents,
regards / groeten,
Rob

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

MarsWarrior

Just a few questions while checking both DHT versions:

Rob:
- Has a delay of 20msec for both DHT11 and DHT22.
- Uses a counter in the while to break out of the while in case the pin does not change

Mark:
- Has a delay of 18msec for the DHT11 and 800usec for the DHT22.
- Uses an endless while loop, so if the pin does not change --> Arduino in endless loop!

Further:
- I am using multiple DHT22's on different pins. Which library would be most RAM efficient?
- Is the 800usec the right delay for the DHT22? If so, it saves me 5*19msec = 75msec of doing nothing, which is a lot using NilRTOS/ChibiOS RTOSses...

Please comment  8)

robtillaart

Quote
Rob:
- Has a delay of 20msec for both DHT11 and DHT22.
- Uses a counter in the while to break out of the while in case the pin does not change

The counter makes the loop fool proof.
The 20 mSec is to make code as similar as possible for both sensors, Mark optimizes the code to the detail of the datasheet which is good better ;)


Quote
I am using multiple DHT22's on different pins. Which library would be most RAM efficient?

Not tested, I expect the lib from mark be smaller for a single sensor but my lib can support multiple with one instance. Somewhere there must be a break even point.
It would be very informative if you could provide some numbers

Quote
- Is the 800usec the right delay for the DHT22? If so, it saves me 5*19msec = 75msec of doing nothing, which is a lot using NilRTOS/ChibiOS RTOSses...

800usec - check datasheet.

In an RTOS one should schedule another thread when delay is called, to return /test later. In pseudocode
Code: [Select]
delay(uint32_t ms)
{
  wakeUpThisThread(ms);
  switchThread();
}

This way one could always use the waiting time effective. (disclaimer, no RTOS expert)
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Mark Ruys

Thanks Rob for your suggestions. I just commited a new version of the library with the following changes:

  • Removed ERROR_TOO_QUICK. If you poll too often, you just get cached data

  • Removed read() and added getTemperature() and getHumidity(). This gives a much cleaner interface for the users.
  • Fixed DHT11 detection. Removed the detection from the class constructor to a seperate setup()



Code example:
Code: [Select]

#include "DHT.h"

DHT dht = DHT(2); // data pin 2, auto detect DHT model

void setup()
{
  dht.setup();
}

void loop()
{
  delay(dht.getMinimalDelay());

  Serial.print(dht.getHumidity(), 1);
  Serial.print("\t");
  Serial.println(dht.getTemperature(), 1);
}

Go Up