HOME  > >  ARDUINO MAIN PAGE > >  HINTS AND HOW-TOs > >  NuELEC DATALOG  t.o.c.
Delicious.Com Bookmark this on Delicious    StumbleUpon.Com Recommend to StumbleUpon

DHT11 / Aosong AM2302 humidity and temperature sensor

(With some specifics relating to nuelectronics datalogging shield)


Oh, yes! If only everything could be so simple! (Ha! I wrote that five (working) hours ago. Using the module may be easy. Understanding everything in the code... not so easy.)

Stop press: If you visited this page before 10 March, and fetched code, be advised:

There is a place where the code used to say....

delayMicroseconds(40);//DHT22 datasheet says..

Information came in from a helpful reader that the program works more reliably if you change the 40 to 30. (It now says 30 on this page, but it didn't, before 9 Mar 13). There are more details at the relevant line, in the code.

__________________
Anyway....

I plugged my DHT11 sensor into my Arduino, loaded some demo software, changed one line (made...

Serial.begin(19200);

... into...

Serial.begin(9600);

And it Just Worked!! A nice stream of humidity and temperature reading appeared on my Arduino serial monitor as soon as I switched to it after uploading the program. Nothing beyond a "basic" Arduino setup is needed.

Credit where due: The demo software, and my awareness of the sensor came from using the NuElectronics datalogging shield. There was nothing in what I did with the DHT11 which "needed" the shield, though.

Remember: To run EXACTLY like this, the sensor needs to be plugged into the input that the NuElectronics shield "fed" from its "P4". Change the #define line if you want to use it elsewhere.

The only connections you need to the very reasonably priced module are: +5v, gnd (zero volts), and a free analog data line. That line is used in a digital mode, but because of the way the software is written, it is hard to move the sensor to a line other than D14-19, aka analog A0-5. I've done a separate page about signal usage on the nuelectronics datalogging shield, which you may want to consult.



Just Do It

The code immediately below is not properly tested, commented, etc, etc... but it may work. This block of code was just "dropped into" a better webpage. Later, we will return to that more sober, more carefully done material. What you see below was edited by hand after testing. Errors may have crept in. It is an attempt at a "clean" version of the code I derived from the nuelectronics suggested code. If it doesn't "just work", just go on to the other two code listings. Both of them SHOULD work. If you find that either of them do work for you, but the code immediately below doesn't, please let me know? If you want more than just "the answer" to "how do I read the sensor, read the rest of this page. But the following code SHOULD work....

"Cleanest", but least tested code for reading DHT11, DHT22, AM2303

//ReadHumTturDHT11alternate2-tweaked by hand for webpage
//vers 20Jly10-tweaked by hand for webpage

//See for more information....
//http://sheepdogguides.som/arduino/ar3ne1humDHT11.htm

//N.B. "bit" is used in the narrow, computer "1 or 0"
//   sense throughout.

//"DHT" from sensor's names: DHT11, DHT22.
//DHT aka Aosong AM2302, and there's an AM2303 which
//seems to be in the same family.

//Comments on this based on Aosong AM2302, aka DHT22, datasheet.
//Believed to generally apply to DHT11 as well, except in the
//case of the DHT11, I believe the second and fourth bytes are
//always zero.

//***N.B.****
//The comments may not yet be EXACTLY right.
//See the web-page cited above for latest news.

//Works with Aosong DHT11. Only 3 wires are involved:
//Vcc, ground, and a single data line. No extra components
//needed. One of the DHT11's 4 pins goes nowhere.

//You should not need to change anything except the next line to use
//the software with the sensor on a different line, or for a DHT22.

//Just "huffing" on the sensor from deeply filled lungs should show
//a near-instant rise in humidity

#define dht_dpin 14 //no ; here. Set equal to channel sensor is on,
     //where if dht_dpin is 14, sensor is on digital line 14, aka analog 0
     //Other digital lines can be used, e.g. D2

byte bGlobalErr;//for passing error code back from complex functions.
byte dht_dat[5];//Array to hold the bytes sent from sensor.
//  That was, wrongly, ..dat[4] until 28 Jan 13. See
//  http://sheepdogguides.com/arduino/aht9ArrIndex
//  for guidance on array index gotcha

void setup(){
InitDHT();//Does what's necessary to prepare for reading DHT
Serial.begin(9600);
delay(300);//Let system settle
Serial.println("Humidity and temperature\n\n");
delay(700);//Wait rest of 1000ms recommended delay before
  //accessing sensor
}//end "setup()"

void loop(){
  ReadDHT();//This is the "heart" of the program.
      //Fills global array dht_dpin[], and bGlobalErr, which
      //will hold zero if ReadDHT went okay.
      //Must call InitDHT once (in "setup()" is usual) before
      //calling ReadDHT.
  //Following: Displays what was seen...
  switch (bGlobalErr){
    case 0:
	Serial.print("Current humidity = ");
	Serial.print(dht_dat[0], DEC);
	Serial.print(".");
	Serial.print(dht_dat[1], DEC);
	Serial.print("%  ");
	Serial.print("temperature = ");
	Serial.print(dht_dat[2], DEC);
	Serial.print(".");
	Serial.print(dht_dat[3], DEC);
	Serial.println("C  ");
        break;
     case 1:
        Serial.println("Error 1: DHT start condition 1 not met.");
        break;
     case 2:
        Serial.println("Error 2: DHT start condition 2 not met.");
        break;
     case 3:
        Serial.println("Error 3: DHT checksum error.");
        break;
     default:
        Serial.println("Error: Unrecognized code encountered.");
        break;
     	}//end "switch"
  delay(800);//Don't try to access too frequently... in theory
                   //should be once per two seconds, fastest,
                   //but seems to work after 0.8 second.
}// end loop()

/*Below here: Only "black box" elements which can just be plugged
  unchanged into programs. Provide InitDHT() and ReadDHT(), and a function
  one of them uses.*/

void InitDHT(){
        pinMode(dht_dpin,OUTPUT);
        digitalWrite(dht_dpin,HIGH);
}//end InitDHT

void ReadDHT(){
/*Uses global variables dht_dat[0-4], and bGlobalErr to pass
  "answer" back. bGlobalErr=0 if read went okay.
  Depends on global dht_dpin for where to look for sensor.*/
bGlobalErr=0;
byte dht_in;
byte i;
  // Send "start read and report" command to sensor....
  // First: pull-down I/O pin for 23000us
digitalWrite(dht_dpin,LOW);
delay(23);
/*aosong.com datasheet for DHT22 says pin should be low at least
  500us. I infer it can be low longer without any]
  penalty apart from making "read sensor" process take
  longer. */
//Next line: Brings line high again,
//   second step in giving "start read..." command
digitalWrite(dht_dpin,HIGH);
delayMicroseconds(30);//DHT22 datasheet says host should
   //keep line high 20-40us, then watch for sensor taking line
   //low. That low should last 80us. Acknowledges "start read
   //and report" command.
   //Getting the delay exacly right is critical...
   //  put 40 in for the delay, in one of the later
   //  editions of this code, and the program
   //  will work SOMETIMES, but not ALWAYS.
   //  You have to allow for processing overheads,
   //  etc, too. Using, say, 30 won't "magically"
   //  make the TOTAL delay (with overheads, etc)
   //  exactly 30.0000 milliseconds. (This version may
   //  also have been unreliable with delay=40.. now
   //  deprecated.)
//Next: Change Arduino pin to an input, to
//watch for the 80us low explained a moment ago.
pinMode(dht_dpin,INPUT);
delayMicroseconds(40);

dht_in=digitalRead(dht_dpin);

if(dht_in){
   bGlobalErr=1;//dht start condition 1 not met
   return;
   }//end "if..."
delayMicroseconds(80);

dht_in=digitalRead(dht_dpin);

if(!dht_in){
   bGlobalErr=2;//dht start condition 2 not met
   return;
   }//end "if..."

/*After 80us low, the line should be taken high for 80us by the
  sensor. The low following that high is the start of the first
  bit of the forty to come. The routine "read_dht_dat()"
  expects to be called with the system already into this low.*/
delayMicroseconds(80);
//now ready for data reception... pick up the 5 bytes coming from
//   the sensor
for (i=0; i<5; i++)
   dht_dat[i] = read_dht_dat();

//Next: restore pin to output duties
pinMode(dht_dpin,OUTPUT);

//Next: Make data line high again, as output from Arduino
digitalWrite(dht_dpin,HIGH);

//Next see if data received consistent with checksum received
byte dht_check_sum =
       dht_dat[0]+dht_dat[1]+dht_dat[2]+dht_dat[3];
/*Condition in following "if" says "if fifth byte from sensor
       not the same as the sum of the first four..."*/
if(dht_dat[4]!= dht_check_sum)
   {bGlobalErr=3;}//DHT checksum error
};//end ReadDHT()

byte read_dht_dat(){
//Collect 8 bits from datastream, return them interpreted
//as a byte. I.e. if 0000.0101 is sent, return decimal 5.

//Code expects the system to have recently entered the
//dataline low condition at the start of every data bit's
//transmission BEFORE this function is called.

  byte i = 0;
  byte result=0;
  for(i=0; i< 8; i++){
      //We enter this during the first start bit (low for 50uS) of the byte
      //Next: wait until pin goes high
      while(digitalRead(dht_dpin)==LOW);
            //signalling end of start of bit's transmission.

      //Dataline will now stay high for 27 or 70 uS, depending on
            //whether a 0 or a 1 is being sent, respectively.
      delayMicroseconds(30);//AFTER pin is high, wait further period, to be
        //into the part of the timing diagram where a 0 or a 1 denotes
        //the datum being send. The "further period" was 30uS in the software
        //that this has been created from. I believe that a higher number
        //(45?) might be more appropriate.

      //Next: Wait while pin still high
      if (digitalRead(dht_dpin)==HIGH)
 	   result |=(1<<(7-i));// "add" (not just addition) the 1
                      //to the growing byte
    //Next wait until pin goes low again, which signals the START
    //of the NEXT bit's transmission.
    while (digitalRead(dht_dpin)==HIGH);
    }//end of "for.."
  return result;
}//end of "read_dht_dat()"

I've done a more thorough exploration of the "fancy" code in the demo, and of what I did while converting it to the above, if you want to understand what was in the old code.



Properly tested and explained humidity sensor reading code

As I said: The code above is not properly tested, commented, etc, etc... but it may work. That section was just "dropped into" a better webpage. Here we return to that more sober, more carefully done material.

The code below, (immediately below the "stop press" notice"!) uses some "fancy" commands. I will discuss them later.

It also looks vast and complicated. Don't be alarmed by all the comments. Ignore them, if it makes you happier! Connect three wires. Maybe change one line of the code (the "#define" line. There's no need to change it, if you connected your sensor to analog0, aka digital14, aka nuelectronics shield P4.) And it should just work!

STOP PRESS: BETTER CODE....

There is what may be a better version, down at the end of the page.


Pretty Good code... and least "messed about with"... very closely related to the code recommended by nuelectronics...

//ReadHumTturDHT11alternate
//vers 19Jly10

//See for more information....
//http://sheepdogguides.som/arduino/ar3ne1humDHT11.htm

//N.B. "bit" is used in the narrow, computer "1 or 0"
//   sense throughout.

//Comments on this based on Aosong AM2302, aka DHT22, datasheet.
//Believed to generally apply to DHT11 as well, except in the
//case of the DHT11, I believe the second and fourth bytes are
//always zero.

//***N.B.****
//The code WORKS... the comments may not yet be EXACTLY right.
//See the web-page cited above for latest news.

//This code works with a DHT11 humidity/ temperature sensing module
//from nuelectronics.com, complied with vers 0018 of the Arduino environment
//Sensor attached to P4 (nuelectronics shield)/ analog 0, aka digital 14.

//That "module", according to the
//nuelectronics site, and visual inspection simply provides for easy
//connection of an Aosong DHT11 unit to the nuelectronics datalogging
//shield. Only 3 wires are involved: Vcc, ground, and a single data
//line. One of the DHT11's 4 pins goes nowhere.

//You should not need to change anything except the next line to use
//the software with the sensor on a different line, or for a DHT22.

//Just "huffing" on the sensor from deeply filled lungs should show
//a near instant rise in humidity

#define DHT11_PIN 0      // ADC0...
  //even though we are using it as a digital pin.
  //Other parts of code restrict us to using
  //ADC0-5, aka D14-19

byte read_dht11_dat()
//Collect 8 bits from datastream, return them interpreted
//as a byte. I.e. if 0000.0101 is sent, return decimal 5.

//Code expects the system to have recently entered the
//dataline low condition at the start of every data bit's
//transmission BEFORE this function is called.
{
  byte i = 0;
  byte result=0;
  for(i=0; i< 8; i++){
  //We enter this during the first start bit (low for 50uS) of the byte
  while(!(PINC & _BV(DHT11_PIN)));  // wait until pin goes high
           //signalling end of start of bit's transmission.
  //Dataline will stay high for 27 or 70 uS, depending on if
  //   a 0 or a 1 is being sent, respectively
  delayMicroseconds(30);//AFTER pin is high, wait further period, to be
      //into the part of the timing diagram where a 0 or a 1 denotes
      //the datum being send. The "further period" was 30uS in the software
      //that this has been created from. I believe that a higher number
      //(45?) would be more appropriate.

  if(PINC & _BV(DHT11_PIN))//If pin still high
	result |=(1<<(7-i));// "add" (not just addition) the 1 to the
                //growing byte
  while((PINC & _BV(DHT11_PIN)));  // wait for pin to go low again, which
          //signals he START of the NEXT bit's transmission.
  }//end of "for.."
  return result;
}//end of "read_dht11_dat()"


void setup()
{
	DDRC |= _BV(DHT11_PIN);//set data pin... for now... as out(?)put
              //DDRC is data direction register for pins A0-5 are on
	PORTC |= _BV(DHT11_PIN);//(dis?)-connect internal pull up on line
              //PORTC relates to the pins A0-5 are on.
Serial.begin(9600);
delay(300);//Let system settle
Serial.println("Humidity and temperature\n\n");
delay(700);//Wait rest of 1000ms recommended delay before
  //accessing sensor.
	}

void loop()
{
	byte dht11_dat[5];//Array to hold the bytes sent from sensor. 0-4 should be enough
           //don't believe dht11_dat[5] is used.
	byte dht11_in;
	byte i;
	// Send "start read and report" command to sensor....
	// 1. pull-down i/o pin for 18ms
	PORTC &= ~_BV(DHT11_PIN);
	delay(18);
        delay(5);//TKB, from Quine at Arduino forum
        //Aosong datasheet for DHT22 says pin should be low at least
        //500us. I infer it can be low longer without any]
        //penalty apart from making "read sensor" process take
        //longer
	PORTC |= _BV(DHT11_PIN);//Bring line high again
	delayMicroseconds(30);//DHT22 datasheet says host should
           //keep line high 20-40us, then watch for sensor taking line
           //low. That low should last 80us. Acknowledges "start read
           //and report" command.
           //Getting the delay exacly right is critical...
		   //  put 40 in for the delay, in one of the later
		   //  editions of this code, and the program
		   //  will work SOMETIMES, but not ALWAYS.
		   //  You have to allow for processing overheads,
		   //  etc, too. Using, say, 30 won't "magically"
		   //  make the TOTAL delay (with overheads, etc)
		   //  exactly 30.0000 milliseconds. (This version may
		   //  also have been unreliable with delay=40.. now
		   //  deprecated.)


	DDRC &= ~_BV(DHT11_PIN);//Change Arduino pin to an input, to
           //watch for the 80us low explained a moment ago.
	delayMicroseconds(40);

	dht11_in = PINC & _BV(DHT11_PIN);

	if(dht11_in){
		Serial.println("dht11 start condition 1 not met");
		return;
	}
	delayMicroseconds(80);

	dht11_in = PINC & _BV(DHT11_PIN);

	if(!dht11_in){
		Serial.println("dht11 start condition 2 not met");
		return;
	}

        //After 80us low, the line should be taken high for 80us by the
        //sensor. The low following that high is the start of the first
        //bit of the forty to come. The routine "read_dht11_dat()"
        //expects to be called with the system already into this low.
	delayMicroseconds(80);
	//now ready for data reception... pick up the 5 bytes coming from
        //   the sensor
	for (i=0; i<5; i++)
		dht11_dat[i] = read_dht11_dat();

	DDRC |= _BV(DHT11_PIN);//restore pin to in?out?put duties
	PORTC |= _BV(DHT11_PIN);//re-(dis?) connect internal pullup?

        byte dht11_check_sum = dht11_dat[0]+dht11_dat[1]+dht11_dat[2]+dht11_dat[3];
	// check check_sum
	if(dht11_dat[4]!= dht11_check_sum)
        //says "if fifth byte from sensor not the same as the sum of the first four..."
	{
		Serial.println("DHT11 checksum error");
	}

	Serial.print("Current humidity = ");
	Serial.print(dht11_dat[0], DEC);
	Serial.print(".");
	Serial.print(dht11_dat[1], DEC);
	Serial.print("%  ");
	Serial.print("temperature = ");
	Serial.print(dht11_dat[2], DEC);
	Serial.print(".");
	Serial.print(dht11_dat[3], DEC);
	Serial.println("C  ");

	delay(800);//Don't try to access too frequently
}


STOP PRESS: BETTER CODE....

There is what may be a better version, down at the end of the page.



DHT11, DHT22, Aosong AM2303

My first experience of this apparent family of devices came with the well made module from nuelectronics, part of their range for their very reasonably priced datalogging shield for the Arduino. It was described as being DHT11 based.

In the course of working with that, I encountered mention of a DHT22 and found the AM2302 and AM2303 on the aosong.com site.

Now- I am not complaining. Multiple product codes and similar devices are just a fact of life. I deal with it (mostly). But I mention it in case you are also doing research and wonder if you are going mad. (An Aosong datasheet clearly states that the AM2302 is also called a DHT22.)

I believe that the four devices, if they are not two devices by two names, or something like that, can be interchanged. The hardware appears to have similar specs. It seems that it would respond "nicely" to the same software.

One "little nasty": I suspect that the DHT11, while it will return something for the fractional parts of the humidity and temperatures sensed, will only ever return "zero". This might seem daft, but think about it: If the DHT22 returns something other than zero for the fractional part, isn't it nice that you don't have to change your code if you decide to upgrade your sensor? That's what I guess the logic to be, anyway. I've looked closely at the code, and it seems to me that the sensor truly is returning zeros; it does not seem that there's a bug in the code.

Word of advice: While the sensor does have a temperature sensor, that may be affected by being on the PCB with the humidity sensor. While it will of course be an indication of ambient temperatures, when adding a separate temperature sensor is so easy, if you need accurate temperatures, it might make sense to do that.

Operating environment

After the next section, specifications, we will start a long exploration of the details of using these sensors. Remember that you can Just Use the code already presented.

Here are a few things I've learned about the "care and feeding" of the sensors...

The sensors should not be used where there is very high humidity- steam rooms, or places dew falls. (The DHT11 specifies the operating range as 20-90% RH.)

Exposing them to some chemical vapors may interfere with the sensor and degrade its sensitivity.

If you have a problem arising from too much humidity, or some bad vapors, the following may effect a cure:

Step one: Expose the sensor to a dry (<10% RH) 50° to 60° Celsius for 2 hours.

Step two: Expose the sensor to a 70% - 85% RH at 20° to 30° Celsius for 5 hours.

Note: Relative humidity strongly depend on temperature. That is why temperature compensation technology is used in the sensor to promote accurate measurement of RH. If you have a sealed jar with 50% RH at one temperature, at a different temperature, you may see a different RH... or you may not. It may be necessary to arrange for the pressure in the jar to stay constant as well as the water in the air, while changing the temperature. Bottom line: Relative humidity is NOT a simple concept!

Long time exposure to strong light or ultraviolet may degrade the sensor's performance.

Specifications

At the Aosong website, I learned that it isn't recommended that the sensor be interrogated too frequently. The minimum time between reads for one was 1.7 seconds, for another: 2 seconds. Not "long" in human terms, but without a "delay" line in your "loop()" function, you're going to read too often!

The back of my sensor, from nuelectronics, July 2010, says:

From the Aosong website, I picked up the following for similar sensors...

Data on the AM2302. The data sheet says that "DHT22" is another name for the AM2302

Data on the AM2303.

Interfacing with the humidity / temperature sensor

P.S. Oh dear. The following, it turned out after I'd spent about three ours on it, isn't quite right! But fear not! It is All Good Stuff. The only part that is wrong is how the sensor sends the forty 1's and 0's it sends. Believe almost everything you see below. Just be ready to "adjust" things you read about how the 1's and 0's are "seen". Everything else is fine as it is! Whew. Even the slightly wrong story is worthy of study, as some systems work exactly as below.

I am now, as I hope you will see, carrying on what I was saying earlier. What follows is meant to give weight to my assertions about the DHT11 really just returning zeros for the "fraction" part of the readings. It is also part of your preparation for later discussions about how the code is put together.

In broad terms, here's how the sensor module works:

It generally "just sits there". It has to be "woken up" by a signal from the system it is plugged into, hereafter called the "host". For the code above to "just work", the host must be an Arduino, but the protocol is simple, and should be easy enough to port to other microcontrollers, e.g. PICs.

Once "woken up", the sensor, after an interval, sends forty 1's and 0's back to the host, as one big undifferentiated stream. This makes it (relatively) easy to read the response. It is up to the host to "chop" that stream into five 8 bit binary numbers.

I should mention two things in passing:

1) The sensor has four pins, but only three of them are used: Vcc, data, ground.

2) The data pin is sometimes sending output from the sensor, sometimes accepting data into the sensor. Be careful: You can't interconnect two outputs willy/ nilly. But THIS data pin, and an Arduino data pin can talk to one another, swapping data direction as the conversation proceeds, if you use the right software.

