The DHT11 is the most popular entry-level temperature and humidity sensor in the hobbyist world — cheap, easy to wire, and supported by a mature Arduino library. But despite its simplicity, a surprising number of beginners and even experienced makers run into frustrating issues: Serial Monitor prints nan for temperature and humidity, readings time out, values are stuck, or the sensor delivers wildly inaccurate readings. This comprehensive troubleshooting guide covers every known cause of DHT11 failures and their solutions, so you can get reliable readings from your sensor without wasting hours debugging.
Table of Contents
- How the DHT11 Works
- Fixing NaN (Not a Number) Errors
- Fixing Timeout and Checksum Errors
- Correct Wiring and Pull-Up Resistor
- Library Selection and Version Issues
- Timing and Sampling Interval Issues
- When to Upgrade: DHT22, DHT20, BME280
- Frequently Asked Questions
How the DHT11 Works
The DHT11 uses a single-wire, half-duplex communication protocol. When the Arduino pulls the data line LOW for at least 18 ms and then releases it, the DHT11 responds with 40 bits of data — 8 bits humidity integer, 8 bits humidity decimal (always 0 on DHT11), 8 bits temperature integer, 8 bits temperature decimal (always 0), and 8 bits checksum. The entire transaction completes in about 5 ms.
The DHT11’s specifications:
- Temperature range: 0–50°C (±2°C accuracy)
- Humidity range: 20–90% RH (±5% accuracy)
- Sampling rate: maximum once every 1–2 seconds
- Supply voltage: 3.0–5.5 V
- Single data pin with internal pull-up (10 kΩ recommended externally)
Understanding this protocol is key to diagnosing failures — most issues stem from violated timing requirements or signal integrity problems on the data line.
Fixing NaN (Not a Number) Errors
The most common complaint: Temperature: nan°C | Humidity: nan% in the Serial Monitor. The DHT library returns NaN when it cannot complete a successful read. Here are the causes in order of likelihood:
Cause 1: Missing or Wrong Pull-Up Resistor
The DHT11’s data line is an open-drain output — it can only pull the line LOW. The pull-up resistor is essential to pull the line HIGH between communication bits. Without it, the line floats, causing random bit errors and NaN readings.
Fix: Add a 4.7 kΩ to 10 kΩ resistor between the data pin and VCC. For cable lengths under 20 cm, 10 kΩ works. For longer cables, use 4.7 kΩ to compensate for cable capacitance that slows signal rise time.
Cause 2: Reading Too Frequently
The DHT11 needs at least 1 second between readings (DHT22 needs 2 seconds). If you call dht.readTemperature() in a tight loop without delay, the sensor does not have time to prepare a fresh sample and returns NaN.
Fix: Always use millis()-based timing instead of delay(), and enforce a minimum 2-second interval:
unsigned long lastRead = 0;
const unsigned long INTERVAL = 2000; // 2 seconds minimum
void loop() {
unsigned long now = millis();
if (now - lastRead >= INTERVAL) {
lastRead = now;
float temp = dht.readTemperature();
float hum = dht.readHumidity();
if (isnan(temp) || isnan(hum)) {
Serial.println("DHT read failed! Retrying...");
return;
}
Serial.print("Temp: "); Serial.print(temp); Serial.println("°C");
Serial.print("Hum: "); Serial.print(hum); Serial.println("%");
}
}
Cause 3: Incorrect Data Pin Number
If you declare DHT dht(5, DHT11) but physically connect the data pin to pin 4, you get NaN. Double-check pin numbers. On Arduino Nano, pin numbers differ from Uno labelling on some clones — verify with the physical pin markings on your board.
Cause 4: Power Supply Issues
The DHT11 draws a brief 2.5 mA peak during measurement. On breadboards with poor connections or underpowered USB hubs, this brief current spike can dip VCC below 3 V, causing the sensor to reset mid-communication and return NaN. Add a 100 µF electrolytic capacitor between VCC and GND near the DHT11 module to smooth power supply spikes.
Fixing Timeout and Checksum Errors
Timeout errors occur when the Arduino waits for a signal transition from the DHT11 that never arrives within the expected window. Checksum errors mean the 40 bits were received, but the last 8 bits (checksum) do not match the sum of the first four bytes.
Enable Verbose Error Reporting
The DHT library provides a read() function that returns true/false, plus a readRaw() approach. For detailed error info, use the DHT_nonblocking library or add manual checksum validation. For the standard Adafruit DHT library, add this to see the specific failure:
#include "DHT.h"
#define DHTPIN 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(9600);
dht.begin();
}
void loop() {
delay(2000);
sensors_event_t humidity_event, temp_event;
// Use the sensor event API for error codes
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(h)) Serial.println("Error: Humidity read timeout/checksum");
if (isnan(t)) Serial.println("Error: Temperature read timeout/checksum");
if (!isnan(h) && !isnan(t)) {
Serial.print("OK — T:"); Serial.print(t);
Serial.print(" H:"); Serial.println(h);
}
}
Timeout Cause: Long Breadboard Wires
Breadboard wires longer than 30 cm act as antennas, picking up RF interference that corrupts the DHT11’s precise timing. Shorten wires, use a module with decoupling capacitor, or switch to a 4.7 kΩ pull-up resistor to improve signal edge quality.
Checksum Cause: Electrical Noise Near Motors or PWM
Running a DC motor, servo, or LED dimmer on the same power rail as the DHT11 without decoupling creates noise that corrupts bit timing. Use separate power rails with 100 µF + 100 nF bypass capacitors on each sensitive component.
Correct Wiring and Pull-Up Resistor
The bare DHT11 sensor (without module PCB) has 4 pins. Pin 1 (left) = VCC, Pin 2 = Data, Pin 3 = NC (not connected), Pin 4 (right) = GND. Module versions typically expose 3 pins: VCC, Data, GND with the pull-up resistor already soldered on.
| DHT11 Pin | Arduino Connection | Notes |
|---|---|---|
| VCC (Pin 1) | 5V | Add 100µF cap to GND |
| Data (Pin 2) | Digital pin (e.g., D2) | 10kΩ pull-up to VCC required for bare sensor |
| NC (Pin 3) | Leave unconnected | — |
| GND (Pin 4) | GND | — |
When using 3.3 V Arduinos (Nano 33 series, STM32 Blue Pill), power the DHT11 from 3.3 V — it works reliably down to 3.0 V, and this avoids the need for a logic level converter on the data line.
Library Selection and Version Issues
There are multiple competing DHT libraries for Arduino, and mixing them causes compilation errors or unexpected behavior:
- DHT sensor library by Adafruit: The most popular. Requires the Adafruit Unified Sensor library as a dependency. Install both from Library Manager. Use
#include "DHT.h". - SimpleDHT by Winlin: A lightweight alternative without dependencies. Better for memory-constrained projects. Use
#include <SimpleDHT.h>. - DHT_nonblocking by Martin Maly: Avoids blocking delays in the DHT communication. Use this when blocking for 18 ms in the main loop is unacceptable (e.g., when controlling a stepper motor simultaneously).
A common mistake is having both the Adafruit DHT library and an older DHTLIB installed simultaneously. Arduino IDE may pick up the wrong header. Check Sketch → Include Library and ensure only one DHT library is active. Remove old libraries from the Arduino libraries folder if needed.
Also verify the sensor type in the constructor: DHT dht(pin, DHT11) for DHT11, DHT dht(pin, DHT22) for DHT22/AM2302. Using DHT22 type constant with a DHT11 sensor results in consistently wrong values (approximately 2× high on temperature).
Timing and Sampling Interval Issues
Arduino timing can be disrupted by heavy use of delay(), long interrupt service routines, or libraries that disable interrupts for extended periods (e.g., some WS2812 NeoPixel libraries). The DHT11 protocol requires microsecond-precision timing to decode bits correctly.
Non-Blocking Read Pattern
Use millis() for all DHT read scheduling and avoid delay() in the main loop:
#include "DHT.h"
#define DHTPIN 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
unsigned long previousMillis = 0;
const unsigned long SAMPLE_INTERVAL = 2000;
void setup() {
Serial.begin(9600);
dht.begin();
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= SAMPLE_INTERVAL) {
previousMillis = currentMillis;
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(h) || isnan(t)) {
Serial.println("Failed to read DHT sensor!");
} else {
Serial.print("Humidity: "); Serial.print(h); Serial.print("%t");
Serial.print("Temperature: "); Serial.print(t); Serial.println("°C");
}
}
// Other non-blocking code here
}
NeoPixel + DHT Conflict
The Adafruit NeoPixel library disables interrupts while sending pixel data. If a DHT read happens simultaneously, bits will be corrupted. Solution: use the DHT_nonblocking library, or schedule DHT reads when NeoPixel updates are not occurring.
When to Upgrade: DHT22, DHT20, BME280
If you have tried all the above fixes and still get unreliable readings, it may be time to consider a better sensor:
DHT22 (AM2302)
The DHT22 uses the same single-wire protocol as DHT11 but offers higher accuracy (±0.5°C, ±2–5% RH) and a wider range (-40 to +80°C). Most DHT11 NaN issues also affect DHT22 — the fix is the same. Cost is about 2× the DHT11.
DHT20
The DHT20 is the modern successor using I2C — far more reliable than the single-wire timing-sensitive DHT11. It runs at 3.3 V natively and requires no external pull-up resistors (I2C pull-ups are typically onboard). Accuracy: ±0.5°C, ±3% RH.
BME280
For professional-grade measurements, the BME280 (I2C or SPI) measures temperature (±0.5°C), humidity (±3% RH), and barometric pressure. It is significantly more expensive but offers the best accuracy and reliability for weather stations and environmental monitoring.
DS18B20
If you only need temperature (no humidity), the DS18B20 uses the 1-Wire protocol and delivers ±0.5°C accuracy from -55 to +125°C — far better than DHT11’s ±2°C. Multiple DS18B20 sensors can share a single data wire using unique 64-bit addresses.
Frequently Asked Questions
My DHT11 reads temperature correctly but humidity always shows 0% or a fixed value. Why?
The DHT11’s humidity decimal byte is always zero (it only measures integer humidity). If you are getting 0% humidity constantly, the sensor may be damaged — humidity sensors can be permanently impaired by condensation (dew point exceedance) or by exposure to corrosive chemicals. Test with a fresh sensor. Also verify the library is configured for DHT11 not DHT22, as the data interpretation differs between models.
Can I use multiple DHT11 sensors on the same Arduino?
Yes, each DHT11 requires its own dedicated data pin. Use separate digital pins and create a separate DHT object for each sensor: DHT dht1(2, DHT11) and DHT dht2(3, DHT11). Do NOT connect two DHT11 data pins to the same Arduino pin — the sensors cannot share a data line with this protocol (unlike I2C or 1-Wire).
Why does my DHT11 show temperature 10°C higher than the room temperature?
Self-heating is the most common cause. If the DHT11 is inside an enclosure with poor ventilation near other heat-generating components (voltage regulator, motor driver, ESP8266 Wi-Fi module), it will read high. Mount the sensor with at least 10 cm clearance from heat sources in a well-ventilated location. The DHT11’s accuracy specification (±2°C) also means it can legitimately read up to 2°C off from reference.
Does the Arduino Nano 33 BLE work with DHT11 at 3.3V?
Yes. The DHT11 operates reliably from 3.0 V to 5.5 V. At 3.3 V supply with a 10 kΩ pull-up to 3.3 V, the sensor and its single-wire protocol function correctly. The logic levels are compatible with the Nano 33 BLE’s 3.3 V I/O without a level shifter. Ensure total current draw from the 3.3 V supply pin does not exceed 50 mA when combining multiple sensors.
How do I store DHT11 readings in EEPROM for data logging?
Convert the float temperature and humidity values to integers (multiply by 10 for one decimal place if needed), then store using the EEPROM library. Example: EEPROM.write(address, (byte)temperature) for integer values. For longer storage with timestamps, use an SD card module or a connected RTC + EEPROM IC like the AT24C32 (common on DS3231 RTC modules).
Get Reliable Readings from Your Sensors
DHT11 troubleshooting usually comes down to three things: correct wiring with the pull-up resistor, a minimum 2-second sampling interval, and using the right library version for your sensor type. Once those three conditions are met, the DHT11 delivers consistent readings for most basic temperature and humidity monitoring projects. And when you need more accuracy or reliability, there is a clear upgrade path through DHT20, BME280, and DS18B20.
Find the DHT11, DHT20, BME280, and a full range of temperature and humidity sensors at zbotic.in Arduino & Microcontrollers. Fast shipping across India, with genuine components and technical support.
Add comment