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:
- Khuếch đại tín hiệu (op-amp stage 1 và 2)
- Lọc băng thông (bandpass filter ~0.1Hz – 10Hz — tần số người đi bộ)
- Comparator: so sánh với ngưỡng → quyết định có chuyển động không
- Điều khiển output timing (thời gian giữ HIGH)
- 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ỉnh | Vặn theo chiều kim đồng hồ | Vặn ngược chiều |
|---|---|---|---|
| Sx | Độ nhạy / Tầm xa | Tăng tầm (đến ~7m) | Giảm tầm (xuống ~3m) |
| Tx | Thời gian OUT HIGH | Tă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:
| Mode | Jumper | Hành vi |
|---|---|---|
| L (Single Trigger) | Jumper nối 2 chân trái | Trigger 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ải | Nế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 động | 5V – 20V |
| Dòng tiêu thụ (standby) | <60µA |
| Mức OUT khi phát hiện | 3.3V HIGH (không phải 5V!) |
| Mức OUT khi bình thường | LOW (0V) |
| Tầm phát hiện | 3m – 7m (điều chỉnh Sx) |
| Góc nhìn | ~120° ngang, ~90° đứng |
| Thời gian delay output | 0.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ước | 32mm × 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ân | Chức năng |
|---|---|
| VCC | 5V – 20V |
| OUT | Digital 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-SR501 | 2 pot điều chỉnh, jumper mode L/H, 5-20V | Phổ biến nhất, đa dụng |
| HC-SR505 | Nhỏ hơn, không có pot, cố định 5V | Nhúng vào sản phẩm nhỏ |
| AM312 | Cực nhỏ, 3.3V, không có kính rời | Wearable, IoT nhỏ |
| RCWL-0516 | Radar microwave 3.18GHz, xuyên tường/vật | Phát hiện qua cửa/tường mỏng |
| DYP-ME003 | PIR + relay tích hợp | Bậ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ụng | Gợi ý cấu hình |
|---|---|
| Đèn hành lang tự bật | H mode, Tx=1-3 phút, Sx=tối đa |
| Báo trộm | L mode, Tx=5 giây, kết hợp còi buzzer |
| Bật điều hòa khi có người | H mode, Tx=5 phút, điều khiển qua relay |
| Đếm lượt ra vào | L mode, Tx=1 giây, tăng counter mỗi HIGH |
| Camera an ninh tự kích | L mode, Tx=1 giây, trigger GPIO camera |
| Tiết kiệm điện tự động | H 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ổ.


