IoTLabs

Nghiên cứu, Sáng tạo và Thử nghiệm

Series 37 Module Cảm Biến – Nguyên Lý Hoạt Động DHT11: Cảm Biến Nhiệt Độ & Độ Ẩm Phổ Biến Nhất

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:

ByteNội dung
Byte 1Phần nguyên độ ẩm (VD: 55)
Byte 2Phần thập phân độ ẩm (DHT11 luôn = 0)
Byte 3Phần nguyên nhiệt độ (VD: 24)
Byte 4Phần thập phân nhiệt độ (DHT11 luôn = 0)
Byte 5Checksum = 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 động3.0V – 5.5VModule trên board có thể hạn chế
Dòng tiêu thụ (đo)0.5mALúc đang giao tiếp
Dòng tiêu thụ (standby)100µAGiữa 2 lần đọc
Dải nhiệt độ0°C – 50°CNgoài dải → kết quả sai
Độ chính xác nhiệt độ±2°CWorst case, typical ±1°C
Dải độ ẩm20% – 80% RHNgoài dải → không tin cậy
Độ chính xác độ ẩm±5% RHWorst case
Độ phân giải1°C / 1% RHKhông có dấu phẩy
Thời gian đáp ứng nhiệt độ≤30 giâyTrong điều kiện gió nhẹ
Thời gian đáp ứng độ ẩm≤5 giây
Sampling period tối thiểu1 giâyKhuyến nghị dùng 2 giây
Chiều dài cáp tối đa20mCần R pull-up 100Ω tại đầu cáp
Kích thước (sensor)15.5 × 12 × 5.5mmKhông gồm PCB module
Kích thước (module)23 × 12 × 5.5mmTù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ânTênChức năng
1VCCNguồn 3.0V – 5.5V
2DATADữ liệu single-wire (cần pull-up 4.7kΩ lên VCC)
3NCBỏ trống
4GNDĐấ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 moduleKế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

SensorDải nhiệt độĐộ chính xác TDải độ ẩmĐộ chính xác RHGiao thứcPhân giải
DHT110–50°C±2°C20–80%±5%Single-wire AOSONG1°C / 1%
DHT22 (AM2302)-40–80°C±0.5°C0–100%±2%Single-wire AOSONG0.1°C / 0.1%
DHT21 (AM2301)-40–80°C±0.5°C0–100%±3%Single-wire AOSONG0.1°C / 0.1%
SHT31-40–125°C±0.3°C0–100%±2%I2C0.01°C
AHT20-40–85°C±0.3°C0–100%±2%I2C0.01°C
AM2320-40–80°C±0.5°C0–100%±3%I2C + Single-wire0.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:

BoardLibraryCài từ
Arduino UnoDHT sensor library by AdafruitArduino IDE Library Manager
ESP32DHTesp by beegee-tokyoArduino 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ụngLý do dùng DHT11Khi 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-doorPhòng server: cần SHT31
Cảnh báo độ ẩm cao (mốc)Ngưỡng 80% RH rõ ràngBảo tàng, kho lạnh: SHT31
Tự động bật quạtLogic đơn giản ±5% OKHệ thống HVAC chính xác
Trạm thời tiết học tậpGiá rẻ, dễ lắpTrạm thực tế ngoài trời
Smart farm cơ bảnGiám sát nhà kínhTướ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.

Bài tiếp theo: