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 DS18B20: Cảm Biến Nhiệt Độ 1-Wire Chống Nước

DS18B20 khác hoàn toàn DHT11/DHT22 ở một điểm cốt lõi: nó dùng chuẩn 1-Wire của Maxim (nay là Analog Devices), cho phép nhiều sensor trên cùng 1 dây mà vẫn phân biệt được từng cái. Lý do chọn DS18B20 thay vì DHT: khi cần đo nhiệt độ chất lỏng, đất, hoặc môi trường khắc nghiệt — nơi sensor phải nhúng trực tiếp vào môi trường đo.

Nguyên Lý Hoạt Động

1. Đo Nhiệt Độ — Silicon Bandgap Reference

DS18B20 dùng nguyên lý bandgap temperature sensing thay vì NTC thermistor:

Trong transistor BJT, hiệu điện thế base-emitter (V_BE) phụ thuộc nhiệt độ theo:

VBE(T) = Vg0 × (1 – T/T₀) + V_BE(T₀) × (T/T₀) – (nkT/q) × ln(T/T₀)

Trong đó V_g0 ≈ 1.205V là bandgap silicon ở 0K. IC đo tỷ lệ giữa 2 transistor hoạt động ở mật độ dòng khác nhau → lấy được nhiệt độ tuyệt đối với độ chính xác cao, không cần calibrate từng con chip.

Ưu điểm so với NTC thermistor:

  • Tuyến tính theo nhiệt độ trong dải rộng (-55°C đến 125°C)
  • Không cần calibrate (tolerance do IC handle)
  • Không bị drift theo tuổi thọ như thermistor

2. Chuẩn 1-Wire — Nhiều Sensor, 1 Dây

Đây là công nghệ đặc trưng của Maxim/Dallas. Giao thức 1-Wire sử dụng chỉ 1 đường dữ liệu (cộng GND) nhưng có thể kết nối nhiều thiết bị (DS18B20, DS2431, DS2413…) trên cùng một dây.

Mỗi DS18B20 có ROM code 64-bit duy nhất (laser-engraved khi sản xuất):

ROM 64-bit:
┌──────────────────────────────────────────────────────────┐
│  8-bit Family Code │  48-bit Serial Number │  8-bit CRC  │
│      0x28          │   (unique per chip)   │  (checksum) │
└──────────────────────────────────────────────────────────┘

Family code 0x28 là định danh của dòng DS18B20 — khi master đọc ROM, nó biết đây là thermometer, không phải DS2431 (EEPROM) hay thiết bị 1-Wire khác.

Các lệnh 1-Wire quan trọng:

LệnhChức năng
SKIP ROM0xCCPhát lệnh tới TẤT CẢ sensor (chỉ dùng khi có 1 sensor)
MATCH ROM0x55Chọn sensor theo ROM address 64-bit
SEARCH ROM0xF0Tìm kiếm tất cả ROM trên bus
READ ROM0x33Đọc ROM (chỉ khi 1 sensor trên bus)
CONVERT T0x44Bắt đầu chuyển đổi nhiệt độ
READ SCRATCHPAD0xBEĐọc 9 byte bộ nhớ (gồm kết quả đo)

3. Scratchpad Memory — 9 Byte Kết Quả

Sau khi lệnh CONVERT T hoàn thành, kết quả lưu trong Scratchpad (bộ nhớ tạm 9 byte):

ByteNội dung
0Nhiệt độ LSB
1Nhiệt độ MSB
2Ngưỡng cao TH (user-programmable)
3Ngưỡng thấp TL (user-programmable)
4Configuration register (độ phân giải)
5–7Reserved
8CRC của byte 0–7

Ví dụ đọc nhiệt độ 25.0625°C:

  • Byte 0: 0x91 = 1001 0001
  • Byte 1: 0x01 = 0000 0001
  • Ghép: 0x0191 = 401 → 401 × 0.0625 = 25.0625°C

Độ phân giải cấu hình được (Configuration Register):

