IoTLabs

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

Series ESP32 & Cảm biến: Bài 2 – Đọc cảm biến PIR HC-SR501: phát hiện chuyển động & theo dõi realtime

Ở bài này, chúng ta sử dụng cảm biến PIR HC-SR501 để phát hiện chuyển động của con người dựa trên bức xạ hồng ngoại. PIR là một trong những cảm biến dễ dùng nhất, rất phù hợp cho các bài toán như:

  • Báo có người
  • Bật đèn tự động
  • Giám sát phòng / cửa / hành lang

Bài viết gồm 2 ví dụ code:

  1. Đọc PIR local và hiển thị Serial
  2. Gửi trạng thái PIR lên IoTLabs Cloud MQTT để theo dõi realtime

1) Nguyên lý ngắn gọn về PIR HC-SR501

  • PIR không đo khoảng cách hay hình ảnh
  • so sánh sự thay đổi nhiệt hồng ngoại trong vùng quan sát
  • Khi có người/động vật di chuyển → OUT = HIGH

Đặc điểm:

  • Output: Digital (HIGH / LOW)
  • Điện áp hoạt động: 5V (nhưng OUT an toàn ở 3.3V cho ESP32)
  • Có 2 biến trở:
    • Time: thời gian giữ mức HIGH
    • Sensitivity: độ nhạy

2) Chuẩn bị

Phần cứng

  • ESP32-C3 SuperMini (Tenstar Robot)
  • PIR HC-SR501
  • Breadboard + dây

Chân sử dụng

  • PIR_OUT → GPIO2
  • VCC → 5V
  • GND → GND

⚠️ Lưu ý:

  • PIR nên cấp 5V để hoạt động ổn định
  • GPIO ESP32 chỉ đọc tín hiệu, không cấp nguồn

3) Nối dây PIR với ESP32

PIR HC-SR501        ESP32-C3 SuperMini
-----------------------------------
VCC   ------------ 5V
GND   ------------ GND
OUT   ------------ GPIO2

4) Trạng thái đọc được từ PIR

Giá trị OUTÝ nghĩa
LOW (0)Không có chuyển động
HIGH (1)Phát hiện chuyển động

Ví dụ 1 — Code local đơn giản (đọc PIR + Serial)

Mục tiêu: phát hiện chuyển động và in trạng thái ra Serial Monitor.

// ===== PIR Local Read =====
const int PIR_PIN = 2;

int lastState = LOW;

void setup() {
  Serial.begin(115200);
  delay(200);

  pinMode(PIR_PIN, INPUT);
  Serial.println("PIR local monitor started...");
}

void loop() {
  int state = digitalRead(PIR_PIN);

  if (state != lastState) {
    if (state == HIGH) {
      Serial.println("🚶 Phát hiện chuyển động!");
    } else {
      Serial.println("🟢 Không còn chuyển động");
    }
    lastState = state;
  }

  delay(100);
}

✅ Kết quả:

  • Khi có người đi qua → in “Phát hiện chuyển động”
  • Khi đứng yên → quay lại trạng thái LOW

5) Chuẩn dữ liệu realtime cho IoTLabs Cloud

Topic

iotlabs/<orgId>/devices/<deviceId>/telemetry

Payload JSON

{
  "ts": 1760000000,
  "metrics": {
    "motion": 1
  },
  "status": {
    "motion": "detected"
  }
}

Ví dụ 2 — Gửi trạng thái PIR lên IoTLabs Cloud MQTT

Logic:

  • Chỉ gửi MQTT khi trạng thái thay đổi
  • Tránh spam dữ liệu không cần thiết
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>

// ===== CONFIG =====
const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_PASS";

const char* MQTT_HOST = "mqtt.iotlabs.vn";
const int   MQTT_PORT = 8883;
const char* MQTT_USER = "YOUR_MQTT_USER";
const char* MQTT_PASS = "YOUR_MQTT_PASS";
const char* MQTT_TOPIC =
  "iotlabs/<orgId>/devices/<deviceId>/telemetry";

// ===== PIR =====
const int PIR_PIN = 2;
int lastState = LOW;

WiFiClientSecure net;
PubSubClient mqtt(net);

void connectWiFi() {
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(400);
    Serial.print(".");
  }
  Serial.println("\nWiFi connected");
}

void connectMQTT() {
  net.setInsecure(); // demo nhanh
  mqtt.setServer(MQTT_HOST, MQTT_PORT);

  while (!mqtt.connected()) {
    if (mqtt.connect("esp32c3-pir", MQTT_USER, MQTT_PASS)) {
      Serial.println("MQTT connected");
      break;
    }
    delay(1000);
  }
}

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

  connectWiFi();
  connectMQTT();
}

void loop() {
  if (!mqtt.connected()) connectMQTT();
  mqtt.loop();

  int state = digitalRead(PIR_PIN);

  if (state != lastState) {
    lastState = state;

    long ts = millis() / 1000;

    String payload = "{";
    payload += "\"ts\":" + String(ts) + ",";
    payload += "\"metrics\":{\"motion\":" + String(state) + "},";
    payload += "\"status\":{\"motion\":\"";
    payload += (state == HIGH ? "detected" : "idle");
    payload += "\"}}";

    mqtt.publish(MQTT_TOPIC, payload.c_str());

    Serial.println(payload);
  }

  delay(100);
}

6) Lỗi thường gặp & kinh nghiệm thực tế

  • PIR kích hoạt liên tục
    → Giảm sensitivity, tránh gần quạt / cửa sổ
  • Vừa cấp nguồn đã HIGH
    → PIR cần 30–60s warm-up
  • Spam MQTT
    → Chỉ gửi khi state thay đổi (đã xử lý trong code)

7) Ứng dụng thực tế

  • Đèn hành lang tự động
  • Báo có người xâm nhập
  • Kích hoạt camera / ghi log
  • Kết hợp với LDR để chỉ kích hoạt ban đêm

Bài tiếp theo (Level 1)

👉 Bài 3: Hướng dẫn đọc cảm biến Reed Switch (công tắc từ cửa) bằng ESP32: phát hiện đóng/mở cửa & theo dõi realtime