The dht library arduino ecosystem almost universally relies on the Adafruit DHT Sensor Library to read DHT11 and DHT22 (AM2302) temperature and humidity modules. If you are seeing NaN (Not a Number) or Failed to read from DHT sensor! in your Serial Monitor, the issue is rarely a broken library—it is almost always a timing violation, a missing pull-up resistor, or a power starvation problem on the single-bus data line.
This guide provides the exact wiring, fully compilable code with error handling, and a ranked debugging framework to get your sensor reading accurately. We assume you are using an Arduino Uno R3 (ATmega328P) or Nano v3 operating at 5V logic, and the Adafruit DHT Sensor Library (v1.4.4 or newer) installed via the Arduino Library Manager.
Project Spec Sheet & Parts List
Before wiring, verify exactly which sensor variant you have. The bare 4-pin sensors require an external resistor, while the mounted 3-pin modules have it built-in.
| Component | Exact Variant / Spec | Notes |
|---|---|---|
| Microcontroller | Arduino Uno R3 or Nano v3 | 5V logic, ATmega328P |
| Sensor | DHT22 (AM2302) or DHT11 | DHT22 preferred for 0.1°C resolution |
| Pull-up Resistor | 10kΩ (1/4W carbon film) | Mandatory for bare 4-pin sensors only |
| Wiring | 22 AWG solid core jumper wires | Keep data runs under 3 meters |
| Power | USB 5V or 7-12V barrel jack | Ensure clean 5V rail output |
Pin Mapping & Wiring Steps
The DHT sensors use a custom single-bus protocol. The microcontroller must pull the data line low for 18ms to request a reading, then release it. The sensor responds by pulling the line low and high in specific microsecond intervals to transmit 40 bits of data (16-bit humidity, 16-bit temperature, 8-bit checksum).
| DHT22 / DHT11 Pin | Arduino Uno R3 Pin | Function |
|---|---|---|
| 1 (VCC / +) | 5V | Power (3.3V-5.5V for DHT22; 5V only for DHT11) |
| 2 (DATA / OUT) | Digital Pin 2 | Single-bus data line (requires 10k pull-up to VCC) |
| 3 (NC) | Not Connected | Leave floating |
| 4 (GND / -) | GND | Common ground reference |
- Power the Sensor: Connect the sensor VCC pin to the Arduino 5V pin. Do not use 3.3V on an Uno; the sensor needs adequate current to drive the data line high against the pull-up resistor.
- Establish Ground: Connect the sensor GND pin to any Arduino GND pin.
- Wire the Data Line: Connect the sensor DATA pin to Arduino Digital Pin 2.
- Install the Pull-up (If required): If using a bare 4-pin sensor, insert a 10kΩ resistor between the DATA pin and the VCC pin on your breadboard.
Complete Compilable Arduino Code
This code targets the Arduino Uno R3 and includes the mandatory isnan() error handling. The DHT library returns NaN (Not a Number) when the checksum fails or the sensor times out. Never pass NaN directly to math functions or displays, as it will crash your logic.
#include <DHT.h>
// --- PIN DEFINITIONS ---
#define DHTPIN 2 // Digital pin connected to the DHT sensor
#define DHTTYPE DHT22 // Define sensor type (DHT11, DHT22, or DHT21)
// --- GLOBAL OBJECTS ---
DHT dht(DHTPIN, DHTTYPE);
// Timing variables to prevent reading too fast
unsigned long previousMillis = 0;
const long interval = 2500; // DHT22 needs 2s minimum; 2.5s adds safety margin
void setup() {
Serial.begin(115200);
while (!Serial) {
; // Wait for serial port to connect (needed for native USB boards)
}
Serial.println(F("DHT22 Sensor Initialization..."));
dht.begin();
}
void loop() {
unsigned long currentMillis = millis();
// Non-blocking delay to respect the sensor's maximum sampling rate
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
// Readings can take up to 250ms to complete
float humidity = dht.readHumidity();
float temperatureC = dht.readTemperature();
float temperatureF = dht.readTemperature(true); // Fahrenheit
// --- ERROR HANDLING ---
// Check if any reads failed and exit early (to try again)
if (isnan(humidity) || isnan(temperatureC) || isnan(temperatureF)) {
Serial.println(F("Failed to read from DHT sensor! Check wiring and timing."));
return; // Skip the rest of the loop and try again next interval
}
// --- DATA PROCESSING ---
// Compute heat index (must use Fahrenheit)
float heatIndexF = dht.computeHeatIndex(temperatureF, humidity);
Serial.print(F("Humidity: "));
Serial.print(humidity, 1);
Serial.print(F("% | Temp: "));
Serial.print(temperatureC, 1);
Serial.print(F("°C / "));
Serial.print(temperatureF, 1);
Serial.print(F("°F | Heat Index: "));
Serial.print(heatIndexF, 1);
Serial.println(F("°F"));
}
// You can run other non-blocking code here
}
Debugging: Fixing "Failed to Read" and NaN Errors
When the Serial Monitor outputs Failed to read from DHT sensor! or raw NaN values, the microcontroller failed to receive a valid 40-bit packet with a matching checksum. Here are the first three things to check, ranked by probability.
1. The Pull-Up Resistor is Missing or Incorrect
The Symptom: Serial monitor outputs NaN or DHT timeout waiting for start signal low.
The Fix: The single-bus protocol relies on an open-drain architecture. The sensor can only pull the line low; it cannot drive it high. The 10kΩ pull-up resistor is what brings the line back to 5V (Logic HIGH). If you are using a bare 4-pin DHT22 and forgot the resistor, the data line floats, and the Arduino reads garbage noise. Measure the resistance between the DATA and VCC pins with your multimeter (power off). It must read ~10kΩ.
2. Timing Violations (Reading Too Fast)
The Symptom: Sensor works on the first read, then outputs NaN on subsequent reads.
The Fix: The DHT22 has a hardware-mandated sampling period of 2 seconds (2000ms). The DHT11 requires 1 second. If your loop() queries the sensor every 500ms, the sensor's internal microcontroller ignores the start signal and returns nothing. Ensure your non-blocking millis() interval is set to at least 2500 for the DHT22.
3. Power Starvation or Voltage Drop
The Symptom: Intermittent Failed to read errors, especially when using long wires.
The Fix: The DHT22 can draw up to 1.5mA during a read. If you are powering it from a weak 3.3V rail on a clone Arduino, or using thin 28 AWG jumper wires longer than 1 meter, the voltage at the sensor's VCC pin may drop below 3.1V during the read cycle, causing a brownout. Measure the voltage directly at the sensor's VCC pin while it is running. It must remain above 4.5V for reliable 5V-logic operation.
Extending and Simplifying the Build
Once you have stable readings, you will likely want to move away from the Serial Monitor. Here is how to scale the project up or down.
Adafruit_SSD1306 library. Because I2C and the DHT single-bus protocol operate independently, you can update the display in the loop() without blocking the DHT timing intervals.
How to Simplify (Hardware Swaps): If you are tired of managing pull-up resistors and bare pins, switch to the AM2302 3-pin wired module. It comes pre-assembled with the 10kΩ SMD resistor and a 100nF decoupling capacitor on the power rail, which eliminates 90% of breadboard-induced noise issues. Alternatively, if you are migrating this project to an ESP32, switch to the DHTesp library, which handles the ESP32's dual-core RTOS timing interrupts much more gracefully than the legacy Adafruit library.
DHT Library Arduino FAQ
Why does my DHT22 read NaN with the DHT library?
The NaN (Not a Number) output is the library's deliberate error state. It triggers when the 40-bit data packet received from the sensor fails the 8-bit checksum validation, or when the sensor fails to respond to the 18ms start signal within the expected microsecond window. This is almost always caused by reading the sensor too frequently (less than 2 seconds apart), a missing 10kΩ pull-up resistor, or a loose breadboard connection on the data line.
Can I use the standard DHT library on an ESP32 instead of an Arduino?
Yes, the Adafruit DHT library compiles for the ESP32, but you may experience intermittent timeouts. The ESP32 runs FreeRTOS, and background tasks (like WiFi or Bluetooth) can interrupt the strict microsecond timing required to read the DHT sensor's single-bus protocol. If you must use an ESP32, disable WiFi during the sensor read, or use the DHTesp library, which is optimized to handle ESP32 interrupt latency. Also, remember to wire the DHT VCC to the ESP32's 5V (VIN) pin, not the 3.3V pin, and use a GPIO pin that does not have a boot-strapping conflict (avoid GPIO 0, 2, and 12).
Do I need a 10k pull-up resistor for the DHT11 data pin?
Yes, if you are using the bare 4-pin DHT11 component. The internal architecture of the DHT11 uses an open-collector output for the data line, meaning it can only pull the signal to ground. The 10kΩ pull-up resistor is required to pull the signal back to 5V (Logic HIGH) when the sensor releases the line. If you buy the DHT11 mounted on a small blue or green PCB with 3 pins, the resistor is already soldered onto the board.
What is the minimum delay between DHT sensor reads?
For the DHT22 (AM2302), the absolute minimum hardware sampling period is 2 seconds (2000ms). For the DHT11, it is 1 second (1000ms). However, in practice, adding a 500ms safety margin (using 2500ms for DHT22 and 1500ms for DHT11) significantly reduces checksum failures and NaN errors, especially in environments with high electrical noise or when using longer data wires.






