Read a DHT22 temperature and humidity sensor
- 192parts on the bench
- 25boards running now
- 1.00xreal time, on every board
The DHT22, also sold as the AM2302, is the sensor most people meet first for temperature and humidity: three pins, one data wire, and a reading every two seconds. The circuit above is a small weather station on an Arduino Uno, with a DHT22 on pin 2 and the reading on an I2C LCD. It is running on a simulated Uno, and the sensor inside it follows the datasheet closely enough to reproduce the two behaviors that confuse people most.
Open it in the editor and drag the temperature and humidity sliders on the sensor. The display does not change right away, and the reason is further down this page.
What you need
- An Arduino Uno
- A DHT22 sensor module (a bare sensor also needs a 10 k pull-up on DATA)
- A 16x2 LCD with an I2C backpack
- A breadboard and jumper wires
Wiring
One wire, and it is all timing
There is no I2C or SPI on the sensor’s data pin. The board pulls the line low to ask for a reading and lets go; the sensor answers with a short handshake and then forty bits, where each bit is a fixed low followed by a high whose length is the bit: about 27 microseconds for a nought and 70 for a one. The driver is a stopwatch.
Five bytes come back: humidity high and low, temperature high and low, and a checksum that is the low eight bits of the sum of the other four. A frame whose checksum does not match is thrown away. On the DHT22, a negative temperature sets the top bit and keeps the size in the rest, rather than using two’s complement, which is the classic hand-written driver bug that only shows up in winter.
The DHT library code
The Adafruit tutorial sketch compiles here as it stands. DHT.h is Mokxi’s own header on its DHT driver, with begin(), readTemperature(), readHumidity(), isnan() checks and computeHeatIndex(). The floats it returns are built from whole tenths, print normally, and take arithmetic of your own, such as converting to Fahrenheit. The built-in example avoids floats and works in tenths of a degree, which keeps it small on the Uno.
#include "DHT.h"
DHT dht(2, DHT22);
void setup() {
Serial.begin(9600);
dht.begin();
}
void loop() {
delay(2000);
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(h) || isnan(t)) {
Serial.println("Failed to read from DHT sensor!");
return;
}
Serial.print(t);
Serial.print(" C ");
Serial.print(h);
Serial.println(" %");
}Why the first reading fails, and why the number seems stuck
Both datasheets say to leave the sensor alone for a second after power comes up, and the simulated DHT22 does exactly that: a request inside that second gets no answer at all. The example deliberately asks right away, so its first line says waiting and then no answer, before the real readings start. Most sketches hide this behind a two second delay in setup(). It is worth seeing once, because on real hardware it is the reason a reading fails right after reset.
The second surprise is that the DHT22 only measures every two seconds and hands back its last reading in between. Drag the temperature slider and the display does not move until the sensor has looked again. A sketch that polls in a tight loop sees the same value over and over and looks broken. The example asks every two and a half seconds.
Try it in the editor
Open the circuit in the editor and change PERIOD_MS from 2500 to 500. Drag the temperature slider and watch the display: it still only moves every two seconds, because the sensor hands back its last reading until it has measured again. Asking more often does not make it measure more often.
Then select the sensor and change its model property to DHT11 without touching the sketch. The readings go wrong, because the DHT11 packs its bytes differently. Change DHT22 to DHT11 in the sketch and they come right again. The same two-line mistake is behind a great many forum posts.
Finally, drag the temperature below zero. A driver that treats the temperature as an ordinary signed number gets this wrong; the example handles the sign bit properly and shows the minus.
Common mistakes
Reading faster than every two seconds and wondering why the value never changes.
No pull-up on a bare sensor. The three-pin modules carry one; a bare four-pin DHT22 needs a 10 k resistor from DATA to VCC or the line never goes high again.
Treating a failed read as zero degrees. Always check with isnan() and skip the update, the way the sketch above does.
Mixing up DHT11 and DHT22 code. The wire is identical but the bytes mean different things: the DHT11 sends whole degrees and whole percent, so dividing its reading by ten is wrong.
Questions
What is the difference between the DHT11 and the DHT22?
The DHT22 reads 0 to 100 percent humidity and minus 40 to 80 degrees in tenths, and measures every two seconds. The DHT11 reads 20 to 90 percent and 0 to 50 degrees in whole numbers, every second. Both are on the bench, and the part has a model property to switch between them.
Can I use a DHT22 with an ESP32?
Yes. The DHT library runs on every board that compiles here, and the sensor works at 3.3 volts. Choose any free GPIO for DATA.
Why does my DHT22 always read nan?
Usually the wrong pin number in the DHT constructor, a missing pull-up, or reading inside the first second after power-up. Check the wiring against the table on this page first.
Build this for real
Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.