yet another DHT11 Class for Arduino

Thanks for this code for the DHT11. ... I use a pull-up of 10k on the data line.

you are welcome,

depending on the length of the wires a pull up helps to improve the signals edges

Robtillaart, Have you thought about using the (:source lang=c:) and (:sourcend:) for your code in the playground?

Hi Krodal,

I have updated the DHT lib pages, it looks def. better!

Thanks,

update to version 0.4.1 - Arduino Playground - DHT11Lib -

  • added #define error codes
  • use these in sample application

makes the code more readable, no functionality change.

Hi,
I am trying out your DHT11 librarys using both dht11_test1.pde and DHT11LIB_VERSION "0.4.1" but keep getting this error:

dht11\dht11.cpp.o: In function dht11::read(int)': C:\Program Files\Arduino-1.0\libraries\dht11/dht11.cpp:28: multiple definition of dht11::read(int)'
dht11.cpp.o:C:\DOCUME~1\DrWil\LOCALS~1\Temp\build8921908579828605482.tmp/dht11.cpp:28: first defined here

Is dht11::read(int) being redefined in the temp build folder?

Arduino software version 1.0.1
Arduino hardware version Duemilanove w/ ATmega328

Cheers

trousersalive:
I am trying out your DHT11 librarys using both dht11_test1.pde and DHT11LIB_VERSION "0.4.1" but keep getting this error

It is running fine with me.
Arduino 1.0.1.
The three files (not as library), and changed one thing in the example file: #include <dht11.h> into #include "dht11.h"

Rob Tillaart,

I don't know if I open an old issue, but I'm not convinced that the Arduino should set the line high. I read the datasheet over and over again, and I think it is not very clear but I read the datasheet as if the resistor pulls the line high.

The datasheet tells that the "DHT pulls up voltage...", but I assume it is an open collector output. So they mean the pull-up resistor. So when the datasheet tells that the "MCU pulls up voltage...", I think they mean it in the same way.

Your code:

        pinMode(pin, OUTPUT);
        digitalWrite(pin, LOW);
        delay(18);
        digitalWrite(pin, HIGH);
        delayMicroseconds(40);
        pinMode(pin, INPUT);

But this works as well:

        // The line should be set as INPUT_PULLUP.
        // Make it output to pull it down.
        // Wait at least 18ms, so let's wait 25ms
        pinMode(pin, OUTPUT);
        digitalWrite(pin, LOW);
        delay(25);
        pinMode(pin, INPUT_PULLUP);
        // The DHT11 will react in 20 - 40us.
        // Let's wait 50 to be sure it has responded.
        delayMicroseconds(50);

I use the resistor to make the pullup. So there will be no shortcut when the DHT11 pulls the line down.
I also wait 25ms, since 18ms is the minimum.
And I wait 50us, to be sure that the DHT11 has already pulled the line down.

from Arduino.h

#define HIGH 0x1
#define LOW  0x0

#define INPUT 0x0
#define OUTPUT 0x1
#define INPUT_PULLUP 0x2

HIGH and INPUT_PULLUP is clearly different values but digitalWrite handles them identically, so no difference in electrical behaviour.

from wiring_digital.c

void digitalWrite(uint8_t pin, uint8_t val)
{
	uint8_t timer = digitalPinToTimer(pin);
	uint8_t bit = digitalPinToBitMask(pin);
	uint8_t port = digitalPinToPort(pin);
	volatile uint8_t *out;

	if (port == NOT_A_PIN) return;

	// If the pin that support PWM output, we need to turn it off
	// before doing a digital write.
	if (timer != NOT_ON_TIMER) turnOffPWM(timer);

	out = portOutputRegister(port);

	uint8_t oldSREG = SREG;
	cli();

	if (val == LOW) {
		*out &= ~bit;
	} else {
		*out |= bit;
	}

	SREG = oldSREG;
}

The point is: In my code I let the Arduino never output 5V. The high level of the signal is only done by the resistors. This also prevents a shortcut when the Arduino outputs 5V and the sensor tries to pull it to ground.

The same goes for the DHT lib, Arduino Playground - DHTLib
The datasheet of the DHT22 tells: "...then MCU will pulls up and wait 20-40us for RHT03's response". The only way to wait for a response is to let the pull-up resistor make the signal high, and not by making the output high with the Arduino pin.

updated - Arduino Playground - DHT11Lib - ( dewpoint only)

changelog:

  • added some comments + references explaining the dewPoint algorithm.
  • a small performance improvement in dewPointFast (from 5x -> 6.9x as fast)
  • a small test program to compare the output of the two dewPoint algorithms.

