Armed only with a bucket full of enthusiasm, a wiki full of miss-information and a 2 digit IQ, the good Captain seeks not only to understand the modern world, but also fix one or two bits of kit along the way.

Category

Friday, 19 December 2014

DHT22 Temperature/RH Sensor on the RaspberryPi

The DHT22 is a low cost, single wire sensor which measures temperature and relative humidity.

I started out just playing around with this thing, just wiring it to a Pi to see it working.

But I got sucked in much deeper into thinking about how it worked and assessing its limitations.

Output Data Stream

The DHT22 produces a serial stream of data. In other words the sensor has just one "wire" over which it sends data and receives commands.

Pin 1 = +V, 2 = data, 3 =no connect, 4 = 0V

It does this by simply raising and lowering the voltage level, and varying the amount of time that the wire is either "high" or "low". In my circuit "high" is approximately 3.3 Volts, while low is approximately 0 Volts.

The data output consists of a series of low-to-high-to-low sequences where each sequence represents either a logical 0 or a 1.

A logical 1 waveform looks like this:-

While logical 0 is like this:-

There should be 40 of these zeros and ones in a complete data set, and this data stream may start out looking something like this:-

00000010 00110101 0000...

The first 2 bytes contain the rh (relative humidity) value. In this example:-

02hex & 34hex = 234hex = 564

As data values are 10 x actual readings, 564 is an rh of 56.4%.

Likewise, the third and forth bytes represent 10 x the temperature reading.

The Checksum

In order to validate the integrity of the sensors transmitted data, the unit generates a simple checksum, which occupies that last byte of the 40 bit data stream.

This sensor calculates the checksum by adding the 4 data bytes together, and using only the lower 8 bits of the result as the 1 byte checksum.

When our system [software] reads this data it simply repeats the process and checks the result against the checksum. If there was a data transmission or reception error, our calculated checksum will not match the checksum transmitted from the sensor, so we can ignore this bad data.

There are of course a couple of exceptions. If the data error is in the 1st or 3rd bytes, this error will not be detected by the checksum, because we only use the lower 8 bits of the result. Also, it is possible that 2 or more errors may cancel one another out (e.g. a -1 error in rh and a -1 error in received checksum).

However, in the first case, an error in the 1st or 3rd bytes will make a very large difference to either the rh or temperature. For example, 01hex in the first byte is 256. This would be a change of 25.6% rh (or 25.6'C for the 3rd byte).

In the second case? Well, someone with good maths abilities could probably tell me the likelyhood of canceling errors.

Connecting sensor to Pi

The DHT22 is a four terminal package, but only pins 1, 2 & 4 are used.

I simply plugged it into a breadboard and wired as follows:-

Initially I fitted a 10k Ohm resistor to pins 1 & 2. During testing I replaced this with a 4.7k and also added a 0.1uF capacitor across the supply pins (1 & 4) although these changes did not appear to make any significant improvement in performance.

Testing with wiringPi

Once again I'm relying on Gordon's wiringPi software, and here are a few points regarding the notes that follow.

Once wiringPi is downloaded (use the latest snapshot) it should be unzipped and located on the RaspberryPi in a suitable folder (e.g. /home/pi/wiringPi-version).

The Pi uses pcManFM filemanager. If you navigate to a folder then press F4, a terminal window will open at that point in the file system. So where I say: run sudo ./rht03 in examples, I mean navigate to /home/pi/wiringPi-version/examples, press F4, and type: sudo ./rht03 in terminal.

So lets start by building wiringPi:-
Run ./build from your wiringPi-version folder. The terminal should show something like this:-

Now open rht03.c in the examples folder (e.g. edit in LeafPad).
Change pin number to suit your wiring using wiringPi pin numbers, in my case:-
#define RHT03_PIN 15

Run make rht03 from the examples folder.

Now run the demo program by typing: sudo ./rht03 from the examples folder.

You may start to see rh and temperature readings displayed in your terminal. However, you may also notice your Pi soon becomes paralyzed as the cpu load sits at 100%.

Put the little critter out of its misery by hitting <ctrl><c>

I opened rht03.c again at added a 5 second sleep:

#include <stdio.h>#include <unistd.h>

#include <wiringPi.h>#include <maxdetect.h>

#define RHT03_PIN 15... for (;;) { delay (100) ;sleep(5);

if (!readRHT03 (RHT03_PIN, &newTemp, &newRh))

After saving, making and running rht03 again, I found the cpu load to be reasonably low, and the screen spat out readings from time to time. Sometimes the readings appeared 5 seconds apart, and sometimes there were much longer gaps.

I had another look at rht03.c and noticed that it doesn't output results unless they have changed since last time, hence the apparently erratic display rate.

This demo program calls readRHT03 which is in ../devLib/maxdetect.c. This file contains most of the routines used to talk to the DHT22 sensor.

Very basically: readRHT03 calls maxDetectRead which "wakes up" the sensor by holding the data line low for 10ms and then pulsing it high for 40us. It then calls maxDetectLowHighWait and waits for the data line to switch from a high to a low state (this is the signal from the sensor indicating that data transmission is about to follow).

The maxDetectRead routine then calls maxDetectClockByte which checks if the data line is a 1 or a 0 (after a 30us delay) and uses this to build up the data, bit-by-bit.

I decided to sprinkle this code with printf so I could see more closely what was going on.#include <stdio.h>

Note that intTemp and intRH are 10x the actual value, so have to be divided by 10 for display.

This test program took readings from the DHT22 at 10 second intervals and also recorded the total number of readings and the number of errors. I did not record checksum errors, I only recorded readings which were either more than 5'C or 5% different from the previous reading. So this error count may include data error in the high order data byte which do not affect the calculated checksum.

In approximately 3500 readings I recorded 5 errors.

Conclusion

Since the DHT22 is designed to measure temperature and relative humidity in an environment like a house, it is not too much of a problem to drop readings when a checksum error is detected, or when a reading is clearly very different from previous and subsequent readings.