Module 8 - Sensors & Calibration

25. DHT11 / DHT22 Temperature & Humidity

Read temperature and humidity from a DHT11 or DHT22 with the Adafruit library, and reject failed readings with isnan().

Estimated time 1 session + optional extrasIn class Week 9 · Session 41

Learning outcomes

  • Explain what temperature and relative humidity the DHT reports
  • Compare DHT11 and DHT22 specs and constructor types
  • Wire a bare sensor (with pull-up) or a 3-pin module
  • Read with the Adafruit DHT library and reject failed readings with isnan

Parts and preparation

Uno, DHT11 or DHT22 sensor/module, 4.7-10 k ohm pull-up for a bare sensor and jumpers. Install both Adafruit libraries listed in the Libraries box.

Before power: inspect wiring, confirm supply voltage and ensure all connected circuits share GND.

Libraries for this lesson

In Arduino IDE 2 open Tools → Manage Libraries…. Search by the Library Manager name and install the package by the exact author below. Similar names from other authors can use different APIs and will break the example.

IncludeLibrary Manager nameAuthorInstall note
DHT.hDHT sensor libraryAdafruitInstall via Library Manager.
(dependency)Adafruit Unified SensorAdafruitRequired dependency of the DHT sensor library. Install via Library Manager if prompted or if compile fails.
DHT11 / DHT22 Temperature & Humidity instructional connection diagram

What a DHT reports

A DHT family sensor measures air temperature (C) and relative humidity (%RH). It is a digital single-wire device: VCC, DATA and GND (plus NC on many bare 4-pin packages). It is not an analogue ADC sensor and not an I2C device.

Inside the package, sensing elements and a small controller exchange a timed bit protocol on DATA. Use a library for the first practical - hand-timing that protocol is easy to get wrong.

A blue DHT11 with legs VCC, DATA, NC and GND gives two readings: temperature such as 23.0 degrees C from dht.readTemperature() and humidity such as 45 %RH from dht.readHumidity(), sent as digital pulses on one DATA wire to D2
Temperature and %RH over one DATA wire. Use a library for the bit protocol.

DHT11 vs DHT22

DHT11 is the cheap course default: modest range and coarse steps (about 1 C and 1 %RH). DHT22 (also sold as AM2302) covers a wider range with finer resolution and better accuracy, at higher cost.

Wiring is the same idea for both. The Adafruit constructor type must match the part you fitted: DHT11 or DHT22. A mismatch often produces failed reads or nonsense values.

DHT11 (blue, course default): 0 to 50 degrees C at plus or minus 2, 20 to 80 %RH, 1-degree steps, DHT dht(2, DHT11); DHT22 or AM2302 (white): -40 to 80 degrees C at plus or minus 0.5, 0 to 100 %RH, 0.1-degree steps, DHT dht(2, DHT22)
Same wiring pattern; change DHT11 to DHT22 in code when you swap sensors.
ItemDHT11DHT22
ConstructorDHT11DHT22
Typical useLearning / rough checksBetter accuracy projects
ResolutionCoarseFiner
Read intervalAbout 2 s or slowerAbout 2 s or slower

Bare sensor vs module wiring

A common bare 4-pin DHT, viewed from the front grill, is often VCC, DATA, NC, GND left to right. Pin 3 is not connected. You must add a 4.7-10 k ohm pull-up from DATA to VCC.

Many 3-pin modules already include the pull-up and label VCC / DATA / GND on the silkscreen. Pin order is not universal - always check the board text before powering.

Drawing of a blue DHT11 with its grill facing you and four legs labelled 1 VCC, 2 DATA, 3 NC, 4 GND, next to the same sensor on a small 3-pin board with a built-in pull-up
Course: DATA to D2, VCC to 5 V, GND shared. Bare parts need the DATA pull-up.
ConnectionCourse practice
VCC5 V
DATAD2
GNDUno GND
Bare pull-up4.7-10 k ohm DATA to VCC
Bare pin 3NC - leave open

Sampling interval

DHT sensors need recovery time between readings. Reading much faster than about once every two seconds often returns failed or stale data. The worked sketch uses delay(2000) before each read.

Reads every 2 seconds are all fresh; reads every half second mostly get nothing new or fail with NaN; the course sketch uses delay(2000) before reading
Wait at least about 2 seconds between reads.

Libraries and isnan

Install DHT sensor library by Adafruit and the Adafruit Unified Sensor dependency. Call dht.begin() in setup, then readHumidity() and readTemperature() in loop.

A failed read returns NaN (not a number). Always check isnan on both values before printing, logging or driving an LCD. The extension challenge is to keep the previous LCD values when a read fails.

Read humidity and temperature, check if (isnan(h) || isnan(t)): a good read prints 23.0 C 45.0 %RH, a failed read prints DHT read failed and returns
Guard with isnan before you trust the floats.
#include <DHT.h>
const byte dhtPin = 2;
DHT dht(dhtPin, DHT11);  // use DHT22 if that is the part fitted

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("DHT read failed");
    return;
  }
  Serial.print(t, 1);
  Serial.print(" C  ");
  Serial.print(h, 1);
  Serial.println(" %RH");
}

Wiring and safe build sequence

Breadboard wiring for 25. DHT11 / DHT22 Temperature & Humidity
Breadboard layout for this lesson. Match colours and pins before powering the circuit. Click the image for a larger view.
  1. VCC -> 5 V
  2. GND -> GND
  3. DATA -> D2
  4. Bare sensor: 4.7-10 k ohm from DATA to VCC
  5. Pin 3 of a common bare four-pin package is not connected
Power rule: switch off before moving wires. Arduino I/O pins are control signals; high-current loads require a driver and suitable external supply.

Worked sketch

Download .ino
#include <DHT.h>

const byte dhtPin = 2;
DHT dht(dhtPin, DHT11);  // use DHT22 if that is the part fitted

void setup() {
  Serial.begin(9600);
  dht.begin();
}

void loop() {
  delay(2000);
  float humidity = dht.readHumidity();
  float temperature = dht.readTemperature();

  if (isnan(humidity) || isnan(temperature)) {
    Serial.println("DHT read failed");
    return;
  }
  Serial.print(temperature, 1);
  Serial.print(" C  ");
  Serial.print(humidity, 1);
  Serial.println(" %RH");
}

How the code works

  1. isnan detects the library's failed floating-point reading.
  2. The two-second delay respects sensor timing.
  3. Change DHT11 to DHT22 in the constructor when you fit a DHT22 / AM2302.

Test and record evidence

Expected result: Serial reports plausible temperature and relative humidity every two seconds.

Practical evidence checklist

Common faults and checks
  • Verify sensor orientation and module pin labels.
  • Install both required Adafruit libraries.
  • Add/check the data pull-up for a bare sensor.
  • Confirm the constructor type matches DHT11 or DHT22.
  • Slow the loop if reads fail when polled too quickly.
Challenge (extension - optional): Display both values on the I2C LCD and retain the previous display when a read fails.

Check your understanding

Q1. Why check isnan?

Show answer

A failed DHT read returns a not-a-number value.

Q2. How frequently should a DHT11 be read?

Show answer

About once every two seconds or slower.

Q3. What must you change in code when swapping DHT11 for DHT22?

Show answer

The type constant in the DHT constructor (DHT22).

Q4. Why does a bare DHT need a pull-up on DATA?

Show answer

DATA is an open single-wire line; without a pull-up the level is undefined when idle.

Code Along 17: Temperature & Humidity (DHT11)

Optional: practise in your browser

Write and test this lesson's code on a virtual Uno. Work through the 4 exercises in order. Press Test and each one checks itself. This practice is optional - do it if you have time.

Exercises passed 0 / 4About 40-60 min, optionalOpen as its own page

Optional practice: a DHT11 on the virtual Uno

This practice is optional. Do it if you have time, or to revise before the environment monitor. Nothing in class depends on it.

The virtual board has a DHT11 wired to D2, just like the lesson. While a sketch runs you can:

  • drag the Temperature and Humidity sliders - the air around the sensor changes
  • tick Sensor fault - that is the data wire coming loose, so every reading fails and comes back as NaN (not a number)

Three things behave exactly like the Adafruit library on a real board. A DHT11 reports whole numbers, so 21.6 °C reads as 22.0. A reading within 2 seconds of the last one just repeats the last values - which is why the sketches wait 2 s between reads. And dht.begin() must run in setup() first, or every read fails.

What the simulator does not model: the DHT11's own error (about ±2 °C and ±5 %RH), how slowly a real sensor follows a change of air, and the pull-up resistor a bare sensor needs. Those are what the bench is for.

Worked example

The lesson's sketch

Press Run, then move the sliders and tick Sensor fault. Watch how long it takes for each change to reach the Serial Monitor.

#include <DHT.h>

const byte dhtPin = 2;
DHT dht(dhtPin, DHT11);  // use DHT22 if that is the part fitted

void setup() {
  Serial.begin(9600);
  dht.begin();
}

void loop() {
  delay(2000);
  float humidity = dht.readHumidity();
  float temperature = dht.readTemperature();

  if (isnan(humidity) || isnan(temperature)) {
    Serial.println("DHT read failed");
    return;
  }
  Serial.print(temperature, 1);
  Serial.print(" C  ");
  Serial.print(humidity, 1);
  Serial.println(" %RH");
}

Turn on JavaScript to edit, run and test this code in the browser.

Expected output
22.0 C  50.0 %RH
22.0 C  50.0 %RH
22.0 C  50.0 %RH
  • return; inside loop() ends this pass early - the next pass starts with the next delay(2000).
  • A change can take up to 2 s to show, because the sketch only asks every 2 s. That is fine for room air.
Exercise 17.1

Read the temperature

Not started

Everything is set up. In loop(), read the temperature into a float and print it like this, every 2 seconds:

Temperature: 22.0 C

Print the number with 1 decimal place. The test warms the air to 26 °C after 3 seconds, so the second line should change.

Sample output
Temperature: 22.0 C
Temperature: 26.0 C
#include <DHT.h>

const byte dhtPin = 2;
DHT dht(dhtPin, DHT11);

void setup() {
  Serial.begin(9600);
  dht.begin();
}

void loop() {
  delay(2000);
  // Read the temperature into a float, then print "Temperature: ", the value and " C"

}

Turn on JavaScript to edit, run and test this code in the browser.

Exercise 17.2

Temperature and humidity on one line

Not started

Add the humidity. Each line should read like the lesson's sketch:

22.0 C 50.0 %RH

Read it with dht.readHumidity() and print it with 1 decimal place. The test makes the air damper (65 %) after 3 seconds.

Sample output
22.0 C  50.0 %RH
22.0 C  65.0 %RH
#include <DHT.h>

const byte dhtPin = 2;
DHT dht(dhtPin, DHT11);

void setup() {
  Serial.begin(9600);
  dht.begin();
}

void loop() {
  delay(2000);
  float temperature = dht.readTemperature();
  // Read the humidity too

  Serial.print(temperature, 1);
  Serial.print(" C  ");
  // Print the humidity with 1 decimal place, then " %RH" to end the line

}

Turn on JavaScript to edit, run and test this code in the browser.

Exercise 17.3

Catch a failed reading

Not started

This sketch prints whatever the sensor gives it - so when the data wire comes loose it prints nan C nan %RH. Press Run and tick Sensor fault to see it.

Change it so that when either reading failed it prints Sensor error instead of the numbers. isnan(value) is true when a value is NaN. The test unplugs the sensor between 3 and 5 seconds.

Sample output
22.0 C  50.0 %RH
Sensor error
22.0 C  50.0 %RH
#include <DHT.h>

const byte dhtPin = 2;
DHT dht(dhtPin, DHT11);

void setup() {
  Serial.begin(9600);
  dht.begin();
}

void loop() {
  delay(2000);
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();

  // If either reading failed, print "Sensor error" instead of the line below
  Serial.print(temperature, 1);
  Serial.print(" C  ");
  Serial.print(humidity, 1);
  Serial.println(" %RH");
}

Turn on JavaScript to edit, run and test this code in the browser.

Exercise 17.4

Too hot or broken: the alarm goes on

Not started

The alarm LED on D8 must be on when the temperature is 30 °C or more, and off otherwise.

There is a catch. Every comparison with NaN is false, so temperature >= TOO_HOT on its own leaves the alarm off when the sensor is unplugged - a broken monitor that says all is well. The course rule is fail safe: a sensor fault switches the alarm on. It is the same rule Practical Task B marks.

The test warms the air to 32 °C, cools it to 24 °C, then unplugs the sensor.

#include <DHT.h>

const byte dhtPin = 2;
const int ALARM_PIN = 8;
const float TOO_HOT = 30.0;

DHT dht(dhtPin, DHT11);

void setup() {
  pinMode(ALARM_PIN, OUTPUT);
  dht.begin();
}

void loop() {
  delay(2000);
  float temperature = dht.readTemperature();

  // Alarm ON if the reading failed OR it is too hot - otherwise OFF

}

Turn on JavaScript to edit, run and test this code in the browser.

Try it on a real Uno

Wire the DHT11 as in Lesson 25 - DATA to D2, and a 4.7-10 kΩ pull-up if it is a bare sensor - and upload Catch a failed reading. Breathe on the sensor: humidity jumps within a few seconds, temperature creeps up much more slowly. Then pull the data wire out and check you get Sensor error, not a number.

Too hot or broken is the heart of the alarm in Lesson 27, so it is worth having in your fingers before you start that build.

Want more? Code Along chapter 17 has a Deeper exercise that goes further than this lesson. It is optional.