How to Use DHT11 Sensor with Arduino: Wiring, Code and Projects Explained
Learn how the DHT11 temperature and humidity sensor works, how to wire it to Arduino, and build a temperature-triggered automatic fan controller. Full code included.
Last Updated: April 14, 2026 | Arduino IDE 2.3.8 | Adafruit DHT sensor library v1.4.6
The DHT11 sensor is one of those components that shows up in almost every beginner Arduino kit, and for good reason. It measures both temperature and humidity over a single data wire, making it a great starting point for anyone getting into environmental sensing or home automation. By the end of this tutorial, you’ll know exactly how the DHT11 works internally, how it talks to your Arduino, and you’ll have two working projects to show for it – a basic serial readout and a temperature-triggered automatic fan controller.
Table of Contents
- What the DHT11 Sensor Actually Is
- How It Measures Temperature and Humidity
- The Single-Wire Communication Protocol Explained
- DHT11 Pinout and Key Specifications
- Demo 1 – Wiring the DHT11 to Arduino
- Demo 1 – Reading Temperature and Humidity on the Serial Monitor
- Demo 2 – Building an Automatic Fan Controller
- Demo 2 – Fan Circuit Wiring with a Transistor
- Demo 2 – Temperature Threshold Fan Controller Code
- Troubleshooting Common DHT11 Problems
What the DHT11 Sensor Actually Is
Most Arduino sensors do one thing. An IR sensor detects infrared light. An ultrasonic sensor measures distance. A soil moisture sensor reads conductivity. The DHT11 is a bit different because it measures two things at once – ambient temperature and relative humidity – from a single module. And it does that while sending all the data over just one wire, which is kind of impressive for something that costs a couple of euros.
What makes this possible is that there are actually two seperate sensing elements packed inside the module. One handles humidity, one handles temperature, and a tiny internal microcontroller ties everything together before any data leaves the chip. You’re not doing any of the heavy lifting on the Arduino side – the DHT11 sends you clean, processed values and that’s it.
Common Mistake: A lot of beginners assume they need to apply calibration math after receiving DHT11 readings. You don’t. The internal MCU handles all calibration before the data reaches your Arduino. What you recieve is already in final, usable form.
How It Measures Temperature and Humidity
Humidity – Resistive Moisture Sensing
For humidity, the DHT11 uses a resistive moisture sensor. Think of it as a small piece of conductive material sitting between two electrodes. As moisture in the air increases, that material absorbs water molecules, which changes its electrical resistance. The sensor measures that resistance shift and converts it into a relative humidity percentage.
Relative humidity is just the percentage of water vapour in the air compared to the maximum it could hold at that temperature. So 60% RH means the air is carrying 60% of the maximum possible moisture for that temperature. That’s the number the DHT11 gives you.
Temperature – NTC Thermistor
For temperature, the sensor uses an NTC thermistor. NTC stands for Negative Temperature Coefficient, which means the thermistor’s resistance drops as temperature rises. The internal circuit reads that resistance change and maps it to a temperature value in Celsius. It’s a pretty reliable method for measuring ambient temperature in the range the DHT11 covers.
The Internal 8-Bit Microcontroller
Here’s the clever bit. Inside the DHT11 module is a tiny 8-bit microcontroller. This MCU reads the raw values from both sensing elements, applies pre-stored calibration data, converts everything into a digital format, and sends it out over the single data pin. This is exactly why the DHT11 is called a digital sensor. You get processed, calibrated output – not raw analog voltage that you’d have to interpret yourself.
The Single-Wire Communication Protocol Explained
Most sensors use established protocols like I2C (two wires – SDA and SCL), SPI (four wires), or UART (TX and RX). The DHT11 doesn’t use any of those. It uses a custom single-wire protocol where the Arduino and the sensor share one data line and communicate entirely through precisely timed HIGH and LOW pulses. This part is a bit technical but it’s worth understanding, especially when things go wrong.
How the Communication Sequence Works
Every reading starts with the Arduino acting as the master. The full sequence has four phases. First, the Arduino pulls the DATA line LOW for at least 18 milliseconds – this wakes the DHT11 and tells it a reading is needed. The DHT11 then responds by pulling the line LOW for 80 microseconds and then HIGH for 80 microseconds – basically saying “I’m here and I’m ready.”
After that the DHT11 transmits 40 bits of data. Each bit starts with a 50-microsecond LOW pulse. The bit value is determined by how long the line stays HIGH afterwards. A short HIGH pulse of around 26-28 microseconds is a binary 0. A longer HIGH pulse of 70 microseconds is a binary 1. The Arduino identifies each bit purely by measuring that HIGH duration.
What’s Inside Those 40 Bits
The 40 bits are structured as five bytes sent in order. The first byte is the humidity integer (e.g. 65 for 65% RH). The second byte is the humidity decimal, which is always zero on the DHT11 since it has no decimal precision. The third byte is the temperature integer, the fourth is the temperature decimal (also always zero), and the fifth byte is a checksum – the sum of the first four bytes. If the checksum doesn’t match, the reading gets discarded as corrupt.
Important: You don’t need to implement any of this protocol manually. The Adafruit DHT library handles all the timing and checksum validation internally. But understanding it helps a lot when you’re trying to figure out why you’re getting NaN errors or dropped readings.
DHT11 Pinout and Key Specifications
Most beginners will have the DHT11 module rather than the bare component. The module version exposes three pins and has a pull-up resistor built in. The bare DHT11 component has four pins but requires you to add your own 10k pull-up resistor on the data line. If you’re not sure which one you have, look at the back – the module usually has a small PCB with a resistor soldered on it.
- VDD: Power supply pin. Accepts 3.5V to 5.5V DC, so it works with both Arduino’s 5V and 3.3V outputs without any level shifting needed.
- DATA: The single bidirectional data line. All temperature and humidity readings come through this one pin.
- GND: Ground.
Here are the specs you’ll actually care about when building with this sensor:
- Temperature range: 0°C to 50°C with an accuracy of ±2°C.
- Humidity range: 20% to 80% RH with an accuracy of ±5% RH.
- Resolution: 8-bit for both sensors. Readings are whole numbers – don’t expect 24.7°C, you’ll get 24 or 25.
- Minimum sampling interval: 2 seconds. Poll it faster than this and you’ll get stale data or failed reads.
- Operating voltage: 3.5V to 5.5V DC.
Tip: If you need decimal precision or a wider range, the DHT22 is a direct upgrade. It reads from -40°C to 80°C with ±0.5°C accuracy and uses the exact same pinout and library. The code change is literally one line.
Demo 1 – Wiring the DHT11 to Arduino
This is one of the simplest circuits you’ll build. Three connections, no resistors needed if you’re using the module version, and it works with Arduino Uno, Nano, Mega or anything else you have sitting around.
- DHT11 VDD connects to Arduino 5V.
- DHT11 GND connects to Arduino GND.
- DHT11 DATA connects to Arduino Digital Pin 4.
I’m using pin 4 because it sits cleanly in the 3-7 range – away from the hardware serial pins (0 and 1), away from I2C on A4 and A5, and away from the SPI pins. No special function conflicts on any common Arduino board. You can use any digital pin in that range and just update the pin number in the code.
Common Mistake: If you have the bare 4-pin DHT11 component rather than the module, you must add a 10k ohm pull-up resistor between the DATA pin and VDD. Skipping this causes intermittent read failures that are really annoying to diagnose because everything looks wired correctly.
Reading Temperature and Humidity on the Serial Monitor
Installing the Adafruit DHT Library
Open Arduino IDE and go to Sketch > Include Library > Manage Libraries. In the search box, type DHT sensor library – use that exact phrase, not just “dht”. You’re looking for the result titled DHT sensor library by Adafruit. If you just search “dht” you’ll get a pile of unrelated results including AM2302-Sensor and EduIntro, neither of which will work here.
Click Install on the Adafruit result. Arduino IDE will then ask if you want to install dependencies – click Install All. This pulls in the Adafruit Unified Sensor library which the DHT library needs to function. If you skip that step and only install the DHT library itself, the code won’t compile.
Common Mistake: Searching just “dht” in the Library Manager returns too many results and the Adafruit library doesn’t always appear at the top. Always search the full phrase “DHT sensor library” and confirm the author says Adafruit before clicking Install.
Demo 1 Code
#include <DHT.h>
#define DHTPIN 4 // DATA wire connected to Digital Pin 4
#define DHTTYPE DHT11 // We are using DHT11 (not DHT22 or DHT21)
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(9600);
dht.begin();
Serial.println("DHT11 Sensor Ready!");
}
void loop() {
delay(2000); // DHT11 needs at least 2 seconds between readings
float humidity = dht.readHumidity();
float tempC = dht.readTemperature(); // Celsius
float tempF = dht.readTemperature(true); // Fahrenheit
// isnan() catches failed reads before they cause bad output
if (isnan(humidity) || isnan(tempC)) {
Serial.println("ERROR: Failed to read from DHT11. Check wiring.");
return;
}
Serial.print("Humidity: ");
Serial.print(humidity);
Serial.println(" %");
Serial.print("Temperature: ");
Serial.print(tempC);
Serial.print(" C | ");
Serial.print(tempF);
Serial.println(" F");
Serial.println("----------------------------");
}
What Each Part Does
#include <DHT.h> loads the Adafruit library which handles all that single-wire timing internally. DHTPIN 4 tells the library which pin to listen on. DHTTYPE DHT11 is important – the same library supports DHT22 and DHT21, and setting the wrong type gives you completely wrong readings without throwing any error. So don’t skip that.
The delay(2000) inside loop() isn’t optional. The DHT11 hardware can’t produce a valid reading faster than once every two seconds. Polling faster than that returns either stale values or triggers the isnan() error check. I tested this on IDE 2.3.8 with library version 1.4.6 and the output matched a reference thermometer to within about 1 degree.
Passing true to dht.readTemperature() returns Fahrenheit. No argument, or passing false, returns Celsius. Both calls read the same sensor – the library just handles the conversion for you.
Using Serial Plotter for a Live Graph
If you want a more visual output – which looks great when you’re demonstrating the sensor reacting to breath or a heat source – you can feed the Serial Plotter instead. Open it with Tools > Serial Plotter (or Ctrl+Shift+L on Windows, Cmd+Shift+L on Mac) and make sure the baud rate is set to 9600.
Replace the Serial.print block in your loop with this:
Serial.print("Temperature:");
Serial.print(tempC);
Serial.print(",");
Serial.print("Humidity:");
Serial.println(humidity);
The Label:Value format tells the plotter to name and colour-code each line automatically. The Serial.println() at the end marks one complete data point. When you breathe near the sensor, the humidity line spikes visibly within a reading or two. It’s one of those moments that makes the sensor click for people who are just learning this stuff.
Demo 2 – Building an Automatic Fan Controller
This is where it gets actually useful. The Arduino reads temperature from the DHT11 every two seconds. If it hits or exceeds 30°C, the fan turns on automatically. Drop below 30°C and it turns off. This is the same control logic you’ll find in 3D printer cooling systems, server rack fans, and electronics enclosures – just with a more precise sensor on top.
My suggestion for beginners: wire up an LED on pin 7 first to confirm the logic works, then swap in the fan circuit once you’re confident. It saves a lot of head-scratching later because it isolates the code problem from any wiring issue in the transistor circuit.
Fan Circuit Wiring with a Transistor
You can’t connect a DC fan directly to an Arduino pin. Arduino digital outputs are rated at 40mA maximum and most small 5V fans need 100mA or more just to spin up. Doing it anyway risks permanently damaging the ATmega microcontroller on your Arduino board. So we use a transistor as a switch – the Arduino sends a small control signal, and the transistor handles the actual current to the fan.
Warning: Never connect a DC motor or fan directly to an Arduino digital output pin. The inrush current when the motor starts can exceed the pin’s 40mA maximum rating and cause permanent damage to the microcontroller. Always route it through a transistor or MOSFET.
What You’ll Need for Demo 2
- Arduino Uno, Nano, or Mega.
- DHT11 sensor module.
- Small 5V DC fan.
- NPN transistor – a 2N2222, BC547, or PN2222 all work. Alternatively you can use an N-channel MOSFET like the 2N7000 if that’s what you have.
- 1N4007 flyback diode – this protects the transistor from voltage spikes generated by the fan motor coil when it switches off. It’s not optional.
- 1k ohm resistor for the transistor base.
- Breadboard and jumper wires.
Important: The 1N4007 flyback diode is not an optional component. DC motors are inductive loads and generate a reverse voltage spike when switched off – this is called inductive kickback. Without the diode across the fan terminals, that spike will eventually destroy your transistor. Place it with the cathode (striped end) toward the positive terminal of the fan.
Wiring Connections
The DHT11 connections are identical to Demo 1. Add the following for the fan circuit:
- Arduino Pin 7 connects through a 1k ohm resistor to the Transistor Base.
- Transistor Emitter connects to GND.
- Transistor Collector connects to the fan negative terminal.
- Fan positive terminal connects to Arduino 5V.
- 1N4007 diode placed across the fan terminals, cathode (striped end) toward the positive side.
When Arduino writes HIGH to pin 7, the transistor saturates and completes the fan circuit. LOW on pin 7 cuts the transistor off and the fan stops. The 1k resistor on the base limits current from the Arduino pin to a safe level. Its not the most glamorous circuit but its solid and its exactly how commercial products handle this.
Demo 2 – Temperature Threshold Fan Controller Code
#include <DHT.h>
// --- Pin Definitions ---
#define DHTPIN 4
#define DHTTYPE DHT11
#define FAN_PIN 7
// --- Temperature Threshold ---
#define TEMP_THRESHOLD 30.0 // Fan activates at or above this value (Celsius)
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(9600);
pinMode(FAN_PIN, OUTPUT);
digitalWrite(FAN_PIN, LOW); // Ensure fan is OFF on startup
dht.begin();
Serial.println("=== Smart Fan Controller ===");
Serial.print("Threshold: ");
Serial.print(TEMP_THRESHOLD);
Serial.println(" C");
Serial.println("============================");
}
void loop() {
delay(2000);
float humidity = dht.readHumidity();
float tempC = dht.readTemperature();
if (isnan(humidity) || isnan(tempC)) {
Serial.println("ERROR: Sensor read failed. Check wiring.");
return;
}
Serial.print("Temp: ");
Serial.print(tempC);
Serial.print(" C | Humidity: ");
Serial.print(humidity);
Serial.print(" % | Fan: ");
if (tempC >= TEMP_THRESHOLD) {
digitalWrite(FAN_PIN, HIGH);
Serial.println("ON");
} else {
digitalWrite(FAN_PIN, LOW);
Serial.println("OFF");
}
}
Code Walkthrough
FAN_PIN 7 is our transistor base control line. Pin 7 sits in the safe 3-7 range with no hardware function conflicts on Uno or Nano. TEMP_THRESHOLD 30.0 is defined at the top so you can change it in one place without hunting through the loop. That’s a small thing but it saves a lot of confusion when you’re tuning the project.
The digitalWrite(FAN_PIN, LOW) right after pinMode in setup() is there for a reason. On some Arduino boards the pin can float HIGH briefly during boot before the sketch initialises, which would cause the fan to flicker on for a split second. Setting it LOW immediately prevents that.
The actual control logic is a single if-else. If temperature is at or above the threshold, pin 7 goes HIGH and the fan runs. Below the threshold, it goes LOW and the fan stops. That’s it. And honestly that single if-else is the core of every thermostat and thermal protection circuit in the world. The sensors get more precise and the systems around them get more complex, but the fundamental logic doesn’t change.
Tip: To add humidity-based triggering as well, change the if condition to
if (tempC >= TEMP_THRESHOLD || humidity >= 70.0). The fan will activate when either value exceeds its limit. Useful if you’re building something for a humid environment like a grow tent or bathroom.
Troubleshooting Common DHT11 Problems
Getting “Failed to read from DHT11” on the Serial Monitor
- Confirm the DATA wire goes to the same pin number you defined in
DHTPIN. This is the most common cause and the easiest to miss. - If you’re using the bare 4-pin component rather than the module, add a 10k pull-up resistor between DATA and VDD. The module version has it built in.
- Make sure
delay(2000)is in your loop. Anything shorter than 2000ms will produce regular read failures. - Try a different digital pin and update
DHTPINto match. Some clone Arduino boards have quirks on specific pins.
Compilation Error: “DHT.h: No such file or directory”
- Search for
DHT sensor libraryas the full phrase in Library Manager, not just “dht”. - Confirm the library author is Adafruit – not AM2302-Sensor or any other result.
- When the dependency prompt appears, click Install All to include Adafruit Unified Sensor.
- Close and reopen Arduino IDE after installing, then try compiling again.
Fan Won’t Turn On
- Test with an LED and 220 ohm resistor on pin 7 first. If the LED activates at the threshold, the code is working and the issue is in the transistor circuit.
- Check transistor leg orientation. Base, Collector, and Emitter are not always in the same physical order across different transistor packages – check the datasheet for your specific part.
- Verify the fan is getting 5V on its positive terminal when the transistor is supposed to be switched on.
Readings Are Stuck or Not Updating
- Check that
DHTTYPEis set toDHT11and notDHT22. The wrong type produces frozen or nonsensical readings without any error message. - Make sure the Serial Monitor baud rate matches
Serial.begin(9600)in your code. A mismatch gives you garbled output that looks like nothing is happening.
Related Guides
- Arduino Uno Pinout – Complete Reference Guide
- How to Use the Arduino Serial Monitor
- Using an NPN Transistor as a Switch with Arduino
- Controlling LEDs with Arduino – Beginner’s Guide
Important: Verify each internal link above resolves correctly on rootsaid.com before publishing. Replace any that return 404 with confirmed live URLs from the site.
Written by Jithin at RootSaid. Last updated April 14, 2026. Both demo circuits were verified on Arduino Uno R3 running Arduino IDE 2.3.8 with Adafruit DHT sensor library v1.4.6. Questions or issues? Drop them in the comments.

One Comment