At July 2010, the demo code for reading a DHT11 which was supplied by nuelectronics.com used some advanced techniques. It made it hard for me to see what was going on. I also would structure a program differently than the demo code was structured, and so I set about trying to create a functionally equivalent program.
Now: I hadn't worked with DHT11's previously. There may have been reasons the demo was done the way it was. However, I can tell you that my code does work, at least some of the time. Furthermore, I don't really see any reason it wouldn't work. I don't think I'm riding a wave of "luck". And my code allows you to attach the sensor to any free digital I/O line.
Why read the rest of this? If you are an Arduino programmer, you may find it interesting. There's not a lot here for other readers.
I started by moving things around, leaving the actual code used pretty much as before.
I wanted the code for initializing the software in a single function. (The hardware doesn't need any initializing.) And I wanted a single call to cause the sensor to report the current conditions.
Once those two tasks were in functions, then half the work of making a library for them was done. And users of my code could just "cut and paste" the details without needing to look at them. Users just had to know what to call.
I've used global variables to hold things passed back from the functions. Nothing needs to be passed to the functions, although the pin the sensor is on is indicated by the value of a global "#define". These are "bad" techniques, and better answers exist.... but doing things this way makes the code accessible to novices.
The global variables are: array dht_dat[0-4]. (Existed before, as dht11_dat[0-5], but not as global, and element 5 was spare) and bGlobalErr (0 is returned if no error seen).
Sometimes, while in one of the "black box" parts of the code, an error will be detected. Rather than reporting it there and then, I have elected to set an error flag. What reports are generated when errors occur can then be decided by someone using the software, without them having to make any changes in the "black box" regions of the code. I hope you can see that working in the code in the "loop()" function. (What's there is NOT in the "black box" region... but the call to readDHT() takes the program off to the "black box", from whence it should promptly return.
This essay is going to get sketchy here... sorry. I just don't expect many people to read this, and even fewer to try any of my shareware. The essay will still not be worth less than you are paying me for it!
There will be a number of blocks which will start with the old code, and the code that replaced it. In some instances, there will be comments to go with the "old" and "new".
Variable names: These may... vary! The demo used "DHT11" as part of names. The code also works for DHT22 sensors, I believe, so I dropped the "11"... but it may still be present in some places.
Direct Port Access: The chip at the heart of the Arduino has three "ports", A, B and C. When we use a digital I/O line, we are using one or another of these ports. While we stick with the lovely high level things like pinMode(12,INPUT), we don't need to concern ourselves with these ports, nor with how to interact with them. The demo code made extensive use of direct port access.
There's a lot about direct port access in the Arduino reference pages, online.
The following are usually used in connection with accessing the underlying ports. All of the words written all in caps are "known" to the Arduino development environment.
Each register can hold a number. It is best to think of that number in binary form. Let's, for instance, consider that DDRB is holding what we would usually call "six". In binary, that would be 00000110. (The port has a particular width, which I'm not looking up just now. If it is not 8 bits wide, just add some zeros to the left of the number I wrote out.) Each bit controls the direction of data though a single digital pin. You can look up the mapping if you need it, but if DDRB held 00000110, then most of the pins would be outputs (or inputs... I'm not looking up what "1" says, either), and two would be for passing data the other way.
When we use pinMode(), we are setting or clearing (making 1, or making zero) one of the bits in a data direction register. Using pinMode() is a LOT easier than messing about with three DDR's, and finding the right position for a given pin! But the pin's functions were set in the demo code using direct manipulation of the DDRs.
Now that you know all(!) about DDRs, what about the other two? The values you make the bits of the port output registers determine the state of the associated pins... if they are currently configured as outputs.
When a pin is configured (by the value in the DDR) for input, then the corresponding bit of the PIN- Port INput- register will be 1 or 0 based on the voltage the chip is "seeing" on the corresponding input line.
THAT's what you need to know about the ports and their registers.
Besides knowing about PORTC and DDRC, you need to know something about bit bashing.
Abandon all knowledge of the meaning of "AND" and "OR".
In the rest of this essay, we are going to be talking about bitwise logical ANDing and ORing.
For much of this, think in binary terms.
Just for a moment go back to "normal" numbers. The following should hold no fears....
2 2 ADD ===== 4
I'm just stating a fact: If you add two and two, you get four.
Here's another fact. If you do a bitwise OR between the binary numbers 00011 and 10001, you get 10011. Written as follows, the rule should be easy enough to understand....
00011 10001 bitwise OR ===== 10011
The bitwise AND works like this....
00011 10001 bitwise AND ===== 00001
I hope you do! Writing this is taking time!
Bitwise ORs and bitwise ANDs are very useful when dealing with registers. You can't usually directly turn just one bit on or off, or determine the state of just one bit. But, if you are interested, say, in the middle bit, you CAN do the following. In each case, the number on the top is "random", and the number on the second line is the right mask to use if you want to know something about the middle bit, or make it a particular value....
To find out if the middle bit of the number on the top is a one or a zero, regardless of what else is present....
00011 00111 00100 bitwise AND 00100 ===== ===== 00000 (zero) 00100 (not zero)
To MAKE the middle bit a "1", leaving the others as they were....
00011 00100 bitwise OR ===== 00111 (zero)
To MAKE the middle bit a "0", leaving the others as they were....
00111 11011 bitwise AND ===== 00011 (zero)
There are similar tricks you do for other needs of this sort. Many of the above arise in the "tricky" code I converted the program for the humidity sensor from.
If you do x=_BV(4), then you will put 16 in x. The "_" isn't special... it is just part of the name of the "_BV" function. _BV(0) returns 1, _BV(1) returns 2,_BV(2) returns 4, and so on. You start with 1, and double it as many times as called for. This always results in a binary number consisting of a single "1" and lots of zeros.
At last we are ready to look at some of the code from the demo, and what replaced it:
DDRC |= _BV(DHT11_PIN);//original pinMode(dht_dpin,OUTPUT);//replacement
What was in DHT11_PIN and in dht_dpin was not quite the same. If the former was 0, the latter would have had to be 14 to have the new command do what the former did. This was because the reference base changed. In the old code, we were talking about which bit of PORTC we wanted to use. The Arduino analog pins, 0-5, are on PORTC, bits 0-5 respectively. The numbering of the digital pins, and pinMode(), are more clever. We can use 0-19, and the system takes care of finding the right bit in the right port.
DDRC |=_BV(DHT11_PIN), when DHT11_PIN is holding 0 is equivalent to...
Take what's in DDRC Do a bitwise OR between that and 00001 Put the result in DDRC
The Arduino reference has more on ports and on bit bashing.
The information on _BV() came from UrbanHonking.
Now that I've taken you by the hand through a few, I will not explain the rest in as much detail. Other instances of replace code are as follows:
PORTC &= ~_BV(DHT11_PIN);//Original digitalWrite(dht_dpin,LOW);//Replacement
The tilde (~) is the bitwise NOT operator. The ampersand (&) says "bitwise AND". (Don't confuse &- bitwise AND with && logical AND... a different concept). If _BV(DH11_PIN) was 000001, then the bitwise NOT of that is 111110. The expression above, in that case, boils down to...
Take what's in PORTC Do a bitwise AND between that and 111110 Put the result in PORTC
DDRC &= ~_BV(DHT11_PIN);//Original pinMode(dht_dpin,INPUT);//Replacement
dht11_in = PINC & _BV(DHT11_PIN);//Original dht_in=digitalRead(dht_pin);//Replacement
Here we are using a bitwise AND of a number with just one "1" and the contents of one of the input registers. It tells us the state of one input, if that pin is currently configured for input.
while(!(PINC & _BV(DHT11_PIN)));//Original while(digitalRead(dht_dpin)==LOW);//Replacement
if(PINC & _BV(DHT11_PIN))//Original if(digitalRead(dht_dpin)==HIGH)//Replacement
while((PINC & _BV(DHT11_PIN)));//Original while(digitalRead(dht_dpin)==HIGH);//Replacement
if(PINC & _BV(DHT11_PIN))//If pin still high result |=(1<<(7-i));
... bit of code builds, or accumulates, a value in a variable. The subject of that "if" clause is going to be, using T for "true" and F for "false", "TTFT" if the rest of the code is working its way though the binary number 1101, which in our ordinary language is a way of writing 13.
As the execution of the loop that code is in progresses, "result" will hold:
0 1 3 6 12 13
Use Google to research "binary to decimal conversion" if you want to know more.
The "<<" operator is covered in the extended Arduino reference documentation, under "bitwise operators".
So there you have it! You may have learned about some things you didn't previously know. You may have a better idea of how the demo code from nuelectronics for the DHT11 and similar humidity sensors worked, and the relationship between that and my code for reading the sensors.
Most of my tutorials are more carefully crafted. If you find any worthy, please click the StumbleUpon link at the top of the page. If you want to reward my (considerable) effort, and you are using Windows, please collect some of my freeware, and spread it around.
Further to the Arduino ideas the page you are reading now will take you to, 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.
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.
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.
Click here to visit editor's Sheepdog Software (tm) freeware, shareware pages.
Click here to visit the homepage of my biggest site.
Click here to visit the homepage of Sheepdogsoftware.co.uk. Apologies if the "?Frmar3ne1humDHT11two" 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.
Page tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org
....... P a g e . . . E n d s .....