Báo trộm cảm biến chuyển động PIR, bật/tắt canh gác qua điện thoại

Phát hiện người đi vào nhà, kho, cửa hàng trong tầm 3–7m rồi hú còi và nháy đèn. Bật/tắt chế độ canh gác trên web điện thoại; mạch ghi nhật ký giờ phát hiện (giờ Việt Nam). Còi tự tắt sau thời gian cài đặt để không làm phiền hàng xóm.

⏱ 90 phút🔧 Biết hàn💰 Linh kiện ~137.200đ🧠 ESP32 DevKit V1⚡ Nguồn USB 5V

✅ Đã kiểm thử

Luật điệnKhông lỗiSai chân, chập nguồn, quá áp 5V vào chân 3,3V, thiếu đi-ốt, thiếu trở kéo…
Mô phỏng SPICE2/2 kịch bản · 11 phép đo đạtDòng/áp từng linh kiện ở trường hợp xấu nhất (ngspice)
Biên dịch codeĐạt · dùng 76% bộ nhớesp32:esp32:esp32doit-devkit-v1
Xem chi tiết 11 phép đo

Đang báo động (PIR phát hiện, còi + đèn bật)

  • Q1: dẫn 29.2mA, Vce=0.04V (bão hòa tốt).
  • D1: dòng 5.9mA (cho phép 20.0mA).
  • Chân GPIO25 cấp 5.9mA (an toàn ≤ 20.0mA).
  • Chân GPIO26 cấp 2.4mA (an toàn ≤ 20.0mA).
  • Tổng dòng đỉnh từ USB 287.7mA (đủ với cục sạc 5V 1A).
  • Áp tín hiệu PIR vào ESP32 (phải ≤ 3,3V): 3.30V ✓
  • Dòng qua còi: 29.2mA ✓
  • Dòng chân GPIO26 mở transistor: 2.4mA ✓
  • Dòng LED đỏ: 5.9mA ✓

Canh gác yên lặng

  • Tổng dòng đỉnh từ USB 250.1mA (đủ với cục sạc 5V 1A).
  • Còi tắt: 0.0mA ✓
Kiểm lần cuối: 17:07:59 12/11/2026

Nguyên lý hoạt động

Cảm biến PIR HC-SR501 nhận bức xạ hồng ngoại từ thân nhiệt người. Khi có người di chuyển trong vùng quét, chân OUT lên 3,3V (có ổn áp riêng bên trong) nên nối thẳng vào GPIO27 của ESP32 an toàn. Module được nuôi bằng 5V từ chân VIN. ESP32 phát WiFi và chạy trang web để bạn bật/tắt canh gác. Khi đang canh gác mà PIR báo, ESP32 bật còi (qua transistor S8050, còi ăn khoảng 30mA, chân GPIO chỉ cấp khoảng 2,5mA) trong thời gian cài đặt (mặc định 30 giây), và ghi lại giờ phát hiện lấy từ Internet (giờ Việt Nam UTC+7).

Sơ đồ đấu dây

Mỗi màu là một dây. Chấm tròn là điểm hàn. Chạm vào tên dây trong bảng để làm nổi bật.

⚡ Mô phỏng tương tácBấm thử — mạch được giải ngay trên máy bạn, điện áp và dòng hiện lên sơ đồ bên dưới.
Tình huống mẫu
Chân GPIO25điều khiển R2
Chân GPIO26điều khiển R1
U2 · OUTHC-SR501 xuất 3,3V khi phát hiện chuyển động, 0V khi không có.

Đây là mô phỏng một chiều (DC) ở trạng thái tĩnh: dùng để kiểm tra mức áp, dòng và công suất. Hiệu ứng nhấp nháy, PWM hay giao tiếp số do code quyết định nên không chạy ở đây.