To make things easy, we will say that the humidity is 11.22 %, and the temperature is 33.44 degrees C.

If those were the conditions, I would expect the following stream of 1's and 0's from the sensor when it is asked to respond.....

0000101100010110001000010010110001101110

What??

What?? I hear you cry!!

Fear not... I'll explain. But I want beginners aware of as much of the detail as I can convey.

Like that, the datastream looks hopelessly arcane. But, if you were to "look" at what comes from the sensor, I think that's what you would see. For the conditions I specified.

Let's break it up into it's parts. There's nothing in the "real world", nothing in the signal, voltages, timings, etc, to tell anyone where to split that stream into five blocks of 8 bits. You just have to "know"

My prior mess, with a few carriage returns, becomes...

00001011
00010110
00100001
00101100
01101110

If you convert those numbers from binary to decimal, you get....

 11
 22
 33
 44
110

Those are the simplest possible interpretations of those patterns of binary digits, bits, 1's and 0's, after they have been grouped into sets of eight. "by eight"s... "byte"s... get it? (Not important if not)

Note that there are other ways of interpreting bytes. 01000001 is sometimes used to stand for "A". Or for 41. But today, happily, we aren't "being clever".

Remember that I stipulated an environment with that pattern in it's figures. We're not done with the first four numbers, but we're going to look at the last one next.

The sensor's designers were worried that the message from the sensor might be misread by the host. So they used an old trick: A checksum. As the sensor was sending 11, 22, 33 and 44, it was adding them together. The result is 110. The sensor then sent that to the host, too. As the host received the first four numbers, it, independently, added up the numbers it had received. The host then fetched the fifth number, and compared that to the total the it had. If they match, the data was probably received correctly. (It would be possible for the data to have been received as 10,23,33,44,110 which would still pass the checksum test... but exactly complementary errors are extremely unlikely.

Going back to the first four numbers "hidden" in the forty bits: I lied. I said I'd expect the sensor to send the binary stream stated. In fact, if the sensor is a DHT11, I would guess it would actually send the binary equivalent of....

 11
  0
 33
  0
 44

Note it is and it isn't sending the fractional part of the humidity and temperature. Instead of a meaningful number in the 2nd and 4th parts of the datastream, a DHT11, I think, always sends a zero. From things I have read, I think the DHT22 does send meaningful numbers for the fractional parts of the readings. I.e., I think a DHT22 would send the binary equivalent of 11,22,33,44,110

I am quite confident that my grasp of this is correct as the software does look at the checksum, and it does not read the 2nd and 4th parts of the stream differently from how it reads the rest.

Enough? Remember: the code at the top does work! The rest of this is knowledge for anyone trying to tinker with it. You have to understand the sensor before you can write, or analyze, code that will work with it!