Hi,

I took the liberty to make a few minor modifications to the code that you provided, and I wanted to share them with you. If you're interested, you can find my changes at:

Thanks,

Andy

Thanks for sharing this version, I added a link to your work in the playground article.

Most interesting change is to give the datapin in the constructor, so you have more the OO approach iso functional approach. To support multiple sensors you will make one unique object per sensor, where my approach is to have one object to rule them all.

some questions:

  • Did you measure the effect of the code changes on the footprint (per object) ?

  • Are you familiar with - Arduino Playground - DHTLib - which supports the DHT22 too (and DHT21 under test) ?
    This is my preferred lib for DHT sensors, and I still want to rewrite it in OO with a base class and 3 derived classes.

  • can you add a link to the playground in your code?

Final note, I see you used the goto statement to handle error conditions. Although you did it in a structured way to handle error conditions it is discouraged as goto's can disrupt code/stack/heap.

Hi Rob,

True, I didn't make any fundamental changes to what you had. I just reorganized it a bit.

To answer your questions:

robtillaart:

  • Did you measure the effect of the code changes on the footprint (per object) ?
  • No, I haven't measured the footprint. I imagine per object it should increase only by the sizeof(pin) (plus maybe some padding). The program text size may have increased some as well, but again I haven't measured.

robtillaart:

  • Are you familiar with - Arduino Playground - DHTLib - which supports the DHT22 too (and DHT21 under test) ?
    This is my preferred lib for DHT sensors, and I still want to rewrite it in OO with a base class and 3 derived classes.
  • No, I wasn't familiar with it -- thanks for the pointer. I took a stab at refactoring that version to the OO version that you mentioned, combined with the changes I introduced in the old version. You can find the new version at: arduino/projects/Dht_Library at master · adalton/arduino · GitHub. This version more exemplifies why I liked having the pin be part of the object (see the readSensor() function in the driver).

robtillaart:

  • can you add a link to the playground in your code?
  • Yes, absolutely! I actually intended to do that up front, but I made these changes late at night and it slipped my mind. I've already pushed the update.

robtillaart:
Final note, I see you used the goto statement to handle error conditions. Although you did it in a structured way to handle error conditions it is discouraged as goto's can disrupt code/stack/heap.

I'm not sure that I follow. Is there some flaw in the compiler that causes it not to properly handle gotos? From a structured programming perspective, neither goto nor having multiple returns is great, but I prefer this over multiple returns.

Thanks again!

Andy

Quote from: robtillaart on Today at 09:37:06 am
Final note, I see you used the goto statement to handle error conditions. Although you did it in a structured way to handle error conditions it is discouraged as goto's can disrupt code/stack/heap.

I'm not sure that I follow. Is there some flaw in the compiler that causes it not to properly handle gotos? From a structured programming perspective, neither goto nor having multiple returns is great, but I prefer this over multiple returns.

Thanks again!

Andy

No the biggest problem is programmers working further from your code.
Goto's jump in the code and if they aren't understood well a minor change can easily break the logic.
Yes that is also true for goto-less code but in my experience code with goto's often become spaghetti.
Maintainable code looks more like lasagne (layered architecture) :wink:

Just got started with Arduino this week, and my DHT11 just came in tonight. This one stumped me, primarily because everything talks about a sensor with four pins however mine only had three. I was trying the same layout 5v, Data, Ground without any luck. Turns out the three pin sensor is Data, 5v, Ground; unfortunately only ground is labeled on the sensor.

In case anyone runs into the same problem this article helped clear up the details for my sensor. http://www.geeetech.com/wiki/index.php/Electric_thermometer_by_using_DHT11_sensor_module

Thanks for the great library!

@jkestr,

thanks for using the library, I'll update the playground article with the link you posted.
Is very informative.
If there are any problems, please let me know.

I would like to thank you for the code for the DHT11. I made some changes to incorporate a second DHT11 and a serial LCD (LCM1602).I would like to make this available to others that need the help, like myself.

Thank you again.

/* YourDuino.com Example Software Sketch
   DHT11 Humidity and Temperature Sensor test
   Credits: Rob Tillaart */

/*-----( Import needed libraries )-----*/
#include <dht11.h>
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>

/*-----( Declare objects )-----*/
dht11 DHT11;
dht11 DHT11_2;

/*-----( Declare Constants, Pin Numbers )-----*/
#define DHT11PIN 2       //DHT11 Indoor
#define DHT11_2PIN 4     //DHT11 Outdoor