Bit R1:R0Độ phân giảiLSBThời gian chuyển đổi
009-bit0.5°C93.75ms
0110-bit0.25°C187.5ms
1011-bit0.125°C375ms
1112-bit0.0625°C750ms

Mặc định: 12-bit (750ms conversion time). Nếu cần đọc nhanh hơn, giảm xuống 9-bit (93ms) nhưng mất độ chính xác.

4. Parasite Power Mode — Không Cần Dây VCC

DS18B20 có chế độ đặc biệt: Parasite Power — lấy điện từ đường DATA (qua tụ bên trong, nạp khi bus ở mức HIGH). Chỉ cần 2 dây: DATA và GND.

Parasite Power:
MCU ─── [R 4.7kΩ] ─── DATA ─── DS18B20 pin DATA + VDD
                                DS18B20 pin GND ─── GND
(VDD nối với DATA, không nối VCC riêng)

Khi nào dùng parasite power: Dây cáp dài, khó kéo 3 dây. Nhưng có hạn chế: không dùng SKIP ROM với nhiều sensor, không đo chính xác > 100°C.

Thông Số Kỹ Thuật

Thông sốGiá trị
Điện áp (VDD)3.0V – 5.5V
Điện áp Parasite3.0V – 5.5V (từ DQ)
Dòng tiêu thụ (active)1.5mA
Dòng tiêu thụ (standby)750nA
Dải nhiệt độ-55°C – 125°C
Độ chính xác (±0.5°C)-10°C – 85°C
Độ phân giải9–12-bit (cấu hình được)
Thời gian chuyển đổi (12-bit)≤ 750ms
ROM Code64-bit laser-engraved unique
Số sensor trên 1 busNhiều (giới hạn bởi pull-up capacity)
Kích thước TO-92 (bare)4.4 × 3.7 × 2.8mm
Kích thước đầu dò chống nướcThường ∅6mm × 30mm (tùy loại)
Chiều dài cáp đầu dò1m, 2m, 3m (tùy loại, màu đen)

Sơ Đồ Chân (Pinout)

DS18B20 TO-92 (Bare Sensor)

  Nhìn từ mặt phẳng (mặt có chữ):
       GND   DQ   VDD
        │     │     │
       (1)   (2)   (3)
        ────────────
           DS18B20
           TO-92
ChânTênChức năng
1GNDĐất
2DQData / 1-Wire bus (cần pull-up 4.7kΩ lên VDD)
3VDDNguồn 3.0V – 5.5V (hoặc nối GND cho parasite mode)

Cách nhận biết chiều chân TO-92: Giữ sensor nhìn từ mặt phẳng (chữ hướng về phía bạn), chân trái là GND, giữa là DQ, phải là VDD.

Đầu Dò Chống Nước (Waterproof Probe)

Cáp 3 màu:
  Đỏ   → VDD (3.3V hoặc 5V)
  Vàng → DQ  (Data — cần pull-up)
  Đen  → GND

Đầu dò kim loại (thường là inox 304) bọc epoxy chống nước. Thực chất bên trong là DS18B20 TO-92 + R 4.7kΩ pull-up tích hợp trong vỏ nhựa đầu cáp.

Các Biến Thể Cùng Dòng

ModelĐặc điểmDùng khi
DS18B20 TO-92Bare sensor nhỏHàn trực tiếp PCB, prototype
DS18B20Z SOIC-8SMD packagePCB sản xuất hàng loạt
DS18B20 waterproof probeĐầu dò kim loại, cáp 1–3mĐo nhiệt độ nước, đất, chất lỏng
DS18S20Chỉ 9-bit, không cấu hình đượcĐời cũ, không khuyến nghị dùng mới
MAX31820Tương thích 1-Wire, 3.3VDùng khi nguồn 3.3V đơn thuần

Lưu ý DS18B20 giả (fake): Thị trường có nhiều DS18B20 không chính hãng. Dấu hiệu nhận biết: ROM không hợp lệ, đọc sai CRC, không hoạt động ở 3.3V, độ chính xác kém. Mua từ nhà phân phối uy tín.