5V5VGNDGNDPIR_OUTPIR_OUTBZ_DRVBZ_DRVBZ_BASEBZ_BASEBZ_COLBZ_COLLED_DRVLED_DRVLED_ALED_AU1 · ESP32 DevKit V1VINGPIO25 (D25)GPIO26 (D26)GPIO27 (D27)GNDR2 · Điện trở 220Ω12D1 · Đèn LED 5mmA · chân dài (+)K · chân ngắn (−)R1 · Điện trở 1kΩ12Q1 · Transistor NPN S8050B (gốc)C (góp)E (phát)U2 · Cảm biến chuyển động PIR HC-SR501VCCOUTGNDBZ1 · Còi chip chủ động 5V-+
#DâyNối các điểmÁp mô phỏng
1đỏ
5V
U1 VIN ⟷ U2 VCC ⟷ BZ1 +—
2đen
GND
U1 GND ⟷ U2 GND ⟷ Q1 E (phát) ⟷ D1 K · chân ngắn (−)—
3vàng
PIR_OUT
U2 OUT ⟷ U1 GPIO27 (D27)—
4xanh lá
BZ_DRV
U1 GPIO26 (D26) ⟷ R1 1—
5xanh dương
BZ_BASE
R1 2 ⟷ Q1 B (gốc)—
6tím
BZ_COL
BZ1 - ⟷ Q1 C (góp)—
7xanh ngọc
LED_DRV
U1 GPIO25 (D25) ⟷ R2 1—
8nâu
LED_A
R2 2 ⟷ D1 A · chân dài (+)—

Danh sách linh kiện

Ký hiệuLinh kiệnGiá tham khảo
U1ESP32 DevKit V1 30 chân (ESP32-WROOM-32)110.000đTìm mua
U2Cảm biến chuyển động PIR HC-SR501 (có 2 biến trở chỉnh tầm xa và thời gian giữ)22.000đTìm mua
Q1Transistor S8050 (TO-92)500đTìm mua
R1Điện trở 1kΩ 1/4W (nâu-đen-đỏ)200đTìm mua
BZ1Còi chip chủ động 5V (hoặc còi báo động 5V loại to)4.000đTìm mua
D1LED đỏ 5mm (red)300đTìm mua
R2Điện trở 220Ω 1/4W (đỏ-đỏ-nâu)200đTìm mua
Tổng (chưa gồm board hàn, dây, thiếc)137.200đ

Các bước làm

Code nạp cho mạch

Chọn board DOIT ESP32 DEVKIT V1.

/*
  Mạch Gọn — Báo trộm PIR, bật/tắt canh gác qua điện thoại
  Board : ESP32 DevKit V1 ("DOIT ESP32 DEVKIT V1")
  Chân  : GPIO27 <- OUT của PIR HC-SR501 (3,3V)
          GPIO26 -> R 1k -> B S8050 (còi ở cực C)
          GPIO25 -> 220Ω -> LED đỏ
  Lần đầu: WiFi "MachGon-BaoTrom" (mật khẩu machgon123) -> 192.168.4.1
*/
#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Preferences.h>
#include <time.h>

const uint8_t PIN_PIR = 27;
const uint8_t PIN_BUZ = 26;
const uint8_t PIN_LED = 25;
const char* AP_SSID  = "MachGon-BaoTrom";
const char* HOSTNAME = "baotrom";
const uint32_t PIR_WARMUP_MS = 60000;   // PIR cần ~60s ổn định sau khi cấp điện
const uint8_t  LOG_MAX = 40;

WebServer server(80);
Preferences cfg;

bool armed = false;
uint32_t armedAt = 0;          // thời điểm bấm canh gác (để tính giờ chờ ra khỏi nhà)
uint16_t sirenSec = 30;        // còi hú tối đa bao nhiêu giây mỗi lần
uint16_t exitDelaySec = 20;    // thời gian chờ sau khi bật canh gác
bool sirenOn = false;
uint32_t sirenStart = 0;
bool lastPir = false;
uint32_t eventCount = 0;

struct LogItem { time_t t; uint32_t ms; bool alarm; };
LogItem logs[LOG_MAX];
uint8_t logHead = 0, logCount = 0;

bool timeOk() { return time(nullptr) > 1700000000; }

void addLog(bool alarm) {
  logs[logHead] = { timeOk() ? time(nullptr) : 0, millis(), alarm };
  logHead = (logHead + 1) % LOG_MAX;
  if (logCount < LOG_MAX) logCount++;
}

String fmtLog(const LogItem& l) {
  char b[40];
  if (l.t) { struct tm tmv; localtime_r(&l.t, &tmv); strftime(b, sizeof b, "%d/%m %H:%M:%S", &tmv); }
  else snprintf(b, sizeof b, "+%lus sau khi bật", (unsigned long)(l.ms / 1000));
  return String(b);
}

bool active() { return armed && millis() - armedAt >= exitDelaySec * 1000UL && millis() > PIR_WARMUP_MS; }

void setSiren(bool on) {
  sirenOn = on;
  if (on) sirenStart = millis();
  else digitalWrite(PIN_BUZ, LOW);
}

const char PAGE[] PROGMEM = R"HTML(<!doctype html><html lang="vi"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1"><title>Báo trộm</title>
<style>
body{margin:0;font-family:system-ui,sans-serif;background:#0f172a;color:#e2e8f0}
header{padding:14px;background:#1e293b;font-weight:700}
.card{margin:14px;padding:14px;background:#1e293b;border-radius:14px}
.big{width:100%;padding:22px;font-size:20px;border:0;border-radius:14px;font-weight:700}
.on{background:#dc2626;color:#fff}.off{background:#22c55e;color:#052e16}
.st{font-size:18px;margin-bottom:10px}.muted{color:#94a3b8;font-size:13px}
ul{list-style:none;padding:0;margin:0}li{padding:8px 0;border-bottom:1px solid #334155}
li.a{color:#fca5a5}input{width:100%;padding:9px;margin:4px 0 8px;border-radius:8px;border:1px solid #475569;background:#0b1220;color:#e2e8f0;box-sizing:border-box}
.btn{background:#334155;color:#e2e8f0;border:0;border-radius:10px;padding:10px 14px;margin-top:6px}
</style></head><body>
<header>🛡️ Báo trộm</header>
<div class="card"><div class="st" id="st">…</div><button class="big" id="arm"></button>
<button class="btn" id="mute" style="width:100%;margin-top:10px">🔕 Tắt còi ngay</button>
<p class="muted" id="info"></p></div>
<div class="card"><b>Nhật ký phát hiện</b><ul id="log"></ul></div>
<div class="card"><b>Cài đặt</b>
<label class="muted">Còi hú tối đa (giây)</label><input id="siren" type="number" min="3" max="600">
<label class="muted">Chờ ra khỏi nhà sau khi bật canh gác (giây)</label><input id="exit" type="number" min="0" max="300">
<button class="btn" onclick="saveOpt()">Lưu</button><hr style="border-color:#334155">
<label class="muted">WiFi nhà (để có giờ chính xác)</label><input id="ssid" placeholder="Tên WiFi"><input id="pass" type="password" placeholder="Mật khẩu">
<button class="btn" onclick="wifi()">Lưu WiFi & khởi động lại</button></div>
<script>
const $=s=>document.querySelector(s);let S={};
async function load(){const r=await fetch('/api/state');S=await r.json();
 $('#st').textContent=S.siren?'🚨 ĐANG BÁO ĐỘNG':S.armed?(S.active?'🔒 Đang canh gác':'⏳ Sắp canh gác…'):'🔓 Đã tắt canh gác';
 $('#arm').textContent=S.armed?'TẮT CANH GÁC':'BẬT CANH GÁC';$('#arm').className='big '+(S.armed?'off':'on');
 $('#info').textContent=(S.sta?'Đã nối WiFi nhà, IP '+S.ip+' — http://baotrom.local':'Chưa nối WiFi nhà')+(S.warm?'':' · PIR đang khởi động')+' · PIR hiện tại: '+(S.pir?'CÓ chuyển động':'yên');
 $('#log').innerHTML=S.log.map(l=>`<li class="${l.a?'a':''}">${l.a?'🚨':'👣'} ${l.t} — ${l.a?'Báo động':'Có chuyển động'}</li>`).join('')||'<li class="muted">Chưa có</li>';
 if(document.activeElement.tagName!='INPUT'){$('#siren').value=S.sirenSec;$('#exit').value=S.exitSec}}
$('#arm').onclick=async()=>{await fetch('/api/arm?on='+(S.armed?0:1),{method:'POST'});load()};
$('#mute').onclick=async()=>{await fetch('/api/mute',{method:'POST'});load()};
async function saveOpt(){await fetch('/api/opt?siren='+$('#siren').value+'&exit='+$('#exit').value,{method:'POST'});load()}
async function wifi(){await fetch('/api/wifi',{method:'POST',body:new URLSearchParams({ssid:$('#ssid').value,pass:$('#pass').value})});alert('Đã lưu, mạch khởi động lại')}
load();setInterval(load,2000);
</script></body></html>)HTML";

void handleState() {
  bool sta = WiFi.status() == WL_CONNECTED;
  String j = "{\"armed\":" + String(armed ? "true" : "false") + ",\"active\":" + (active() ? "true" : "false") +
             ",\"siren\":" + (sirenOn ? "true" : "false") + ",\"pir\":" + (lastPir ? "true" : "false") +
             ",\"warm\":" + (millis() > PIR_WARMUP_MS ? "true" : "false") + ",\"sta\":" + (sta ? "true" : "false") +
             ",\"ip\":\"" + (sta ? WiFi.localIP().toString() : WiFi.softAPIP().toString()) + "\",\"sirenSec\":" + sirenSec +
             ",\"exitSec\":" + exitDelaySec + ",\"log\":[";
  for (uint8_t i = 0; i < logCount; i++) {
    const LogItem& l = logs[(logHead + LOG_MAX - 1 - i) % LOG_MAX];
    if (i) j += ',';
    j += "{\"t\":\"" + fmtLog(l) + "\",\"a\":" + (l.alarm ? "true" : "false") + "}";
  }
  j += "]}";
  server.send(200, "application/json", j);
}

void setupWeb() {
  server.on("/", []() { server.send_P(200, "text/html; charset=utf-8", PAGE); });
  server.on("/api/state", HTTP_GET, handleState);
  server.on("/api/arm", HTTP_POST, []() {
    armed = server.arg("on") == "1"; armedAt = millis(); cfg.putBool("armed", armed);
    if (!armed) setSiren(false);
    digitalWrite(PIN_BUZ, HIGH); delay(armed ? 60 : 200); digitalWrite(PIN_BUZ, LOW);  // bíp xác nhận
    server.send(200, "text/plain", "ok");
  });
  server.on("/api/mute", HTTP_POST, []() { setSiren(false); server.send(200, "text/plain", "ok"); });
  server.on("/api/opt", HTTP_POST, []() {
    sirenSec = constrain(server.arg("siren").toInt(), 3, 600);
    exitDelaySec = constrain(server.arg("exit").toInt(), 0, 300);
    cfg.putUShort("siren", sirenSec); cfg.putUShort("exit", exitDelaySec);
    server.send(200, "text/plain", "ok");
  });
  server.on("/api/wifi", HTTP_POST, []() {
    cfg.putString("ssid", server.arg("ssid")); cfg.putString("pass", server.arg("pass"));
    server.send(200, "text/plain", "ok"); delay(500); ESP.restart();
  });
  server.onNotFound([]() { server.sendHeader("Location", "/"); server.send(302); });
  server.begin();
}

void setup() {
  Serial.begin(115200);
  pinMode(PIN_PIR, INPUT);
  pinMode(PIN_BUZ, OUTPUT);
  pinMode(PIN_LED, OUTPUT);
  digitalWrite(PIN_BUZ, LOW);
  cfg.begin("cfg", false);
  armed = cfg.getBool("armed", false);   // mất điện có lại vẫn giữ trạng thái canh gác
  sirenSec = cfg.getUShort("siren", 30);
  exitDelaySec = cfg.getUShort("exit", 20);
  armedAt = millis();

  WiFi.mode(WIFI_AP_STA);
  WiFi.softAP(AP_SSID, cfg.getString("appass", "machgon123").c_str());
  String ssid = cfg.getString("ssid", "");
  if (ssid.length()) {
    WiFi.begin(ssid.c_str(), cfg.getString("pass", "").c_str());
    uint32_t t = millis();
    while (WiFi.status() != WL_CONNECTED && millis() - t < 15000) delay(250);
  }
  configTime(7 * 3600, 0, "pool.ntp.org", "time.google.com");  // giờ Việt Nam UTC+7
  if (MDNS.begin(HOSTNAME)) MDNS.addService("http", "tcp", 80);
  setupWeb();
  Serial.printf("San sang. AP %s IP %s\n", AP_SSID, WiFi.softAPIP().toString().c_str());
}

void loop() {
  server.handleClient();
  uint32_t now = millis();

  bool pir = digitalRead(PIN_PIR) == HIGH;
  if (pir && !lastPir && now > PIR_WARMUP_MS) {
    eventCount++;
    bool alarm = active();
    addLog(alarm);
    Serial.printf("PIR=1 (%s)\n", alarm ? "BAO DONG" : "chi ghi nhat ky");
    if (alarm) setSiren(true);
  }
  lastPir = pir;

  // còi hú ngắt quãng, tự tắt sau sirenSec
  if (sirenOn) {
    digitalWrite(PIN_BUZ, (now / 250) % 2);
    if (now - sirenStart >= sirenSec * 1000UL) setSiren(false);
  }
  // đèn: nháy nhanh khi báo động, nháy chậm khi chờ canh gác, sáng mờ chớp 1 lần/3s khi canh gác
  if (sirenOn) digitalWrite(PIN_LED, (now / 150) % 2);
  else if (armed && !active()) digitalWrite(PIN_LED, (now / 500) % 2);
  else if (armed) digitalWrite(PIN_LED, (now % 3000) < 80);
  else digitalWrite(PIN_LED, LOW);

  static uint32_t lastCheck = 0;
  if (now - lastCheck > 30000) {
    lastCheck = now;
    if (cfg.getString("ssid", "").length() && WiFi.status() != WL_CONNECTED) WiFi.reconnect();
  }
  delay(5);
}

🔌 Cắm thử trên breadboard

Cắm nháp trên board cắm trước cho chắc, chạy đúng rồi hãy làm mạch in. Sơ đồ này do máy tự xếp từ chính netlist ở trên và đã đối chiếu lại: hai chân cùng một cột (cùng nửa board) là thông nhau, không có net nào bị chập.

+−+−5510101515202025253030JIHGFEDCBAU1 · ESP32 DevKit V1 (30 chân)252627GNDVINU2Q1 S8050R1 1kBZ1+D1 redR2 220
  • Mỗi cột 5 lỗ trong cùng một nửa board thông nhau; hai nửa cách nhau bởi rãnh giữa.
  • Hai đường kẻ dọc mép board là đường nguồn: hàng + (vạch đỏ) và hàng − (vạch xanh). Nhớ bắc dây nối đường nguồn trên với đường nguồn dưới nếu dùng cả hai nửa.
  • Màu dây trên hình trùng với màu trong bảng nối dây ở mục Sơ đồ, cắm theo màu cho dễ dò.

🧲 Mạch in để ủi (PCB 1 mặt)

Bản mạch in một mặt đồng, tự xếp linh kiện và tự đi dây, đã kiểm quy tắc khoảng cách và đối chiếu đúng 100% với sơ đồ nguyên lý ở trên. In tỉ lệ 1:1 rồi ủi lên tấm đồng.

Kích thước board63,5×66,0 mm44 lỗ khoan · mũi 0,8 / 0,9 / 1mm
Đi dây 1 mặt11 đoạn · 539,7 mmKhông cần cầu nhảy nào
Kiểm tra bản mạchĐạt DRC · khớp 100% netlistĐường ≥0,8mm, khe ≥0,5mm; mọi net đối chiếu lại từ hình học thật
Mặt đồng — đã lật gương sẵn để in rồi ủi úp xuống tấm đồng
Mặt linh kiện — vị trí, chiều cắm và tên từng chân
U1U2Q1R1BZ1D1R2EN363934353233252627141213GNDVIN232213211918517164215GND23V3VCCOUTGND
Hướng dẫn ủi – ăn mòn – khoan – hàn (đầy đủ)

Hướng dẫn làm mạch in bằng phương pháp ủi

Mạch: Báo trộm cảm biến chuyển động PIR, bật/tắt canh gác qua điện thoại

Kích thước board: 63,5×66,0 mm · 44 lỗ khoan (mũi 0,8, 0,9 và 1 mm) · 11 đoạn mạch, tổng 539,7 mm · 0 cầu nhảy.

Quy tắc đã kiểm: đường mạch rộng 0,8mm (nguồn và GND 1mm), khe cách tối thiểu 0,5mm. Mạch in đã được máy đối chiếu đúng 100% với sơ đồ nguyên lý.

1. In đúng tỉ lệ 1:1

  • In trang "MẶT ĐỒNG" bằng máy in LASER, đặt tỉ lệ 100%, KHÔNG chọn "Fit to page" hay "Scale to fit".
  • Dùng thước trên bản in đo lại đoạn 100mm: phải đúng 100mm mới dùng được.
  • In trên giấy in ảnh bóng, giấy decal bóc, hoặc giấy tạp chí láng. Mực càng dày càng tốt.
  • Trang "MẶT ĐỒNG" đã được LẬT GƯƠNG sẵn: úp mặt có mực vào tấm đồng là đúng chiều.

2. Chuẩn bị tấm đồng

  • Cắt phíp đồng (board đồng một mặt) lớn hơn kích thước mạch mỗi bề khoảng 5mm.
  • Chà mặt đồng bằng giấy nhám mịn (P800–P1200) rồi rửa sạch, lau khô. Mặt đồng phải sáng, không vết dầu mỡ, không chạm tay vào.

3. Ủi mực sang đồng

  • Úp mặt có mực vào tấm đồng, dùng băng keo giấy dán cố định một cạnh.
  • Bàn ủi để mức nóng nhất (cotton/linen), KHÔNG dùng chế độ phun hơi nước.
  • Ủi đè mạnh và đều 3–5 phút, tập trung từng vùng nhỏ, chú ý các góc và mép.
  • Để nguội hẳn rồi ngâm cả tấm vào nước ấm 5–10 phút, bóc giấy thật nhẹ. Giấy decal thì bóc khi còn ấm.
  • Soi kỹ: chỗ nào mực bị thiếu hoặc đứt đường thì tô lại bằng bút lông dầu (bút CD) rồi để khô.

4. Ăn mòn (etching)

  • Pha dung dịch sắt(III) clorua FeCl3 theo hướng dẫn trên bao bì, hoặc dung dịch oxy già + muối ăn + a-xít; dùng hộp nhựa, KHÔNG dùng đồ kim loại.
  • Nhiệt độ dung dịch khoảng 40–50°C thì ăn nhanh hơn. Lắc nhẹ hộp cho đều, thường 10–25 phút là xong.
  • An toàn: đeo găng tay cao su và kính bảo hộ, làm ở nơi thoáng. Dung dịch ăn mòn làm hỏng quần áo, bồn rửa và gây bỏng rát da.
  • Xong thì rửa board bằng nước sạch, lau khô, dùng xăng thơm hoặc axeton lau sạch lớp mực.
  • Dung dịch đã dùng KHÔNG đổ xuống bồn rửa hay cống; đựng vào can kín và bỏ đúng nơi thu gom chất thải.

5. Khoan lỗ

  • Đối chiếu trang "BẢN VẼ LỖ KHOAN" để biết lỗ nào dùng mũi nào.
  • Dùng mũi khoan 0,8mm, 0,9mm và 1mm, khoan từ MẶT ĐỒNG vào để mũi tự định tâm giữa pad.
  • Khoan tốc độ cao, đẩy nhẹ; mũi nhỏ rất dễ gãy. Khoan xong chà nhẹ bavia hai mặt.

6. Hàn linh kiện

  • Linh kiện cắm ở MẶT KHÔNG CÓ ĐỒNG, hàn ở mặt đồng. Theo trang "MẶT LINH KIỆN" để đặt đúng vị trí và đúng chiều.
  • Hàn linh kiện thấp trước (điện trở, đi-ốt), cao sau (tụ, hàng chân, board vi điều khiển).
  • Chú ý chiều: LED chân dài là (+); đi-ốt có vạch trắng là K; tụ hoá có vạch là (−); transistor theo mặt chữ như nét vẽ đỏ.
  • Trước khi cấp điện: đo thông mạch giữa chân nguồn và GND — KHÔNG được kêu (không được chập).

Lưu ý với board vi điều khiển

  • Board nhái có thể khác thứ tự chân. Đối chiếu tên chân in cạnh từng lỗ trên trang "MẶT LINH KIỆN" với chữ in trên board thật TRƯỚC KHI ăn mòn. Nếu khác, đừng hàn mà báo lại để sửa bản vẽ.
Bản vẽ lỗ khoan
BẢN VẼ LỖ KHOAN (nhìn từ mặt linh kiện)mũi khoan 0,8mm — 7 lỗmũi khoan 0,9mm — 4 lỗmũi khoan 1mm — 33 lỗ

Đo kiểm bằng đồng hồ vạn năng

Giữa VCC và GND của PIR4,6 – 5,1V
Giữa OUT và GND khi vẫy tay trước PIRkhoảng 3,3V, đứng yên vài giây về 0V
Trang web khi vẫy tayDòng "Có chuyển động" mới trong nhật ký
Giữa C và E của S8050 khi còi tắtkhoảng 3V trở lên

Sửa lỗi thường gặp

Báo động liên tục dù không có ai

Đợi 60 giây sau khi cấp điện; giảm tầm xa (Sx); đổi hướng tránh luồng gió máy lạnh, rèm bay, nắng chiếu. Dây PIR dài trên 3m nên dùng dây có chống nhiễu.

Không phát hiện được

Kiểm tra PIR được cấp 5V (không phải 3V3), jumper ở H; xem dòng "PIR=1" trên Serial Monitor 115200 khi vẫy tay.

Giờ trong nhật ký sai hoặc là "--"

Mạch chưa vào được Internet: nhập WiFi nhà ở trang Cài đặt. Khi chưa có giờ, nhật ký ghi số giây kể từ lúc bật.

Còi không kêu

Kiểm tra là còi chủ động (cấp 5V trực tiếp phải kêu), chiều + của còi và chân E-B-C.

⚠️ An toàn

  • Mạch dùng 5V USB, an toàn khi chạm.
  • Nên cắm qua cục sạc dự phòng nếu muốn còn chạy khi mất điện.
  • Đây là mạch tham khảo, không thay thế hệ thống an ninh chuyên nghiệp.