If you are searching for the best humidity sensor for Arduino in 2026, the direct answer depends on your protocol preference: use the AHT20 for bulletproof I2C reliability, or the DHT22 (AM2302) if you are maintaining legacy 1-wire projects or learning basic timing protocols. For this guide, we are targeting the classic Arduino Uno R3 and wiring up the ubiquitous DHT22, while providing the exact bench-tested fixes for the timeout errors that plague it.
While the DHT22 is a rite of passage for makers, its 1-wire protocol is notoriously sensitive to timing interrupts and parasitic capacitance. Below, you will find the exact schematic, complete compilable code with error handling, and a debugging matrix to get your readings stable.
Parts List & Sensor Spec Sheet
Before wiring, it is critical to understand the hardware differences. The DHT11 is a toy (0-80°C, ±2°C accuracy) and should be avoided for serious environmental logging. The SHT31 is laboratory-grade but requires strict 3.3V logic. The AHT20 and DHT22 occupy the sweet spot for hobbyist and prosumer builds.
| Sensor Model | Protocol | RH Accuracy | Read Time | Logic Level | Approx. Price (2026) |
|---|---|---|---|---|---|
| DHT22 / AM2302 | 1-Wire (Custom) | ±2% (20-80% RH) | ~2.0 seconds | 3.3V - 5.5V | $3.50 - $5.00 |
| AHT20 (Adafruit 4566) | I2C | ±2% (20-80% RH) | ~80 milliseconds | 3V - 5V (Regulated) | $4.50 - $6.00 |
| SHT31-D (Sensirion) | I2C | ±1.5% (0-100% RH) | ~15 milliseconds | Strict 3.3V | $10.00 - $14.00 |
Wiring & Pin Mapping (Arduino Uno R3)
The DHT22 requires a pull-up resistor on the data line to function correctly. Many cheap breakout boards include a surface-mount 10kΩ resistor on the back, but if you are using the raw 4-pin AM2302 component, you must add it externally.
| DHT22 Pin | Arduino Uno R3 Pin | Notes & Requirements |
|---|---|---|
| 1 (VCC / +) | 5V | Can also run on 3.3V, but 5V yields a stronger signal edge. |
| 2 (DATA / OUT) | Digital Pin 2 | Must have a 10kΩ pull-up resistor to VCC. |
| 3 (NC) | Not Connected | Leave floating. Do not ground. |
| 4 (GND / -) | GND | Connect to the main Arduino ground plane. |
Numbered Wiring Steps:
- Insert the DHT22 into a breadboard. Identify Pin 1 (usually marked with a small triangle or '+' on the plastic housing).
- Run a jumper from Arduino 5V to the breadboard's positive rail, and Arduino GND to the negative rail.
- Connect DHT22 Pin 1 to the positive rail (5V).
- Connect DHT22 Pin 4 to the negative rail (GND).
- Insert a 10kΩ resistor bridging DHT22 Pin 2 and the positive rail (5V). This is your pull-up.
- Run a jumper from DHT22 Pin 2 directly to Arduino Digital Pin 2.
Complete Arduino Code (DHT22)
This code targets the Arduino Uno R3 and uses the standard Adafruit DHT Sensor Library. Install both the Adafruit Unified Sensor and DHT sensor library via the Arduino Library Manager before compiling.
#include <DHT.h>
// --- PIN DEFINITIONS ---
#define DHTPIN 2 // Digital pin connected to the DHT sensor
#define DHTTYPE DHT22 // Sensor type: DHT11, DHT22 (AM2302), or DHT21 (AM2301)
// Initialize DHT sensor for normal 16MHz Arduino
DHT dht(DHTPIN, DHTTYPE);
// Timing variables to prevent polling too fast
unsigned long previousMillis = 0;
const long interval = 2500; // DHT22 requires minimum 2s between reads
void setup() {
Serial.begin(9600);
Serial.println(F("DHT22 Humidity & Temperature Sensor Initialized"));
// Start the sensor
dht.begin();
}
void loop() {
unsigned long currentMillis = millis();
// Non-blocking delay to respect the 2-second read limit
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
// Readings take ~250ms to complete
float h = dht.readHumidity();
float t = dht.readTemperature();
float f = dht.readTemperature(true); // Fahrenheit
// ERROR HANDLING: Check if any reads failed
if (isnan(h) || isnan(t) || isnan(f)) {
Serial.println(F("Failed to read from DHT sensor! Check wiring and pull-up."));
return; // Exit loop early and try again next interval
}
// Compute heat index
float hif = dht.computeHeatIndex(f, h);
float hic = dht.computeHeatIndex(t, h, false);
// Output structured data
Serial.print(F("Humidity: "));
Serial.print(h);
Serial.print(F("% | Temp: "));
Serial.print(t);
Serial.print(F("°C / "));
Serial.print(f);
Serial.print(F("°F | Heat Index: "));
Serial.print(hic);
Serial.print(F("°C / "));
Serial.print(hif);
Serial.println(F("°F"));
}
}
Debugging: First 3 Things to Check When It Fails
If your serial monitor outputs Failed to read from DHT sensor! or spits out NaN (Not a Number) for both temperature and humidity, do not immediately assume the sensor is dead. The 1-Wire protocol is fragile. Here is your ranked troubleshooting path.
1. The Missing or Incorrect Pull-Up Resistor
The DHT22 uses an open-drain output. It can pull the data line LOW to send a '0', but it cannot drive it HIGH to send a '1'. It relies entirely on the external pull-up resistor to bring the line back to 5V. If your breakout board lacks the onboard SMD resistor, or if your jumper wire has high resistance, the signal will fail. Fix: Verify the 10kΩ resistor is physically bridging DATA and 5V. If using a cable longer than 1 meter, drop the resistor to 4.7kΩ to overcome parasitic capacitance.
2. Polling Too Fast (The 2-Second Rule)
The DHT22 internally samples its thermistor and capacitive humidity element on a slow cycle. If you request data faster than once every 2 seconds, the sensor will simply ignore the microcontroller's start signal, resulting in a timeout. Fix: Ensure your code uses a non-blocking millis() timer set to at least 2500ms, as shown in the code block above. Never put dht.readHumidity() inside a tight loop without a delay.
3. 5V Logic vs 3.3V Board Mismatches
If you port this exact circuit to an ESP32 or Arduino Nano 33 IoT (which are strictly 3.3V logic boards), powering the DHT22 with 5V while feeding its 5V data output into a 3.3V GPIO pin will fry the microcontroller's input buffer. Fix: Power the DHT22 with 3.3V when using 3.3V boards, or use a bidirectional logic level converter (like a BSS138 MOSFET module) between the sensor and the MCU.
Extending and Simplifying the Build
How to Extend: To turn this into a standalone environmental monitor, add an I2C OLED display. Wire an SSD1306 128x64 OLED to the Uno's A4 (SDA) and A5 (SCL) pins. Because the OLED uses hardware I2C and the DHT22 uses bit-banged 1-Wire on Pin 2, they will not interfere with each other. Use the Adafruit_SSD1306 library to print the h and t variables directly to the screen.
How to Simplify: If you are tired of managing pull-up resistors and 2-second polling delays, switch to the AHT20. The Adafruit AHT20 breakout features an onboard voltage regulator and I2C level-shifting circuitry. You simply wire it to 5V, SDA, and SCL, and use the Adafruit_AHTX0 library. It reads in 80ms, requires no pull-ups, and never throws timeout errors due to CPU interrupts.
Frequently Asked Questions
What is the most accurate humidity sensor for Arduino?
For the highest accuracy in the Arduino ecosystem, the Sensirion SHT31 is the benchmark. It offers ±1.5% Relative Humidity accuracy and ±0.2°C temperature accuracy. However, it is strictly a 3.3V I2C device. If you are using a 5V Arduino Uno R3, you must use a logic level shifter. For 5V-native accuracy without level shifters, the Bosch BME280 (which also includes barometric pressure) is the best alternative, offering ±3% RH accuracy.
Why does my DHT22 keep returning NaN or "Failed to read"?
The NaN (Not a Number) output is triggered by the Adafruit library when the microcontroller fails to detect the sensor's 80-microsecond acknowledgment pulse. 90% of the time, this is caused by a missing 10kΩ pull-up resistor on the data line, or polling the sensor faster than its 2-second internal refresh rate. The remaining 10% is usually caused by long, unshielded jumper wires acting as antennas and injecting noise into the 1-Wire bus.
Can I use a 3.3V humidity sensor with a 5V Arduino Uno?
Yes, but you cannot connect them directly. If a sensor like the SHT31 outputs 3.3V on its SDA line, the 5V Uno R3 might not reliably read it as a logic HIGH (the Uno's threshold is typically ~3.0V, leaving zero noise margin). More dangerously, if the Uno sends 5V to the sensor's SCL line, it will destroy the sensor's silicon. You must use a bidirectional logic level converter (such as the SparkFun BOB-12009) to safely translate the I2C signals between the 5V and 3.3V domains.
How do I calibrate an Arduino humidity sensor?
Consumer sensors like the DHT22 and AHT20 drift over time, especially if exposed to condensation. You can perform a "salt test" for a baseline calibration. Place the sensor in a sealed Tupperware container alongside a small bottle cap filled with a saturated solution of table salt (NaCl) and water. At standard room temperature (20-25°C), a saturated salt solution creates an exact 75% Relative Humidity environment. Leave it sealed for 12 hours, note the sensor's offset from 75%, and subtract that offset in your Arduino code.