Why such "fancy" code?

The "strange" stuff in the code above may merely reflect the experience of the person who wrote it. It is elegant, it does use perfectly respectable "words" and operators. But it also goes well beyond some of the basic "words" and operators familiar to beginners.

Remember that the job of the software is to watch a digital input while forty 1's and 0's go by? How does the software "know" that the first bit has been sent, and that what it is now "seeing" is the second bit? If the first two bits are 1 and 0, then the change of the pin's state is a hint. But how can software know the difference between 00010 and 001000 by changes of state alone?

The next paragraph isn't quite right for how the DHT11 works... but, for the moment, pretend it is!

The software can't tell the difference between 00010 and 001000. The "trick" is that the sensor sends the 1's and 0's at a very precise speed.

Let's pretend that it is sending one bit per second, starting 5 seconds after the signal from the host to send the humidity and temperature data. The following software would then be what we need....

While the "delay before start" is not 5 seconds, and the "time per bit" is not 1 second, what actually happens is otherwise as the above.... with a little twist...

The sending of the data is (almost) exactly as above.

The receiving is fancied up a bit. In pseudo-code:

Create 5 element array DataByte[0]... DataByte[4]
Create variables ECounter, BCounter
         (for "element counter, bit counter)

Tell sensor to start sending
Wait for the period "time 'til data stream starts"
Wait for one half of the time a bit is left on the data line

Counter=0

REPEAT:
   DataByte[ECounter]=0

   FOR BCounter= 0 to 7 do...
       Read a bit. Change contents of DataByte[ECounter]
       Wait for start of next bit
       //End of FOR loop

   ECounter=ECounter+1
UNTIL ECounter > 4

That "Change contents" is deliberately a bit vague. Basically, as we go through the "FOR" loop, if we get 0,0,0,0,0,1,0,1, we should, at the end, have "5" in the relevant element of the DataByte array. (Binary 000001010 is "5" in our usual system for writing down numbers.) The "tricks" for assembling a number from a stream of bits can give you a headache, but they are simple... really. When you know how. But they'd be a distraction here. Just trust me?

A detail: We are assuming, with reason, that the time to "read a bit" and to "change contents" will be but a tiny fraction of the time a bit is displayed.

Shake your head. Deep breath. That's pretty well "it". But there's more to say about it, of course.

The nuelectronics code analyzed

If you think about what I've just explained, you should see that the software must execute at a precise speed. That may be the reason that more programmer-friendly words weren't used in the program code.

Oh dear. What I meant to say was...

It turned out, after three hours of creating the above, that there was a small flaw in my grasp of how the forty 1's and 0's are sent. But don't worry! Almost everything above is exactly right. And the detail I'm about to go into means that the messages from the sensor are more robust than they would be in the scenario I painted.

I went to the aosong.com site and collected the datasheet for an AM2302/ DHT22. You may think that it "isn't clear", but I assure you: It is much more clear than many documents of its kind. The author may not use English as his first language, but he does convey what you need to know. Want to complain? Learn traditional Chinese and read the original datasheet. The datasheet's translator's English is brilliant compared to my traditional Chinese.

There's very little wrong in what I've told you so far. The problem was in the bit where I asked/ said....

"How can the software know the difference between 00010 and 001000 by changes of state alone? It can't. The "trick" is that the sensor sends the 1's and 0's at a very precise speed.

That's only true if the system simply sends a 0 or a 1 for a fixed period of time, and then sends the next bit.

The DHT22 (and probably all the other sensors mentioned in this essay) does something more clever. The "cleverness" has a price: It takes more time to send the forty bits than "my" simple method. But it sends them with a way to keep the sending more reliable. It sends them in a way that is harder to misread.

At the end of getting ready for the forty bits to be sent, and at the end of sending each of them, the data line is high. At the start of sending every bit, be it a 1 or a 0, the sensor causes the data line to go low for 50us (micro seconds). This is the "bit starting" signal. After 50us, the sensor makes the data line high again... for 27us if it is sending a 0, for 70 us if it is sending a 1.

Sorry for the confusion. Imagine how my heart sank when I saw the error?

The pseudo-code used to say....

...
Wait for the time a bit is displayed
...

... where it now says...

...
Wait for start of next bit
...

Previously you should have worried: "How do I know the next bit has started?".... but I suspect (and hope) that didn't occur to you. Now that I have corrected my explanation of how the forty 1's and 0's are sent, I hope you aren't worried about knowing a bit is starting?

Within the "read_dht11_dat()" function, something quite clever... if hard to grasp or explain... is being done. At the start of each pass through the "for..." loop, the program should ALREADY be in the part of the timing diagram when the pin is low, the transmission of the 50us "bit starting" signal is being sent. And the "for..." loop code ends with waiting for the start of the next 50us "bit starting" signal, dataline low.

(The pseudo-code is a bit "off" regarding how the start of the whole "read from sensor" process progresses, but it isn't far off! The principles in reality are the same as the mechanism I said was at work. Instead of certain periods of time passing, "edges" (changes from high to low, or from low to high) will be the important issues. Time still plays a role, because you are "promised" that things will happen more or less at certain times, and that you will have stated intervals to "notice" that something has changed state.)

Wow. I reached this point in this essay perhaps five hours into writing this page, having just spent an intense period going through the nuelectronics- supplied "read sensor" code, looking at each line closely. They... the sensor and the code... are marvelous! I have a few "issues" with how the elements of the code are "wrapped"... I shall be making an alternative version... but after the intense inspection, I see that it is clever! And looks sound! My code, in principle, will not be very different. It will differ just in the organization of the code.

Most of the "hard" code in the program is either broadly equivalent to a "pinMode()" command (DDRC lines), or a digitalRead() or digitalWrite() ("PORTC |=" lines.) You'll see a mysterious "_BV()" in several places. It takes a binary 00000001 and moves the "1" left a number of places. "_BV(2)" results in 00000100... or is it 00000010? Something like that. I will try to build another page someday, with more details... especially if my attempt to re-write the code without the "clever" bits fails. (My code may be a bit longer than the original, too. There has been a discussion of this conversion quest at the Arduino forum.)

Concluding... for now... remarks...

I've seen notes at the Arduino forum speaking of interfacing a DHT22... seems as easy. This thread also talks about the "fraction always zero" issue.

There were also "complaints" about these sensors... I'm not convinced (yet!) that there is a problem... but I haven't had my sensor long.

I don't care if I resolve it! The temperature reading is only the temperature of the chip, which is subject to heating by the processes going on within it. It will be loosely connected to ambient temperature... useful... but an accurate reading of ambient temperature is best achieved by other, simple, inexpensive means.

STOP PRESS: BETTER CODE....

(But see "better better" farther down the page!)

I haven't time, now, to write up everything that might be said about the following. It does essentially what the code above did... but BETTER. Please let me know if you use this, and if you encounter any difficulties with it.

For many months, at this point there was text saying "Try the version at the top of the page first"

At 3/13, I can't think why I would have said that. I think it should have said "Try the version at the BOTTOM of the page first". Sorry.

Anyway... following the "top/bottom" text, I had the following which remains true... but I'm not sure which version of the code is which... except that the one at the bottom of the page is the one I would try first, if I were you!

(Some version or other... old text... )... MAY be better... but it is less well tested than what is below (above?). And what is below(above?) retains comments explaining how I got from the nuelectronics-suggested code to what's below(above?)... if you want to know.

ARGH! Here's one version, anyway. And remember: The one at the end of the page is probably the best. It is the latest sent to me. I just sort of take it on faith that only a sensible person would get around to bothering to send his work, and he must have found something to fix to bother writing.

//ReadHumTturDHT11alternate2
//vers 19Jly10

//This is a re-written DHT11/ DHT22 reading code.
//DHT stuff in subroutines.

//See for more information....
//http://sheepdogguides.som/arduino/ar3ne1humDHT11.htm

//N.B. "bit" is used in the narrow, computer "1 or 0"
//   sense throughout.

//"DHT" from sensor's names: DHT11, DHT22.
//DHT aka Aosong AM2302, and there's an AM2303 which
//seems to be in the same family.

//Comments on this based on Aosong AM2302, aka DHT22, datasheet.
//Believed to generally apply to DHT11 as well, except in the
//case of the DHT11, I believe the second and fourth bytes are
//always zero.

//***N.B.****
//The code WORKS... the comments may not yet be EXACTLY right.
//See the web-page cited above for latest news.

//This code works with a DHT11 humidity/ temperature sensing module
//from nuelectronics.com, complied with vers 0018 of the Arduino environment
//Sensor attached to P4 (nuelectronics shield)/ analog 0, aka digital 14.

//That "module", according to the
//nuelectronics site, and visual inspection simply provides for easy
//connection of an Aosong DHT11 unit to the nuelectronics datalogging
//shield. Only 3 wires are involved: Vcc, ground, and a single data
//line. One of the DHT11's 4 pins goes nowhere.

//You should not need to change anything except the next line to use
//the software with the sensor on a different line, or for a DHT22.

//Just "huffing" on the sensor from deeply filled lungs should show
//a near instant rise in humidity

//#define dht_PIN 0      //no ; here. deprecate ADC0...
  //even though we are using it as a digital pin.
  //Other parts of code restrict us to using
  //ADC0-5, aka D14-19
#define dht_dpin 14 //no ; here. Set equal to channel sensor is on,
     //where if dht_dpin is 14, sensor is on digital line 14, aka analog 0

byte bGlobalErr;//for passing error code back from complex functions.
byte dht_dat[5];//Array to hold the bytes sent from sensor.

void setup(){
InitDHT();//Do what's necessary to prepare for reading DHT
Serial.begin(9600);
delay(300);//Let system settle
Serial.println("Humidity and temperature\n\n");
delay(700);//Wait rest of 1000ms recommended delay before
  //accessing sensor
}//end "setup()"

void loop(){
  ReadDHT();//This is the "heart" of the program.
      //Fills global array dht_dpin[], and bGlobalErr, which
      //will hold zero if ReadDHT went okay.
      //Must call InitDHT once (in "setup()" is usual) before
      //calling ReadDHT.
  //Following: Display what was seen...
  switch (bGlobalErr){
     case 0:
	Serial.print("Current humidity = ");
	Serial.print(dht_dat[0], DEC);
	Serial.print(".");
	Serial.print(dht_dat[1], DEC);
	Serial.print("%  ");
	Serial.print("temperature = ");
	Serial.print(dht_dat[2], DEC);
	Serial.print(".");
	Serial.print(dht_dat[3], DEC);
	Serial.println("C  ");
        break;
     case 1:
        Serial.println("Error 1: DHT start condition 1 not met.");
        break;
     case 2:
        Serial.println("Error 2: DHT start condition 2 not met.");
        break;
     case 3:
        Serial.println("Error 3: DHT checksum error.");
        break;
     default:
        Serial.println("Error: Unrecognized code encountered.");
        break;
     	}//end "switch"
  delay(800);//Don't try to access too frequently... in theory
                   //should be once per two seconds, fastest,
                   //but seems to work after 0.8 second.
}// end loop()

/*Below here: Only "black box" elements which can just be plugged unchanged
  unchanged into programs. Provide InitDHT() and ReadDHT(), and a function
  one of them uses.*/

void InitDHT(){
  	//DDRC |= _BV(dht_PIN);//set data pin... for now... as output
              //DDRC is data direction register for pins A0-5 are on
	//PORTC |= _BV(dht_PIN);//Set line high
              //PORTC relates to the pins A0-5 are on.
        //Alternative code...
//        if (dht_dpin-14 != dht_PIN){Serial.println("ERROR- dht_dpin must be 14 more than dht_PIN");};//end InitDHT
        pinMode(dht_dpin,OUTPUT);// replaces DDRC... as long as dht_dpin=14->19
        digitalWrite(dht_dpin,HIGH);//Replaces PORTC |= if dht_pin=14->19
}//end InitDHT

void ReadDHT(){
/*Uses global variables dht_dat[0-4], and bGlobalErr to pass
  "answer" back. bGlobalErr=0 if read went okay.
  Depends on global dht_PIN for where to look for sensor.*/
bGlobalErr=0;
byte dht_in;
byte i;
  // Send "start read and report" command to sensor....
  // First: pull-down i/o pin for 18ms
digitalWrite(dht_dpin,LOW);//Was: PORTC &= ~_BV(dht_PIN);
delay(18);
delay(5);//TKB, from Quine at Arduino forum
/*aosong.com datasheet for DHT22 says pin should be low at least
  500us. I infer it can be low longer without any]
  penalty apart from making "read sensor" process take
  longer. */
//Next line: Brings line high again,
//   second step in giving "start read..." command
digitalWrite(dht_dpin,HIGH);//Was: PORTC |= _BV(dht_PIN);
delayMicroseconds(30);//DHT22 datasheet says host should
   //keep line high 20-40us, then watch for sensor taking line
   //low. That low should last 80us. Acknowledges "start read
   //and report" command.
   //Getting the delay exacly right is critical...
   //  put 40 in for the delay, in one of the later
   //  editions of this code, and the program
   //  will work SOMETIMES, but not ALWAYS.
   //  You have to allow for processing overheads,
   //  etc, too. Using, say, 30 won't "magically"
   //  make the TOTAL delay (with overheads, etc)
   //  exactly 30.0000 milliseconds. (This version may
   //  also have been unreliable with delay=40.. now
   //  deprecated.)

//Next: Change Arduino pin to an input, to
//watch for the 80us low explained a moment ago.
pinMode(dht_dpin,INPUT);//Was: DDRC &= ~_BV(dht_PIN);
delayMicroseconds(40);

dht_in=digitalRead(dht_dpin);//Was: dht_in = PINC & _BV(dht_PIN);

if(dht_in){
   bGlobalErr=1;//Was: Serial.println("dht11 start condition 1 not met");
   return;
   }//end "if..."
delayMicroseconds(80);

dht_in=digitalRead(dht_dpin);//Was: dht_in = PINC & _BV(dht_PIN);

if(!dht_in){
   bGlobalErr=2;//Was: Serial.println("dht11 start condition 2 not met");
   return;
   }//end "if..."

/*After 80us low, the line should be taken high for 80us by the
  sensor. The low following that high is the start of the first
  bit of the forty to come. The routine "read_dht_dat()"
  expects to be called with the system already into this low.*/
delayMicroseconds(80);
//now ready for data reception... pick up the 5 bytes coming from
//   the sensor
for (i=0; i<5; i++)
   dht_dat[i] = read_dht_dat();

//Next: restore pin to output duties
pinMode(dht_dpin,OUTPUT);//Was: DDRC |= _BV(dht_PIN);
//N.B.: Using DDRC put restrictions on value of dht_pin

//Next: Make data line high again, as output from Arduino
digitalWrite(dht_dpin,HIGH);//Was: PORTC |= _BV(dht_PIN);
//N.B.: Using PORTC put restrictions on value of dht_pin

//Next see if data received consistent with checksum received
byte dht_check_sum =
       dht_dat[0]+dht_dat[1]+dht_dat[2]+dht_dat[3];
/*Condition in following "if" says "if fifth byte from sensor
       not the same as the sum of the first four..."*/
if(dht_dat[4]!= dht_check_sum)
   {bGlobalErr=3;}//Was: Serial.println("DHT11 checksum error");
};//end ReadDHT()

byte read_dht_dat(){
//Collect 8 bits from datastream, return them interpreted
//as a byte. I.e. if 0000.0101 is sent, return decimal 5.

//Code expects the system to have recently entered the
//dataline low condition at the start of every data bit's
//transmission BEFORE this function is called.

  byte i = 0;
  byte result=0;
  for(i=0; i< 8; i++){
      //We enter this during the first start bit (low for 50uS) of the byte
      //Next: wait until pin goes high
      while(digitalRead(dht_dpin)==LOW);//Was: while(!(PINC & _BV(dht_PIN)));
            //signalling end of start of bit's transmission.

      //Dataline will now stay high for 27 or 70 uS, depending on
            //whether a 0 or a 1 is being sent, respectively.
      delayMicroseconds(30);//AFTER pin is high, wait further period, to be
        //into the part of the timing diagram where a 0 or a 1 denotes
        //the datum being send. The "further period" was 30uS in the software
        //that this has been created from. I believe that a higher number
        //(45?) would be more appropriate.

      //Next: Wait while pin still high
      if (digitalRead(dht_dpin)==HIGH)//Was: if(PINC & _BV(dht_PIN))
 	   result |=(1<<(7-i));// "add" (not just addition) the 1
                      //to the growing byte
    //Next wait until pin goes low again, which signals the START
    //of the NEXT bit's transmission.
    while (digitalRead(dht_dpin)==HIGH);//Was: while((PINC & _BV(dht_PIN)));
    }//end of "for.."
  return result;
}//end of "read_dht_dat()"

STOP PRESS: BETTER CODE....

(Best?... well... for now, yes: "Best")

Once again (3/13) I find myself saying: I haven't time, now, to write up everything that might be said about the following. It does essentially what the code above did... but BETTER. Please let me know if you use this, and if you encounter any difficulties with it. What is below retains comments from previous versions by various authors of this evolving code. Comments ALWAYS a good idea! (But... isn't it sad? I hesitated to use the word "evolving", in case it upset some creationist!)

My thanks to DaveB for contributing the following... May it serve everyone well!


//ReadHumTturDHT11alternate2
//vers 08 Mar 13, 09:36 (Dave had an old "version" ID here (TKB edit))

//Changes added by DaveB 5 March 2013 as a result of Thomas Henry's
//article on the DHT22 in the March 2013 issue of Nuts&Volts.
//Thanks to http://sheepdogguides.com/arduino/ar3ne1humDHT11.htm
//for providing the original code to work from.

//This is a re-written DHT11/ DHT22 reading code.
//DHT stuff in subroutines.

//See for more information....
//http://sheepdogguides.som/arduino/ar3ne1humDHT11.htm

//N.B. "bit" is used in the narrow, computer "1 or 0"
//   sense throughout.

//"DHT" from sensor's names: DHT11, DHT22.
//DHT aka Aosong AM2302, and there's an AM2303 which
//seems to be in the same family.

//Comments on this based on Aosong AM2302, aka DHT22, datasheet.
//Believed to generally apply to DHT11 as well, except in the
//case of the DHT11, I believe the second and fourth bytes are
//always zero.

//***N.B.****
//The code WORKS... the comments may not yet be EXACTLY right.
//See the web-page cited above for latest news.

//This code works with a DHT11 humidity/ temperature sensing module
//from nuelectronics.com, complied with vers 0018 of the Arduino environment
//Sensor attached to P4 (nuelectronics shield)/ analog 0, aka digital 14.

//That "module", according to the
//nuelectronics site, and visual inspection simply provides for easy
//connection of an Aosong DHT11 unit to the nuelectronics datalogging
//shield. Only 3 wires are involved: Vcc, ground, and a single data
//line. One of the DHT11's 4 pins goes nowhere.

//You should not need to change anything except the next line to use
//the software with the sensor on a different line, or for a DHT22.

//Just "huffing" on the sensor from deeply filled lungs should show
//a near instant rise in humidity

//#define dht_PIN 0      //no ; here. deprecate ADC0...
  //even though we are using it as a digital pin.
  //Other parts of code restrict us to using
  //ADC0-5, aka D14-19
#define dht_dpin 14 //no ; here. Set equal to channel sensor is on,
     //where if dht_dpin is 14, sensor is on digital line 14, aka analog 0

byte bGlobalErr;//for passing error code back from complex functions.
byte dht_dat[5];//Array to hold the bytes sent from sensor.

float lastHumidity;        //Added by DaveB
float lastTemperatureF;        //Added by DaveB
float lastTemperatureC;        //Added by DaveB

const byte mask = 0x7f;        //Added by DaveB
const int ledPin =  13;      // the number of the LED pin, added by DaveB

int ledState = LOW;             // ledState used to set the LED, added by DaveB

void setup(){
InitDHT();//Do what's necessary to prepare for reading DHT
Serial.begin(9600);
delay(1000);  //Let system settle, changed from 300 to 1000 by DaveB to allow
              //2 sec delay before addressing DHT22 again.
Serial.println("Humidity and temperature\n\n");
delay(1000);  //Wait rest of 1000ms recommended delay before accessing sensor,
              // changed from 700 to 1000 for a total of 2000 by DaveB

// set the digital pin as output to use the Arduino LED, Added by DaveB
pinMode(ledPin, OUTPUT);        //Added by DaveB
}//end "setup()"

void loop(){
  ReadDHT();//This is the "heart" of the program.
      //Fills global array dht_dpin[], and bGlobalErr, which
      //will hold zero if ReadDHT went okay.
      //Must call InitDHT once (in "setup()" is usual) before
      //calling ReadDHT.
  //Following: Display what was seen...
  switch (bGlobalErr){
     case 0:    //case 0 changed by DaveB

        //Changes added by DaveB as a result of Thomas Henry's article on the DHT22
        //in the March 2013 issue of Nuts&Volts.
        //
        //Values received from the DHT22 are in two bytes that represent 10 times the value.
        //Therefore 256 * first word plus second word provides 10 times the humidity or
        //temperature value.  MSB of dht_dat[2] tells us if the temperature is
        //positive or negative.  MSB value of 0 is pos temp, MSB value of 1 is a neg temp.

        lastHumidity = (dht_dat[0]*256+dht_dat[1]);  //Calculate float for 10*humidity
        lastHumidity = lastHumidity/10;  //Calculate humidity
	Serial.print("Humidity: ");
	Serial.print(lastHumidity);
        Serial.println("%  ");

        //dht_dat[2] = dht_dat[2] + 128;  // debug for showing negative temperature, uncomment to show neg temps
        // check for MSB set in dht_dat[2] which means negative temperature
        if ((dht_dat[2] & mask) != dht_dat[2]) {   //if they're different, it's negative
           dht_dat[2]= dht_dat[2] & mask;
           lastTemperatureC = -1*(dht_dat[2]*256+dht_dat[3]);  //Calculate neg float 10*temperature C
        }
        else {   //if they're not different, it's positive
           lastTemperatureC = (dht_dat[2]*256+dht_dat[3]);  //Calculate float 10*temperature C
        }

	lastTemperatureC = lastTemperatureC/10;  //Calculate temperature C
        Serial.print("Temp: ");
        Serial.print(lastTemperatureC);  //Uncomment these two lines for C temps
        Serial.print("C, ");             //Uncomment these two lines for C temps
        lastTemperatureF=lastTemperatureC*9/5+32;  //Calculate temperature F
        Serial.print(lastTemperatureF);
        Serial.println("F  ");
        Serial.println("");

         if (ledState == LOW)// alternately light and extinguish the LED
            ledState = HIGH;
         else
            ledState = LOW;
         digitalWrite(ledPin, ledState);

        break;
     case 1:
        Serial.println("Error 1: DHT start condition 1 not met.");
        break;
     case 2:
        Serial.println("Error 2: DHT start condition 2 not met.");
        break;
     case 3:
        Serial.println("Error 3: DHT checksum error.");
        break;
     default:
        Serial.println("Error: Unrecognized code encountered.");
        break;
     	}//end "switch"

  //delay changed from 800 to 2000 by DaveB
  delay(2000);//Don't try to access too frequently... in theory
                   //should be once per two seconds, fastest,
                   //but seems to work after 0.8 second.
}// end loop()

/*Below here: Only "black box" elements which can just be plugged unchanged
  unchanged into programs. Provide InitDHT() and ReadDHT(), and a function
  one of them uses.*/

void InitDHT(){
  	//DDRC |= _BV(dht_PIN);//set data pin... for now... as output
              //DDRC is data direction register for pins A0-5 are on
	//PORTC |= _BV(dht_PIN);//Set line high
              //PORTC relates to the pins A0-5 are on.
        //Alternative code...
//        if (dht_dpin-14 != dht_PIN){Serial.println("ERROR- dht_dpin must be 14 more than dht_PIN");};//end InitDHT
        pinMode(dht_dpin,OUTPUT);// replaces DDRC... as long as dht_dpin=14->19
        digitalWrite(dht_dpin,HIGH);//Replaces PORTC |= if dht_pin=14->19
}//end InitDHT

void ReadDHT(){
/*Uses global variables dht_dat[0-4], and bGlobalErr to pass
  "answer" back. bGlobalErr=0 if read went okay.
  Depends on global dht_PIN for where to look for sensor.*/
bGlobalErr=0;
byte dht_in;
byte i;
  // Send "start read and report" command to sensor....
  // First: pull-down i/o pin for 18ms
digitalWrite(dht_dpin,LOW);//Was: PORTC &= ~_BV(dht_PIN);
delay(18);
//db deleted following line
//delay(5);//TKB, from Quine at Arduino forum
/*aosong.com datasheet for DHT22 says pin should be low at least
  500us. I infer it can be low longer without any]
  penalty apart from making "read sensor" process take
  longer. */
//Next line: Brings line high again,
//   second step in giving "start read..." command
digitalWrite(dht_dpin,HIGH);//Was: PORTC |= _BV(dht_PIN);
delayMicroseconds(30);//DHT22 datasheet says host should
   //keep line high 20-40us, then watch for sensor taking line
   //low. That low should last 80us. Acknowledges "start read
   //and report" command.
   //Getting the delay exacly right is critical...
   //  put 40 in for the delay, and the program
   //  will work SOMETIMES, but not ALWAYS.
   //  You have to allow for processing overheads,
   //  etc, too. Using, say, 30 won't "magically"
   //  make the TOTAL delay (with overheads, etc)
   //  exactly 30.0000 milliseconds.

//Next: Change Arduino pin to an input, to
//watch for the 80us low explained a moment ago.
pinMode(dht_dpin,INPUT);//Was: DDRC &= ~_BV(dht_PIN);

delayMicroseconds(40);

//Read the LO
dht_in=digitalRead(dht_dpin);//Was: dht_in = PINC & _BV(dht_PIN);

if(dht_in){
   bGlobalErr=1;//Was: Serial.println("dht11 start condition 1 not met");
   return;
   }//end "if..."
delayMicroseconds(80);

dht_in=digitalRead(dht_dpin);//Was: dht_in = PINC & _BV(dht_PIN);

if(!dht_in){
   bGlobalErr=2;//Was: Serial.println("dht11 start condition 2 not met");
   return;
   }//end "if..."

/*After 80us low, the line should be taken high for 80us by the
  sensor. The low following that high is the start of the first
  bit of the forty to come. The routine "read_dht_dat()"
  expects to be called with the system already into this low.*/
delayMicroseconds(80);
//now ready for data reception... pick up the 5 bytes coming from
//   the sensor
for (i=0; i<5; i++)
   dht_dat[i] = read_dht_dat();

//Next: restore pin to output duties
pinMode(dht_dpin,OUTPUT);//Was: DDRC |= _BV(dht_PIN);
//N.B.: Using DDRC put restrictions on value of dht_pin

//Next: Make data line high again, as output from Arduino
digitalWrite(dht_dpin,HIGH);//Was: PORTC |= _BV(dht_PIN);
//N.B.: Using PORTC put restrictions on value of dht_pin

//Next see if data received consistent with checksum received
byte dht_check_sum =
       dht_dat[0]+dht_dat[1]+dht_dat[2]+dht_dat[3];
/*Condition in following "if" says "if fifth byte from sensor
       not the same as the sum of the first four..."*/
if(dht_dat[4]!= dht_check_sum)
   {bGlobalErr=3;}//Was: Serial.println("DHT11 checksum error");
};//end ReadDHT()

byte read_dht_dat(){
//Collect 8 bits from datastream, return them interpreted
//as a byte. I.e. if 0000.0101 is sent, return decimal 5.

//Code expects the system to have recently entered the
//dataline low condition at the start of every data bit's
//transmission BEFORE this function is called.

  byte i = 0;
  byte result=0;
  for(i=0; i< 8; i++){
      //We enter this during the first start bit (low for 50uS) of the byte
      //Next: wait until pin goes high
      while(digitalRead(dht_dpin)==LOW);//Was: while(!(PINC & _BV(dht_PIN)));
            //signalling end of start of bit's transmission.

      //Dataline will now stay high for 27 or 70 uS, depending on
            //whether a 0 or a 1 is being sent, respectively.
      delayMicroseconds(30);//AFTER pin is high, wait further period, to be
        //into the part of the timing diagram where a 0 or a 1 denotes
        //the datum being send. The "further period" was 30uS in the software
        //that this has been created from. I believe that a higher number
        //(45?) would be more appropriate.

      //Next: Wait while pin still high
      if (digitalRead(dht_dpin)==HIGH)//Was: if(PINC & _BV(dht_PIN))
 	   result |=(1<<(7-i));// "add" (not just addition) the 1
                      //to the growing byte
    //Next wait until pin goes low again, which signals the START
    //of the NEXT bit's transmission.
    while (digitalRead(dht_dpin)==HIGH);//Was: while((PINC & _BV(dht_PIN)));
    }//end of "for.."
  return result;
}//end of "read_dht_dat()"

--------------------------------------
So! Thank you DaveB. Let's see how long that version stands up to the community's scrutiny! (^_^)




The End?

... until the next person sends me a "better better" to share with you all?

Seriously: Improvements welcome. I am always glad to publish a link to any site contributors want promoted... be it their own, or a worthwhile charity, etc. (The most recent contributor declined the offer)

Also, the effort of the various people who have written to contribute improvements have done a real service to "those who've come after them", don't you think? I just apologize that the original code was faulty! I thought it worked, when I used it, but, maybe not? Oh well. Worth what you paid for it!

=========


Flattr: Have you heard of Flattr? Great new idea to make it easy for you to send small thank you$ to people who provide Good Stuff on the web. If you want to send $$erious thank yous, there are better ways, but for a small "tip" here and there, Flattr ticks a lot of boxes which no one else has found a way to do yet. Please at least check out my introduction to Flattr, if you haven't heard of it? "No obligation", as they say!

Flattr this

... But See Also: The Arduino programming course from Sheepdog Guides:

Further to the Arduino ideas here, I have posted a series of essays which try to help you become a better Arduino programmer and engineer... but, for the best result, you will have to buckle down and work your way through them in sequence. The "How To's" here can be accessed in whatever order you like.


Feel free to use this information in programming courses, etc, but a credit of the source would be appreciated. If you simply copy the pages to other web pages you will do your readers a disservice: Your copies won't stay current. Far better to link to these pages, and then your readers see up-to-date versions. For those who care- thank you- I have posted a page with more information on what copyright waivers I extend, and suggestions for those who wish to put this material on CDs, etc.





Editorial Philosophy

See the discussion near the bottom of the "top level" page covering the bulk of my Arduino contributions. There is information there, too, about things like "May I copy your material?", and the system of file names I am trying to work to.


   Search this site or the web        powered by FreeFind
 
  Site search Web search
Site Map    What's New    Search

The search engine is not intelligent. It merely seeks the words you specify. It will not do anything sensible with "What does the 'could not compile' error mean?" It will just return references to pages with "what", "does", "could", "not".... etc.
In addition to the information about the nuelectronics data shield of which this page is part, I have other sites with material you might find useful.....

Tutorials about the free database which is part of the free Open Office.
Sequenced set of tutorials on Pascal programming and electronics interfacing.
Some pages for programmers.
Using the parallel port of a Windows computer.

If you visit 1&1's site from here, it helps me. They host my website, and I wouldn't put this link up for them if I wasn't happy with their service... although I was less than pleased the other day to have what I was doing interrupted by a telephone call from their sales team, trying to get me to extend my involvement. Sigh. Hardly a rare event, but I'd thought 1&1 were a bit classier that some of the people who have my telephone number.



Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful. However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows PC) please visit my freeware and shareware page, download something, and circulate it for me? Links on your page to this page would also be appreciated!

Click here to visit editor's Sheepdog Software (tm) freeware, shareware pages.


And if you liked that, or want different things, here are some more pages from the editor of these tutorials....

Click here to visit the homepage of my biggest site.

Click here to visit the homepage of Sheepdogsoftware.co.uk. Apologies if the "?Frmar3ne1humDHT11" I added to that link causes your browser problems. Please let me know, if so?

Click here to visit editor's pages about using computers in Sensing and Control, e.g. weather logging.



To email this page's editor, Tom Boyd.... Editor's email address. Suggestions welcomed!


Valid HTML 4.01 Transitional Page tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org. Mostly passes. There were two "unknown attributes" in Google+ button code. Sigh.


Why does this page cause a script to run? Because of the Google panels, and the code for the search button. Why do I mention the script? Be sure you know all you need to about spyware.

....... P a g e . . . E n d s .....