DHT11 là cảm biến bạn gặp đầu tiên trong hầu hết kit Arduino — giá rẻ, dễ dùng, chỉ cần 1 dây dữ liệu. Nhưng bên trong nó hoạt động thế nào? Tại sao lại cần delay 2 giây giữa 2 lần đọc? Tại sao có resistor pull-up trên module? Bài này trả lời từ datasheet gốc AOSONG.
Nguyên Lý Hoạt Động
DHT11 tích hợp 2 bộ cảm biến trong một vỏ nhựa:
1. Đo Độ Ẩm — Capacitive Hygrometer
Bộ phận đo độ ẩm là một tụ điện polymer. Cấu tạo gồm 2 điện cực dẫn điện kẹp một lớp màng polymer hút ẩm (hygroscopic polymer).
Điện cực (+)
│
▓▓▓▓▓▓▓▓▓▓ ← Lớp polymer hút ẩm
│ (thay đổi hằng số điện môi ε theo độ ẩm)
Điện cực (-)
Khi độ ẩm môi trường tăng, polymer hấp thụ hơi nước → hằng số điện môi ε tăng → điện dung C tăng theo công thức:
C = ε × A / d
Trong đó A là diện tích điện cực, d là khoảng cách. IC nội bộ đo tần số dao động của mạch RC (với C thay đổi theo độ ẩm), rồi chuyển đổi sang giá trị số.
Giới hạn của phương pháp này: Polymer mất độ nhạy ở độ ẩm < 20% RH và bão hòa ở > 80% RH — đó là lý do dải đo DHT11 chỉ là 20–80% RH.
2. Đo Nhiệt Độ — NTC Thermistor
Nhiệt độ đo bằng NTC thermistor (Negative Temperature Coefficient). Điện trở NTC giảm khi nhiệt độ tăng theo đặc tuyến Steinhart-Hart:
1/T = A + B·ln(R) + C·(ln(R))³
IC nội bộ linearize đặc tuyến này và xuất ra giá trị số nguyên (không có dấu phẩy — đây là giới hạn của DHT11 so với DHT22).
3. Giao Thức Single-Wire (1-Wire Độc Quyền)
DHT11 dùng giao thức single-wire độc quyền của AOSONG — không phải chuẩn 1-Wire của Dallas/Maxim. Một chu kỳ đọc diễn ra như sau:
MCU gửi START signal:
─────┐ ┌────── MCU pull-up
│ > 18ms (LOW) │
└────────────────────┘
DHT11 phản hồi:
┌──────┐ ┌── Data bits
───────┘80µs └──┘80µs
Mỗi bit dữ liệu:
"0": 50µs LOW → 26–28µs HIGH
"1": 50µs LOW → 70µs HIGH
Tổng cộng 40 bit được truyền mỗi lần đọc, chia làm 5 byte:
| Byte | Nội dung |
|---|---|
| Byte 1 | Phần nguyên độ ẩm (VD: 55) |
| Byte 2 | Phần thập phân độ ẩm (DHT11 luôn = 0) |
| Byte 3 | Phần nguyên nhiệt độ (VD: 24) |
| Byte 4 | Phần thập phân nhiệt độ (DHT11 luôn = 0) |
| Byte 5 | Checksum = Byte1 + Byte2 + Byte3 + Byte4 |
Tại sao cần delay 2 giây? Sau mỗi lần đọc, DHT11 cần thời gian để capacitive sensor ổn định lại. Minimum sampling period theo datasheet là 1 giây, nhưng trong thực tế nên dùng 2 giây để tránh lỗi đọc.
Thông Số Kỹ Thuật
| Thông số | Giá trị | Ghi chú |
|---|---|---|
| Điện áp hoạt động | 3.0V – 5.5V | Module trên board có thể hạn chế |
| Dòng tiêu thụ (đo) | 0.5mA | Lúc đang giao tiếp |
| Dòng tiêu thụ (standby) | 100µA | Giữa 2 lần đọc |
| Dải nhiệt độ | 0°C – 50°C | Ngoài dải → kết quả sai |
| Độ chính xác nhiệt độ | ±2°C | Worst case, typical ±1°C |
| Dải độ ẩm | 20% – 80% RH | Ngoài dải → không tin cậy |
| Độ chính xác độ ẩm | ±5% RH | Worst case |
| Độ phân giải | 1°C / 1% RH | Không có dấu phẩy |
| Thời gian đáp ứng nhiệt độ | ≤30 giây | Trong điều kiện gió nhẹ |
| Thời gian đáp ứng độ ẩm | ≤5 giây | |
| Sampling period tối thiểu | 1 giây | Khuyến nghị dùng 2 giây |
| Chiều dài cáp tối đa | 20m | Cần R pull-up 100Ω tại đầu cáp |
| Kích thước (sensor) | 15.5 × 12 × 5.5mm | Không gồm PCB module |
| Kích thước (module) | 23 × 12 × 5.5mm | Tùy nhà sản xuất module |
| Khối lượng | ~1g |
Điện trở Pull-up DATA
Datasheet AOSONG khuyến nghị:
- Cáp < 20m: 4.7kΩ (module thường đã tích hợp sẵn)
- Cáp 20–30m: 1kΩ (thêm ngoài)
- Cáp > 30m: không khuyến nghị
Lý do cần pull-up: Giao thức dùng open-drain — DHT11 chỉ kéo xuống GND, không đẩy lên HIGH. Cần resistor bên ngoài kéo đường DATA lên VCC.
Sơ Đồ Chân (Pinout)
DHT11 Bare Sensor (4 chân)
┌─────────┐
│ DHT11 │
│ │
1 ─ │ VCC │
2 ─ │ DATA │
3 ─ │ NC │ ← Không kết nối (Not Connected)
4 ─ │ GND │
└─────────┘
(Nhìn từ phía trước — có lỗ thông gió)
| Chân | Tên | Chức năng |
|---|---|---|
| 1 | VCC | Nguồn 3.0V – 5.5V |
| 2 | DATA | Dữ liệu single-wire (cần pull-up 4.7kΩ lên VCC) |
| 3 | NC | Bỏ trống |
| 4 | GND | Đất |
Module DHT11 (3 chân — phổ biến nhất)
┌───────────────┐
│ ┌─────────┐ │
│ │ DHT11 │ │
│ └─────────┘ │
│ [R 4.7kΩ] │
└───────────────┘
GND DATA VCC
│ │ │
Module đã tích hợp R 4.7kΩ pull-up → chỉ cần nối 3 dây.
| Chân module | Kết nối |
|---|---|
| VCC (+) | 3.3V hoặc 5V |
| DATA (S / OUT) | GPIO của MCU |
| GND (-) | GND |
Các Biến Thể Cùng Loại
| Sensor | Dải nhiệt độ | Độ chính xác T | Dải độ ẩm | Độ chính xác RH | Giao thức | Phân giải |
|---|---|---|---|---|---|---|
| DHT11 | 0–50°C | ±2°C | 20–80% | ±5% | Single-wire AOSONG | 1°C / 1% |
| DHT22 (AM2302) | -40–80°C | ±0.5°C | 0–100% | ±2% | Single-wire AOSONG | 0.1°C / 0.1% |
| DHT21 (AM2301) | -40–80°C | ±0.5°C | 0–100% | ±3% | Single-wire AOSONG | 0.1°C / 0.1% |
| SHT31 | -40–125°C | ±0.3°C | 0–100% | ±2% | I2C | 0.01°C |
| AHT20 | -40–85°C | ±0.3°C | 0–100% | ±2% | I2C | 0.01°C |
| AM2320 | -40–80°C | ±0.5°C | 0–100% | ±3% | I2C + Single-wire | 0.1°C |
Khi nào dùng DHT11: Prototype, học tập, môi trường trong nhà không yêu cầu độ chính xác cao, ngân sách hạn chế.
Khi nào không dùng DHT11: Độ ẩm ngoài 20–80% RH, cần độ chính xác < ±2°C, nhiệt độ < 0°C hoặc > 50°C, hệ thống production.
Kết Nối Phần Cứng
Kết Nối với ESP32 DevKit V1
Dùng GPIO4 — chân an toàn, không phải strapping pin, không phải input-only, không phải flash SPI.
ESP32 DevKit V1 DHT11 Module
───────────────────── ─────────────
3V3 ─────────────────→ VCC (+)
GND ─────────────────→ GND (-)
GPIO4 (pin 4) ────────→ DATA (S)
Tại sao dùng 3V3 thay vì 5V? ESP32 GPIO hoạt động ở mức 3.3V logic. DHT11 module hoạt động tốt ở 3.3V. Nếu cấp 5V cho module nhưng DATA kết nối trực tiếp GPIO ESP32 → GPIO nhận 5V → vượt mức tối đa 3.6V → hỏng chip.
Nếu bắt buộc dùng 5V (cáp dài): Cần mạch level shifter giữa DATA và GPIO ESP32.
Kết Nối với Arduino Uno
Arduino Uno DHT11 Module
───────────────────── ─────────────
5V ─────────────────→ VCC (+)
GND ─────────────────→ GND (-)
Pin 4 ────────────────→ DATA (S)
Arduino Uno GPIO chịu được 5V → kết nối trực tiếp, không cần level shifter.
Code Arduino IDE
Cài Library
Arduino Uno và ESP32 dùng library khác nhau:
| Board | Library | Cài từ |
|---|---|---|
| Arduino Uno | DHT sensor library by Adafruit | Arduino IDE Library Manager |
| ESP32 | DHTesp by beegee-tokyo | Arduino IDE Library Manager |
Cài trong Arduino IDE: Tools → Manage Libraries → tìm tên library → Install.
Code cho Arduino Uno
/*
* DHT11 - Đọc nhiệt độ và độ ẩm
* Board: Arduino Uno
* Library: DHT sensor library by Adafruit (cài từ Library Manager)
* Kết nối: DATA → Pin 4, VCC → 5V, GND → GND
*/
#include <DHT.h>
// Định nghĩa chân kết nối và loại cảm biến
#define DHT_PIN 4 // Chân DATA nối vào Arduino pin 4
#define DHT_TYPE DHT11 // Loại sensor: DHT11 (không phải DHT22)
// Khởi tạo đối tượng DHT
DHT dht(DHT_PIN, DHT_TYPE);
void setup() {
Serial.begin(9600); // Arduino Uno dùng 9600 baud
dht.begin(); // Khởi động DHT11
Serial.println("=== DHT11 Test - Arduino Uno ===");
Serial.println("Chờ 2 giây trước lần đọc đầu tiên...");
delay(2000); // DHT11 cần 1-2 giây để ổn định sau khi cấp điện
}
void loop() {
// DHT11 cần ít nhất 1 giây giữa 2 lần đọc
// Dùng 2 giây để an toàn hơn
delay(2000);
// Đọc độ ẩm (% RH)
float humidity = dht.readHumidity();
// Đọc nhiệt độ (°C mặc định, dht.readTemperature(true) để lấy °F)
float temperature = dht.readTemperature();
// Kiểm tra lỗi: hàm readHumidity/Temperature trả về NaN nếu đọc thất bại
if (isnan(humidity) || isnan(temperature)) {
Serial.println("LỖI: Không đọc được dữ liệu từ DHT11!");
Serial.println(" → Kiểm tra kết nối dây, điện trở pull-up 4.7kΩ");
return; // Bỏ qua lần này, thử lại sau 2 giây
}
// In kết quả ra Serial Monitor
Serial.print("Nhiệt độ : ");
Serial.print(temperature, 1); // 1 chữ số thập phân (DHT11 luôn trả về .0)
Serial.println(" °C");
Serial.print("Độ ẩm : ");
Serial.print(humidity, 1);
Serial.println(" %RH");
// Tính Heat Index (chỉ số nhiệt — cảm giác nóng thực tế)
// Chỉ có ý nghĩa khi nhiệt độ > 27°C VÀ độ ẩm > 40%
if (temperature >= 27.0 && humidity >= 40.0) {
float heatIndex = dht.computeHeatIndex(temperature, humidity, false);
Serial.print("Heat Index: ");
Serial.print(heatIndex, 1);
Serial.println(" °C (cảm giác)");
}
Serial.println("---");
}
Serial Monitor: Baud rate 9600, bật “Newline”.
Code cho ESP32
/*
* DHT11 - Đọc nhiệt độ và độ ẩm
* Board: ESP32 DevKit V1
* Library: DHTesp by beegee-tokyo (cài từ Library Manager)
* Kết nối: DATA → GPIO4, VCC → 3V3, GND → GND
*
* Lưu ý: Dùng 3V3 (không dùng 5V) để tránh hỏng GPIO ESP32
*/
#include <DHTesp.h>
// GPIO4 — chân an toàn trên ESP32 DevKit V1
// Không phải strapping pin, không phải input-only, không phải Flash SPI
#define DHT_PIN 4
// Khởi tạo đối tượng DHTesp
DHTesp dht;
void setup() {
Serial.begin(115200); // ESP32 dùng 115200 baud
// Cấu hình cảm biến: chân GPIO + loại sensor
dht.setup(DHT_PIN, DHTesp::DHT11);
Serial.println("=== DHT11 Test - ESP32 ===");
Serial.println("Chờ 2 giây trước lần đọc đầu tiên...");
delay(2000);
}
void loop() {
// getMinimumSamplingPeriod() trả về 1000ms cho DHT11
// Dùng max() để đảm bảo ít nhất 2000ms
delay(max((uint32_t)2000, (uint32_t)dht.getMinimumSamplingPeriod()));
// Đọc cả nhiệt độ và độ ẩm trong một lần gọi
TempAndHumidity data = dht.getTempAndHumidity();
// Kiểm tra lỗi đọc
DHTesp::DHTesp_ERROR err = dht.getStatus();
if (err != DHTesp::ERROR_NONE) {
Serial.print("LỖI DHT11: ");
Serial.println(dht.getStatusString()); // In mô tả lỗi
Serial.println(" → Kiểm tra kết nối GPIO4, điện áp 3V3");
return;
}
// In kết quả dạng gọn (printf style — chỉ hoạt động trên ESP32)
Serial.printf("Nhiệt độ : %.1f °C\n", data.temperature);
Serial.printf("Độ ẩm : %.1f %%RH\n", data.humidity);
// Tính Dew Point (điểm sương) — nhiệt độ mà hơi nước bắt đầu ngưng tụ
// Công thức Magnus approximation (±0.35°C trong dải 5–60°C)
float dewPoint = dht.computeDewPoint(data.temperature, data.humidity);
Serial.printf("Điểm sương: %.1f °C\n", dewPoint);
// Tính cảm giác nhiệt Heat Index (chỉ có ý nghĩa > 27°C, > 40%RH)
if (data.temperature >= 27.0f && data.humidity >= 40.0f) {
float heatIndex = dht.computeHeatIndex(data.temperature, data.humidity, false);
Serial.printf("Heat Index: %.1f °C (cảm giác)\n", heatIndex);
}
Serial.println("---");
}
Serial Monitor: Baud rate 115200.
Kết Quả Mong Đợi
=== DHT11 Test - ESP32 ===
Chờ 2 giây trước lần đọc đầu tiên...
Nhiệt độ : 28.0 °C
Độ ẩm : 65.0 %RH
Điểm sương: 21.1 °C
Heat Index: 30.3 °C (cảm giác)
---
Nhiệt độ : 28.0 °C
Độ ẩm : 65.0 %RH
...
Lưu ý về kết quả: DHT11 chỉ cho kết quả nguyên (28.0, không phải 28.3). Nếu cần độ phân giải 0.1°C → dùng DHT22.
Ứng Dụng Thực Tế
| Ứng dụng | Lý do dùng DHT11 | Khi nào cần sensor tốt hơn |
|---|---|---|
| Giám sát môi trường phòng | Đủ chính xác cho in-door | Phòng server: cần SHT31 |
| Cảnh báo độ ẩm cao (mốc) | Ngưỡng 80% RH rõ ràng | Bảo tàng, kho lạnh: SHT31 |
| Tự động bật quạt | Logic đơn giản ±5% OK | Hệ thống HVAC chính xác |
| Trạm thời tiết học tập | Giá rẻ, dễ lắp | Trạm thực tế ngoài trời |
| Smart farm cơ bản | Giám sát nhà kính | Tưới tự động chính xác: DHT22 |
Lưu Ý Khi Sử Dụng
1. Không đặt gần nguồn nhiệt
DHT11 đo nhiệt độ của không khí xung quanh sensor. Đặt gần điện trở nóng, IC, hoặc bảng mạch → kết quả cao hơn thực tế. Đặt xa ít nhất 3cm so với linh kiện tỏa nhiệt.
2. Không dùng ngay sau khi cấp điện
Sau khi cấp nguồn, chờ ít nhất 2 giây trước lần đọc đầu tiên. Capacitive sensor cần thời gian cân bằng với môi trường.
3. Lỗi “Failed to read” thường do:
- Thiếu hoặc sai giá trị resistor pull-up
- Dây DATA quá dài (> 20m mà không tăng pull-up)
- Đọc quá nhanh (< 1 giây giữa 2 lần)
- VCC không ổn định (dùng tụ bypass 100nF gần chân VCC)
4. Độ chính xác thực tế
Sau 2–3 năm sử dụng, polymer sensor bị lão hóa. Độ ẩm đọc có thể sai ±10% so với ban đầu. Calibrate định kỳ bằng cách so với sensor chuẩn hoặc dùng muối bão hòa (salt calibration method).
5. DHT11 không chống nước
Để sensor tiếp xúc trực tiếp với nước → hỏng. Nếu môi trường có thể bị ướt: dùng loại có vỏ bảo vệ (waterproof DHT22 với đầu dò cắm), hoặc đặt trong hộp có lỗ thông gió.
6. Không dùng với ngắt (interrupt)
Thư viện DHT đọc dữ liệu bằng bit-banging timing-critical. Nếu có interrupt xảy ra trong quá trình đọc → giao tiếp bị lỗi. Tránh gọi dht.read() trong ISR hoặc khi hệ thống có nhiều interrupt tần suất cao.