#define I2C_ADDR    0x27  // Define I2C Address where the PCF8574A is
#define BACKLIGHT_PIN     3  //This pin is internal. Do not edit.
#define En_pin  2            //This pin is internal. Do not edit.
#define Rw_pin  1            //This pin is internal. Do not edit.
#define Rs_pin  0            //This pin is internal. Do not edit.
#define D4_pin  4            //This pin is internal. Do not edit.
#define D5_pin  5            //This pin is internal. Do not edit.
#define D6_pin  6            //This pin is internal. Do not edit.
#define D7_pin  7            //This pin is internal. Do not edit.
LiquidCrystal_I2C       lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);

void setup()   /*----( SETUP: RUNS ONCE )----*/
{
  lcd.begin (20,4,LCD_5x8DOTS);
  lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE); // init the backlight
  lcd.setBacklight(HIGH);
  //Indoor rH setup
  lcd.setCursor (0,0);
  lcd.print("rH Inside:   %" );

  //degree symbol setup
  lcd.setCursor (11,1);
  lcd.print((char)223);
  lcd.print("C");
  lcd.setCursor (16,1);
  lcd.print((char)223);
  lcd.print("F");

  //Indoor temp setup
  lcd.setCursor (0,1);
  lcd.print("Temp In:");

    //Outside rH setup
  lcd.setCursor (0,2);
  lcd.print("rH Outside:   %" );

  //degree symbol setup
  lcd.setCursor (12,3);
  lcd.print((char)223);
  lcd.print("C");
  lcd.setCursor (17,3);
  lcd.print((char)223);
  lcd.print("F");

  //Outside temp setup
  lcd.setCursor (0,3);
  lcd.print("Temp Out:");

}/*--(end setup )---*/

void loop()   /*----( LOOP: RUNS CONSTANTLY )----*/
{
  int chk = DHT11.read(DHT11PIN);
  int chk_2 = DHT11_2.read(DHT11_2PIN);

  //LCD printing
  // DHT11 number 1 - Indoor
  lcd.setCursor (11,0); //set the cursor for hunidity
  lcd.print((float)DHT11.humidity, 0);
  lcd.setCursor (9,1); // set the cursor for temp
  lcd.print((float)DHT11.temperature, 0);
  lcd.setCursor (14,1); // set the cursor for F temp
  lcd.print(Fahrenheit(DHT11.temperature), 0);

  //DHT11 number 2 - Outdoor
  lcd.setCursor (12,2); //set the cursor for hunidity
  lcd.print((float)DHT11_2.humidity, 0);
  lcd.setCursor (10,3); // set the cursor for temp
  lcd.print((float)DHT11_2.temperature, 0);
  lcd.setCursor (15,3); // set the cursor for F temp
  lcd.print(Fahrenheit(DHT11_2.temperature), 0);

  delay(2000);
}/* --(end main loop )-- */

/*-----( Declare User-written Functions )-----*/
//
//Celsius to Fahrenheit conversion
double Fahrenheit(double celsius)
{
   return 1.8 * celsius + 32;
}

//Celsius to Kelvin conversion
double Kelvin(double celsius)
{
   return celsius + 273.15;
}

// dewPoint function NOAA
// reference: http://wahiduddin.net/calc/density_algorithms.htm
double dewPoint(double celsius, double humidity)
{
   double A0= 373.15/(273.15 + celsius);
   double SUM = -7.90298 * (A0-1);
   SUM += 5.02808 * log10(A0);
   SUM += -1.3816e-7 * (pow(10, (11.344*(1-1/A0)))-1) ;
   SUM += 8.1328e-3 * (pow(10,(-3.49149*(A0-1)))-1) ;
   SUM += log10(1013.246);
   double VP = pow(10, SUM-3) * humidity;
   double T = log(VP/0.61078);   // temp var
   return (241.88 * T) / (17.558-T);
}

// delta max = 0.6544 wrt dewPoint()
// 5x faster than dewPoint()
// reference: http://en.wikipedia.org/wiki/Dew_point
double dewPointFast(double celsius, double humidity)
{
   double a = 17.271;
   double b = 237.7;
   double temp = (a * celsius) / (b + celsius) + log(humidity/100);
   double Td = (b * temp) / (a - temp);
   return Td;
}

/* ( THE END ) */

Update moderator: added code tags

please modify your post and put code tags around it..
selct yout code and press the # button above the smileys and then press save.

Just got one of these devices and am using it on an Arduinio Pro. Note that Serial.begin() must be set to Serial.begin(9600) and (perhaps this is obvious, but not to a newbie like me) the pin to access the dht11 is a digital pin (2), not an analog pin.