Kết Nối Phần Cứng

Kết Nối với ESP32 DevKit V1

ESP32 DevKit V1          DS18B20
─────────────────────    ─────────────────
3V3  ─────────────────→  VDD (chân 3)
GND  ─────────────────→  GND (chân 1)
GPIO4 ────────────────→  DQ  (chân 2)

Pull-up:
3V3 ──[R 4.7kΩ]──────→  DQ  (chân 2)

Resistor pull-up 4.7kΩ BẮT BUỘC nếu dùng bare sensor. Module có sẵn thường đã tích hợp. Không có pull-up → bus luôn LOW → không đọc được.

Nhiều sensor trên 1 dây:

GPIO4 ──[R 4.7kΩ]── DQ ─┬─ DS18B20 #1 (DQ)
3V3 ─────────────────────┤
                          ├─ DS18B20 #2 (DQ)
                          └─ DS18B20 #3 (DQ)

Tất cả GND nối chung, tất cả VDD nối chung với 3V3.

Kết Nối với Arduino Uno

Arduino Uno              DS18B20
─────────────────────    ─────────────────
5V   ─────────────────→  VDD (chân 3)
GND  ─────────────────→  GND (chân 1)
Pin 4 ────────────────→  DQ  (chân 2)

5V ──[R 4.7kΩ]────────→  DQ  (chân 2)

Code Arduino IDE

Cài Library

BoardLibrary 1Library 2
Arduino Uno + ESP32OneWire by Paul StoffregenDallasTemperature by Miles Burton

Cả hai cần cài đặt. Trong Library Manager tìm “DallasTemperature” → Install → khi hỏi về dependency chọn “Install All” (tự cài OneWire).

Code cho Arduino Uno (1 Sensor)

/*
 * DS18B20 - Đọc nhiệt độ 1 sensor
 * Board: Arduino Uno
 * Library: OneWire + DallasTemperature
 * Kết nối: DQ → Pin 4, R 4.7kΩ từ DQ lên 5V, VDD → 5V, GND → GND
 */

#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_PIN  4   // Chân DQ kết nối vào Arduino pin 4

// Khởi tạo bus 1-Wire trên pin 4
OneWire oneWire(ONE_WIRE_PIN);

// Khởi tạo DallasTemperature dùng bus 1-Wire vừa tạo
DallasTemperature sensors(&oneWire);

void setup() {
  Serial.begin(9600);
  sensors.begin(); // Quét bus 1-Wire, tìm các sensor DS18B20

  // In số sensor tìm được trên bus
  Serial.println("=== DS18B20 Test - Arduino Uno ===");
  Serial.print("Số sensor tìm thấy: ");
  Serial.println(sensors.getDeviceCount());

  // Cấu hình độ phân giải 12-bit (mặc định) — 0.0625°C, 750ms
  // Giảm xuống 9-bit nếu cần đọc nhanh hơn (93ms, 0.5°C resolution)
  sensors.setResolution(12);
}

void loop() {
  // Gửi lệnh CONVERT T tới TẤT CẢ sensor trên bus
  // Dùng SKIP ROM → tất cả đồng thời chuyển đổi → tiết kiệm thời gian
  sensors.requestTemperatures();

  // Chờ đủ thời gian chuyển đổi (750ms cho 12-bit)
  // Thư viện tự xử lý nếu không dùng setWaitForConversion(false)
  delay(1000); // Dư giờ để chắc chắn

  // Đọc nhiệt độ sensor đầu tiên (index = 0)
  float tempC = sensors.getTempCByIndex(0);

  // Kiểm tra lỗi: DEVICE_DISCONNECTED_C = -127.0
  if (tempC == DEVICE_DISCONNECTED_C) {
    Serial.println("LỖI: Không tìm thấy DS18B20!");
    Serial.println("  → Kiểm tra: dây kết nối, R pull-up 4.7kΩ, chiều chân TO-92");
    return;
  }

  Serial.print("Nhiệt độ: ");
  Serial.print(tempC, 2); // 2 chữ số thập phân: "25.06 °C"
  Serial.println(" °C");
  Serial.println("---");
}

Code cho Arduino Uno (Nhiều Sensor — Dùng ROM Address)

/*
 * DS18B20 - Đọc nhiều sensor trên cùng 1 dây
 * Board: Arduino Uno
 * Kết nối: Tất cả DQ nối chung vào Pin 4, R 4.7kΩ pull-up
 */

#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_PIN 4

OneWire oneWire(ONE_WIRE_PIN);
DallasTemperature sensors(&oneWire);

// Mảng lưu địa chỉ ROM của từng sensor (8 byte mỗi sensor)
DeviceAddress sensorAddresses[10]; // Tối đa 10 sensor
int sensorCount = 0;

void setup() {
  Serial.begin(9600);
  sensors.begin();

  sensorCount = sensors.getDeviceCount();
  Serial.print("Tìm thấy ");
  Serial.print(sensorCount);
  Serial.println(" sensor DS18B20:");

  // Lấy và in ROM address của từng sensor
  for (int i = 0; i < sensorCount; i++) {
    if (sensors.getAddress(sensorAddresses[i], i)) {
      Serial.print("  Sensor ");
      Serial.print(i);
      Serial.print(": ROM = ");
      // In ROM code dạng hex
      for (int j = 0; j < 8; j++) {
        if (sensorAddresses[i][j] < 0x10) Serial.print("0");
        Serial.print(sensorAddresses[i][j], HEX);
        if (j < 7) Serial.print(":");
      }
      Serial.println();
    }
  }
  sensors.setResolution(12);
}

void loop() {
  sensors.requestTemperatures(); // Đo tất cả cùng lúc
  delay(1000);

  for (int i = 0; i < sensorCount; i++) {
    // Đọc theo ROM address — chính xác sensor nào là sensor nào
    float tempC = sensors.getTempC(sensorAddresses[i]);
    Serial.print("Sensor ");
    Serial.print(i);
    Serial.print(": ");
    if (tempC == DEVICE_DISCONNECTED_C) {
      Serial.println("NGẮT KẾT NỐI");
    } else {
      Serial.print(tempC, 2);
      Serial.println(" °C");
    }
  }
  Serial.println("---");
}

Code cho ESP32

/*
 * DS18B20 - Đọc nhiệt độ
 * Board: ESP32 DevKit V1
 * Library: OneWire + DallasTemperature (cùng library với Arduino Uno)
 * Kết nối: DQ → GPIO4, R 4.7kΩ từ DQ lên 3V3, VDD → 3V3, GND → GND
 *
 * Ưu điểm ESP32: có thể đọc DS18B20 không blocking nhờ millis()
 */

#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_PIN  4  // GPIO4 — an toàn, không phải strapping pin

OneWire oneWire(ONE_WIRE_PIN);
DallasTemperature sensors(&oneWire);

// Biến cho non-blocking conversion
bool conversionRequested = false;
unsigned long conversionStartTime = 0;
const unsigned long CONVERSION_TIME_MS = 750; // 750ms cho 12-bit

void setup() {
  Serial.begin(115200);
  sensors.begin();
  sensors.setResolution(12);

  // Tắt blocking mode — requestTemperatures() trả về ngay, không chờ 750ms
  // Phải tự chờ CONVERSION_TIME_MS trước khi đọc
  sensors.setWaitForConversion(false);

  Serial.println("=== DS18B20 Test - ESP32 ===");
  Serial.printf("Số sensor: %d\n", sensors.getDeviceCount());
}

void loop() {
  unsigned long now = millis();

  // Bắt đầu chuyển đổi nếu chưa yêu cầu, hoặc đã qua đủ 1 chu kỳ
  if (!conversionRequested) {
    sensors.requestTemperatures(); // Không blocking vì setWaitForConversion(false)
    conversionStartTime = now;
    conversionRequested = true;
  }

  // Chờ đủ 750ms kể từ khi request (không dùng delay — không blocking)
  if (conversionRequested && (now - conversionStartTime >= CONVERSION_TIME_MS)) {
    conversionRequested = false; // Reset để chu kỳ tiếp theo request lại

    // Đọc kết quả
    float tempC = sensors.getTempCByIndex(0);

    if (tempC == DEVICE_DISCONNECTED_C) {
      Serial.println("LỖI: DS18B20 không kết nối!");
      return;
    }

    Serial.printf("Nhiệt độ: %.2f °C\n", tempC);

    // Ứng dụng: cảnh báo khi nhiệt độ vượt ngưỡng
    if (tempC > 80.0f) {
      Serial.println("  ⚠ CẢNH BÁO: Nhiệt độ quá cao!");
    } else if (tempC < 0.0f) {
      Serial.println("  ⚠ CẢNH BÁO: Nhiệt độ dưới 0°C!");
    }

    Serial.println("---");

    // Chờ 1 giây trước chu kỳ tiếp theo (millis-based, không blocking)
    delay(1000); // Đơn giản hóa — dùng millis() trong project thực
  }
}

Kết Quả Mong Đợi

=== DS18B20 Test - ESP32 ===
Số sensor: 1
Nhiệt độ: 25.06 °C   ← 12-bit resolution: bước 0.0625°C
---
Nhiệt độ: 25.13 °C
---

Khi nhúng vào nước lạnh: giá trị giảm dần trong 5–10 giây (thời gian đáp ứng phụ thuộc vỏ bọc đầu dò).

Ứng Dụng Thực Tế

Ứng dụngTại sao DS18B20Ghi chú
Đo nhiệt độ nướcĐầu dò chống nước, 125°CKhông dùng DHT
Đo nhiệt độ đấtĐầu dò inox chống ăn mònSoil temp cho nông nghiệp
Nhiệt độ dầu máy125°C max — đủ cho nhiều ứng dụng
Nhiều điểm đo (1 dây)1 GPIO cho nhiều sensorTòa nhà, nhà kính
Tủ đông / kho lạnh-55°C — đo được âm sâu
Kiểm soát nhiệt độ aquariumKhông rò điện, chính xác

Lưu Ý Khi Sử Dụng

1. Pull-up 4.7kΩ là bắt buộc

1-Wire là open-drain — DS18B20 chỉ kéo bus xuống LOW, không đẩy lên HIGH. Không có pull-up → bus luôn LOW → không đọc được bất kỳ dữ liệu nào. Nếu dùng nhiều sensor hoặc cáp dài, giảm pull-up xuống 2.2kΩ để tăng tốc độ sườn lên (rise time).

2. Thời gian chờ 750ms

Ở độ phân giải 12-bit, DS18B20 cần 750ms để hoàn thành chuyển đổi. Đọc trước 750ms → nhận giá trị không hoàn chỉnh. Dùng setWaitForConversion(false) + millis() để không blocking toàn bộ chương trình.

3. Phân biệt nhiều sensor

Khi có nhiều sensor, đọc theo ROM address (không phải index). Index có thể thay đổi tùy thứ tự tìm kiếm trên bus. ROM address không thay đổi. Lần đầu chạy: in ROM của từng sensor → gắn nhãn vật lý → hardcode ROM vào code.

4. DS18B20 giả (clone) phổ biến

Dấu hiệu sensor giả: đọc -127°C, -127.00, hoặc 85°C (giá trị reset mặc định). Thử test với 5V (dù chạy ở 3.3V) — sensor giả thường không hoạt động ở 3.3V.

5. Cáp dài > 10m

Cần giảm pull-up xuống 1–2kΩ, thêm tụ 100nF từ DATA xuống GND tại điểm cuối dây để chống nhiễu. Cáp > 30m: cân nhắc dùng DS2482 (I2C to 1-Wire bridge).

Bài tiếp theo: