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 PIR HC-SR501: Pyroelectric Infrared, Fresnel Lens & Phát Hiện Chuyển Động

PIR (Passive Infrared) HC-SR501 phát hiện chuyển động của người và động vật bằng cách cảm nhận thay đổi bức xạ hồng ngoại. “Passive” vì không phát ra IR — chỉ nhận. Thiết kế thông minh với vật liệu pyroelectric và kính Fresnel cho phép phân biệt người đang di chuyển với nền nhiệt ổn định. Bài này phân tích sâu từng thành phần và hướng dẫn điều chỉnh 2 biến trở + mode hoạt động.

Nguyên Lý Hoạt Động

1. Vật Liệu Pyroelectric — Điện Từ Nhiệt Hồng Ngoại

Cảm biến PIR dùng vật liệu pyroelectric (thường là LiTaO₃ — lithium tantalate, hoặc PVDF — polyvinylidene fluoride) có tính chất đặc biệt: tạo ra điện tích khi nhiệt độ thay đổi.

Vật liệu pyroelectric:
                    Không có thay đổi IR → Điện tích phân cực ổn định
                                         → Không có tín hiệu ra

     Bức xạ IR (cơ thể người 37°C) tới:
                    IR tăng → Tinh thể ấm lên nhanh
                             → Điện tích thay đổi
                             → Tạo ra điện áp nhỏ (µV – mV)
                             → Khuếch đại → Phát hiện

“Passive” vì: Không cần nguồn IR bên ngoài (khác với Active IR phải phát LED IR). Vật liệu pyroelectric chỉ phản ứng khi có thay đổi nhiệt độ → tiết kiệm năng lượng, không bị ngược.

2. Hai Phần Tử Vi Sai — Loại Trừ Nhiễu Nền

Bên trong vỏ HC-SR501 có hai phần tử pyroelectric đặt song song nhưng đấu ngược chiều nhau (differential pair):

       IR chiếu lên
      ┌──────────────┐
      │  Phần tử A   │ → Tạo điện áp +V_A
      │  Phần tử B   │ → Tạo điện áp -V_B (đấu ngược)
      └──────────────┘
      
Khi cả hai phần tử nhận cùng IR (nền nhiệt đồng đều):
  V_A + (-V_B) = 0 → Không có tín hiệu ra → Không báo

Khi người di chuyển (IR không đồng đều):
  Trước: Phần tử A nhận IR → V_A tăng → V_A - V_B ≠ 0 → Tín hiệu!
  Sau:   Người qua → Phần tử B nhận IR → -V_B tăng → lại tín hiệu!

Ý nghĩa thực tế: Sensor không phản ứng với nhiệt độ ổn định (bức tường ấm, nắng chiếu ổn định). Chỉ phản ứng khi có thay đổi — tức là khi người/vật ấm di chuyển qua vùng nhạy.

3. Kính Fresnel — Phân Vùng Nhạy

Kính trắng đục trên HC-SR501 là kính Fresnel (Fresnel lens) — không phải che bụi. Đây là thành phần quang học tạo ra mẫu nhạy đặc trưng.

Cấu trúc kính Fresnel của PIR:

Nhìn từ trước (kính đục trắng):
┌─────────────────────────────────────┐
│ [Vùng 1][Vùng 2][Vùng 3][Vùng 4]  │ ← Hàng trên
│ [Vùng 5][Vùng 6][Vùng 7][Vùng 8]  │ ← Hàng dưới
└─────────────────────────────────────┘

Mỗi "vùng" là một thấu kính nhỏ hội tụ IR từ một góc khác nhau vào phần tử pyroelectric

Hiệu quả: Khi người đứng yên trong vùng → mỗi vùng nhỏ chiếu IR liên tục vào phần tử → vi sai = 0 → không báo. Khi người di chuyển qua ranh giới giữa các vùng → cường độ IR thay đổi đột ngột → vi sai ≠ 0 → báo chuyển động.

Góc nhìn và tầm xa phụ thuộc kính Fresnel — không phải vật liệu pyroelectric. Thay kính Fresnel khác nhau → thay đổi góc nhìn và tầm xa.

4. IC Xử Lý BISS0001 — Lọc Và Quyết Định

Tín hiệu từ phần tử pyroelectric rất nhỏ và nhiều nhiễu. IC BISS0001 (hoặc tương đương) làm:

  1. Khuếch đại tín hiệu (op-amp stage 1 và 2)
  2. Lọc băng thông (bandpass filter ~0.1Hz – 10Hz — tần số người đi bộ)
  3. Comparator: so sánh với ngưỡng → quyết định có chuyển động không
  4. Điều khiển output timing (thời gian giữ HIGH)
  5. Block time (blank time): ~3 giây sau mỗi lần trigger, không trigger lại

5. Hai Biến Trở Điều Chỉnh

HC-SR501 có 2 biến trở (potentiometer) nhỏ màu xanh trên board:

┌──────────────────────────────┐
│  HC-SR501                    │
│  ┌────┐  ┌────┐              │
│  │ Sx │  │ Tx │              │
│  └────┘  └────┘              │
│   VCC   OUT   GND            │
└──────────────────────────────┘

Sx = Sensitivity (độ nhạy, tầm xa)
Tx = Time delay (thời gian output HIGH)
Biến trởĐiều chỉnhVặn theo chiều kim đồng hồVặn ngược chiều
SxĐộ nhạy / Tầm xaTăng tầm (đến ~7m)Giảm tầm (xuống ~3m)
TxThời gian OUT HIGHTăng (đến ~5 phút)Giảm (xuống ~0.3 giây)

6. Hai Mode Hoạt Động (Jumper)

Trên board có jumper 3-pin để chọn mode:

ModeJumperHành vi
L (Single Trigger)Jumper nối 2 chân tráiTrigger 1 lần → OUT HIGH theo Tx → tự hết → không trigger lại trong blank time
H (Repeat Trigger)Jumper nối 2 chân phảiNếu vẫn phát hiện chuyển động → reset bộ đếm thời gian → OUT HIGH kéo dài liên tục

Khuyến nghị:

  • Bật/tắt đèn theo người: dùng H mode — đèn tắt sau Tx giây kể từ lần di chuyển cuối
  • Đếm sự kiện/log: dùng L mode — mỗi lần bước qua = 1 sự kiện riêng biệt

Thông Số Kỹ Thuật

Thông sốGiá trị
Điện áp hoạt động5V – 20V
Dòng tiêu thụ (standby)<60µA
Mức OUT khi phát hiện3.3V HIGH (không phải 5V!)
Mức OUT khi bình thườngLOW (0V)
Tầm phát hiện3m – 7m (điều chỉnh Sx)
Góc nhìn~120° ngang, ~90° đứng
Thời gian delay output0.3 giây – 5 phút (điều chỉnh Tx)
Blank time sau trigger~3 giây (không thể trigger lại)
Nhiệt độ hoạt động-15°C – 70°C
Kích thước32mm × 24mm
Thời gian khởi động (warmup)30 – 60 giây

OUT = 3.3V: Dù cấp 5V–20V, out chỉ là 3.3V HIGH → tương thích trực tiếp với ESP32 (không cần level shifter).

Sơ Đồ Chân (Pinout)

         [Kính Fresnel]
     ┌──────────────────┐
     │   HC-SR501       │
     │  [Sx pot][Tx pot]│
     │  [BISS0001 IC]   │
     │                  │
     └──────────────────┘
      VCC    OUT    GND
ChânChức năng
VCC5V – 20V
OUTDigital output: 3.3V HIGH khi phát hiện, 0V khi bình thường
GNDĐất

Chú ý thứ tự chân: Nhìn từ mặt trước (kính Fresnel về phía bạn) — thứ tự từ trái sang phải thường là GND, OUT, VCC. Luôn kiểm tra ký hiệu in trên PCB — một số batch có thứ tự khác nhau.

Phân Biệt PIR HC-SR501 Với Các Loại Khác

ModelĐặc điểmỨng dụng
HC-SR5012 pot điều chỉnh, jumper mode L/H, 5-20VPhổ biến nhất, đa dụng
HC-SR505Nhỏ hơn, không có pot, cố định 5VNhúng vào sản phẩm nhỏ
AM312Cực nhỏ, 3.3V, không có kính rờiWearable, IoT nhỏ
RCWL-0516Radar microwave 3.18GHz, xuyên tường/vậtPhát hiện qua cửa/tường mỏng
DYP-ME003PIR + relay tích hợpBật/tắt trực tiếp đèn AC

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

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

HC-SR501 cần 5V input nhưng OUT = 3.3V → tương thích trực tiếp với ESP32:

ESP32 DevKit V1           HC-SR501
─────────────────────     ──────────────
5V (VIN hoặc USB 5V)──→  VCC  (cần 5V — không dùng 3V3!)
GND  ─────────────────→  GND
GPIO4 (Input) ←────────  OUT  (OUT=3.3V HIGH — an toàn với GPIO)

GPIO4 là safe pin cho digital input trên ESP32. Có thể dùng GPIO4, 13, 14, 16, 17, 18, 19, 21, 22, 23 — bất kỳ GPIO thường nào.

KHÔNG lấy VCC từ 3V3 pin ESP32: HC-SR501 cần ít nhất 5V để hoạt động đúng. Lấy từ USB 5V hoặc nguồn ngoài.

Kết Nối với Arduino Uno

Arduino Uno              HC-SR501
─────────────────────    ──────────────
5V  ──────────────────→  VCC
GND ──────────────────→  GND
Pin 2 (Interrupt) ←────  OUT  (3.3V HIGH — Arduino Uno nhận OK vì >2V)

Pin 2 và Pin 3 của Arduino Uno hỗ trợ hardware interrupt (INT0, INT1) — cho phép dùng attachInterrupt().

Code Arduino IDE

Code Polling Đơn Giản — Arduino Uno

/*
 * PIR HC-SR501 — Phát hiện chuyển động bằng polling
 * Board: Arduino Uno
 * Kết nối: VCC→5V, GND→GND, OUT→Pin2
 *
 * QUAN TRỌNG: Sau khi cấp điện, chờ 30-60 giây để sensor khởi động
 * OUT HIGH = phát hiện chuyển động
 * OUT LOW  = không có chuyển động
 */

const int PIR_PIN = 2;

// Trạng thái trước đó — để phát hiện thay đổi (không in liên tục)
bool lastState = false;

void setup() {
  Serial.begin(9600);
  pinMode(PIR_PIN, INPUT);

  // Đợi PIR khởi động
  Serial.println("Khởi động PIR HC-SR501...");
  Serial.println("Chờ 30 giây để sensor ổn định...");
  for (int i = 30; i > 0; i--) {
    Serial.print(i); Serial.print("s ");
    delay(1000);
    if (i % 10 == 0) Serial.println();
  }
  Serial.println("\nSẵn sàng phát hiện chuyển động!");
  Serial.println("====================================");
}

void loop() {
  bool currentState = (digitalRead(PIR_PIN) == HIGH);

  // Chỉ in khi trạng thái thay đổi — tránh spam Serial
  if (currentState != lastState) {
    if (currentState) {
      Serial.print("[");
      Serial.print(millis() / 1000);
      Serial.println("s] >>> PHÁT HIỆN CHUYỂN ĐỘNG! <<<");
    } else {
      Serial.print("[");
      Serial.print(millis() / 1000);
      Serial.println("s] Không có chuyển động");
    }
    lastState = currentState;
  }

  delay(50); // Polling mỗi 50ms
}

Code Interrupt — Arduino Uno (Tiết Kiệm CPU)

/*
 * PIR HC-SR501 — Phát hiện chuyển động bằng interrupt
 * Board: Arduino Uno
 * Kết nối: VCC→5V, GND→GND, OUT→Pin2 (INT0)
 *
 * Interrupt: không cần polling liên tục — MCU làm việc khác, chỉ
 * bị ngắt khi PIR thay đổi trạng thái. Tiết kiệm CPU, phản ứng nhanh hơn.
 */

const int PIR_PIN = 2; // Pin 2 = INT0 trên Arduino Uno

volatile bool motionDetected = false;
volatile bool motionEnded    = false;

// Interrupt khi OUT lên HIGH (bắt đầu phát hiện)
void onMotionStart() {
  motionDetected = true;
}

// Interrupt khi OUT xuống LOW (hết phát hiện)
void onMotionEnd() {
  motionEnded = true;
}

void setup() {
  Serial.begin(9600);
  pinMode(PIR_PIN, INPUT);

  // CHANGE: kích hoạt interrupt khi pin thay đổi HIGH ↔ LOW
  attachInterrupt(digitalPinToInterrupt(PIR_PIN), []() {
    if (digitalRead(PIR_PIN) == HIGH) {
      motionDetected = true;
    } else {
      motionEnded = true;
    }
  }, CHANGE);

  Serial.println("PIR HC-SR501 Interrupt Mode");
  Serial.println("Chờ 30s warmup...");
  delay(30000);
  Serial.println("Sẵn sàng!");
}

void loop() {
  // Xử lý flag từ interrupt trong main loop (không làm việc nặng trong ISR)
  if (motionDetected) {
    motionDetected = false;
    Serial.print("["); Serial.print(millis()/1000); Serial.println("s] CHUYỂN ĐỘNG PHÁT HIỆN!");
    // Thêm: bật đèn, gửi MQTT, log...
  }

  if (motionEnded) {
    motionEnded = false;
    Serial.print("["); Serial.print(millis()/1000); Serial.println("s] Kết thúc chuyển động");
  }

  // MCU có thể làm việc khác ở đây mà không cần delay dài
  delay(10);
}

Code ESP32 — Interrupt + Bật Đèn Theo Chuyển Động

/*
 * PIR HC-SR501 — ESP32, phát hiện chuyển động và bật đèn tự động
 * Board: ESP32 DevKit V1
 * Kết nối: VCC→5V, GND→GND, OUT→GPIO4
 * LED: GPIO2 (LED onboard ESP32 — active HIGH)
 *
 * Mode: Khi phát hiện chuyển động → bật LED → tự tắt sau LIGHT_ON_DURATION giây
 *        nếu phát hiện tiếp trong lúc đang bật → reset timer (H mode behavior)
 *
 * QUAN TRỌNG: Đặt jumper HC-SR501 ở H mode (repeat trigger) cho ứng dụng này
 */

const int PIR_PIN  = 4;  // GPIO4: safe digital input
const int LED_PIN  = 2;  // LED onboard ESP32 DevKit

const unsigned long LIGHT_ON_DURATION = 30000; // 30 giây — giữ đèn sáng sau chuyển động
                                                 // Thay đổi theo nhu cầu (ms)

volatile bool pirState = false;    // Trạng thái PIR hiện tại (từ interrupt)
volatile bool stateChanged = false; // Flag: có thay đổi cần xử lý

unsigned long lastMotionTime = 0;  // Thời điểm phát hiện chuyển động gần nhất
bool lightOn = false;              // Trạng thái đèn hiện tại

void IRAM_ATTR onPIRChange() {
  // IRAM_ATTR: đặt ISR trong IRAM của ESP32 — chạy nhanh hơn từ flash
  pirState = (digitalRead(PIR_PIN) == HIGH);
  stateChanged = true;
}

void setup() {
  Serial.begin(115200);
  pinMode(PIR_PIN, INPUT);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW); // Tắt LED ban đầu

  attachInterrupt(digitalPinToInterrupt(PIR_PIN), onPIRChange, CHANGE);

  Serial.println("=== PIR HC-SR501 + Đèn Tự Động - ESP32 ===");
  Serial.println("Chờ 30 giây để PIR khởi động...");
  delay(30000);
  Serial.println("Sẵn sàng!");
}

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

  // Xử lý thay đổi từ interrupt
  if (stateChanged) {
    stateChanged = false;

    if (pirState) {
      // Chuyển động phát hiện → cập nhật thời gian, bật đèn
      lastMotionTime = now;
      if (!lightOn) {
        lightOn = true;
        digitalWrite(LED_PIN, HIGH);
        Serial.printf("[%lus] Chuyển động! Bật đèn.\n", now / 1000);
      } else {
        // Đèn đang bật, reset timer
        Serial.printf("[%lus] Chuyển động tiếp theo — reset timer.\n", now / 1000);
      }
    } else {
      Serial.printf("[%lus] PIR: Hết chuyển động.\n", now / 1000);
    }
  }

  // Tắt đèn sau khi không có chuyển động đủ lâu
  if (lightOn && (now - lastMotionTime > LIGHT_ON_DURATION)) {
    lightOn = false;
    digitalWrite(LED_PIN, LOW);
    Serial.printf("[%lus] Tắt đèn (không có chuyển động %lus).\n",
      now / 1000, LIGHT_ON_DURATION / 1000);
  }

  // Không cần delay lớn — loop chạy nhanh
  delay(50);
}

Kết Quả Mong Đợi

=== PIR HC-SR501 + Đèn Tự Động - ESP32 ===
Chờ 30 giây để PIR khởi động...
Sẵn sàng!
[32s] Chuyển động! Bật đèn.
[35s] PIR: Hết chuyển động.
[38s] Chuyển động tiếp theo — reset timer.
[41s] PIR: Hết chuyển động.
[71s] Tắt đèn (không có chuyển động 30s).

Ứng Dụng Thực Tế

Ứng dụngGợi ý cấu hình
Đèn hành lang tự bậtH mode, Tx=1-3 phút, Sx=tối đa
Báo trộmL mode, Tx=5 giây, kết hợp còi buzzer
Bật điều hòa khi có ngườiH mode, Tx=5 phút, điều khiển qua relay
Đếm lượt ra vàoL mode, Tx=1 giây, tăng counter mỗi HIGH
Camera an ninh tự kíchL mode, Tx=1 giây, trigger GPIO camera
Tiết kiệm điện tự độngH mode, Tx=10 phút, tắt mọi thiết bị điện khi không người

Lưu Ý Khi Sử Dụng

1. Bắt buộc warmup 30–60 giây sau khi cấp điện

Sau khi bật nguồn, HC-SR501 mất 30–60 giây để IC BISS0001 khởi động và sensor pyroelectric ổn định ở nhiệt độ môi trường. Trong giai đoạn này OUT có thể HIGH giả nhiều lần. Không dùng kết quả trong 30 giây đầu.

2. VCC cần 5V tối thiểu

HC-SR501 cần ít nhất 5V input (datasheet nói 5-20V). Không cấp 3.3V từ ESP32 pin 3V3 — sensor hoạt động không ổn định. Cấp 5V từ USB hoặc nguồn ngoài, GND chung với ESP32.

3. Blank time ~3 giây — không re-trigger được

Sau mỗi lần OUT xuống LOW, HC-SR501 có khoảng ~3 giây blank time không nhận trigger mới. Đây là thiết kế cố ý để tránh nhiễu. Nếu cần phát hiện liên tục không bị gián đoạn → dùng H mode.

4. Nhiệt độ phòng ảnh hưởng đến tầm xa

PIR hoạt động dựa trên sự chênh lệch nhiệt độ giữa người (37°C) và nền. Trong phòng lạnh (15°C) → chênh nhiệt lớn → nhạy hơn, tầm xa hơn. Trong phòng nóng (35°C) → chênh nhiệt nhỏ → kém nhạy hơn, tầm ngắn hơn.

5. Không phát hiện người đứng yên

Kính Fresnel tạo “vùng nhạy” — khi người di chuyển qua ranh giới giữa các vùng → phát hiện. Người đứng yên lâu trong một vùng → nhiệt ổn định → không phát hiện → đèn tắt (điều này là bình thường, không phải lỗi).

6. Tránh đặt gần nguồn nhiệt thay đổi

Điều hòa bật/tắt, quạt dao động, ánh nắng di chuyển qua cửa sổ → có thể gây trigger giả. Đặt sensor xa nguồn nhiệt và tránh góc nhìn thẳng ra cửa sổ.

Bài tiếp theo: