ADS

Ic For Fun: 1000 codes for newbie

Ic For Fun: 1000 codes for newbie


1000 codes for newbie

Posted: 11 May 2012 11:38 AM PDT

Very very useful , the software collects a lot of basic codes.

Extract & open ENCYC.EXE :

162201234165271 1000 codes for newbie

 

1000 mach dien 11 1000 codes for newbie

 

 

1000 mach dien 21 1000 codes for newbie

1000 mach dien 41 1000 codes for newbie

DOWNLOAD HERE

SharePinExt 1000 codes for newbietumblr 1000 codes for newbiemyspace 1000 codes for newbie

No related posts.

This posting includes an audio/video/photo media file: Download Now

Humidity and temperature sensor DHT11& Aosong AM2302 Arduino

Posted: 11 May 2012 11:24 AM PDT

I plugged my DHT11 sensor into P4 of the nuelectronics datalogging shield, loaded the demo program (“sketch”), 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.

Remember: To run EXACTLY like this, the sensor needs to be plugged into P4. Change the #define line if you want to use it elsewhere.

The same code should work on any Arduino, by the way. 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  //ver 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[4];//Array to hold the bytes sent from sensor.    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 humdity = ");  	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(40);//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.    //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  //ver 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 ver 0018 of the Arduino environment  //Sensor attached to P4 (nuelectonics 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 belive 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, frm 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(40);//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.    	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 humdity = ");  	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 orultraviolet 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:

  • DHT11
  • 0-50° C
  • 20-90%RH
  • asong
  • (and there’s a serial number)

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

  • AM2302 / DHT22
  • Vcc: 3.3-6v DC
  • Sensing element polymer capacitor
  • Sensing range: -40 to +80° C
  • Sensing range: 0-100%RH
  • Accuracy: humidity +/- 2%RH (max +/- 5%RH)
  • Accuracy: temperature <+/- 0.5° Celsius
  • Resolution: humidity 0.1%RH
  • Resolution: temperature 0.1° Celsius
  • Repeatability: humidity +/- 1%RH
  • Repeatability: temperature +/- 0.2° Celsius
  • Current used: Operating: 1 1.5 mA (that may be a typo)
  • Current used: Standby: 50 uA

Data on the AM2303.

  • AM2303 / DHT??
  • Vcc: 3.3-5.5v DC (Says 6 in one place, 5.5 max in another)
  • Sensing element polymer capacitor
  • Temperature sensor: Dallas DS18B20
  • Sensing range: 0-100%RH
  • Sensing range: -40 to +125° C
  • Accuracy: humidity +/- 2%RH (max +/- 5%RH)
  • Accuracy: temperature +/- 0.2° Celsius
  • Resolution: humidity 0.1%RH
  • Resolution: temperature 0.1° Celsius
  • Repeatability: humidity +/- 1%RH
  • Repeatability: temperature +/- 0.2° Celsius
  • Current used: Operating: 1.5 mA
  • Current used: “Average”: 0.8 mA

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….

  • Tell sensor to start sending
  • Wait five and a half seconds
  • Read the first bit
  • Wait one second
  • Read the second bit
  • Wait one second
  • Read the third bit
  • … etc, etc… until it did…
  • Read the fortieth bit
  • … at which point the reading would be done!

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….

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. (Try the version at the top of the page first… MAY be better… but less well tested than what is below. And what is below retains comments explaining how I got from the nuelectronics-suggested code to what’s below… if you want to know.

//ReadHumTturDHT11alternate2  //ver 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 ver 0018 of the Arduino environment  //Sensor attached to P4 (nuelectonics 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[4];//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 humdity = ");  	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, frm 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(40);//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.    //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()"
Sharetumblr Humidity and temperature sensor DHT11& Aosong AM2302  Arduinomyspace Humidity and temperature sensor DHT11& Aosong AM2302  Arduino

Related posts:

  1. Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 2)
  2. Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 1)
  3. A Digital temperature meter using an LM35 temperature sensor