IoTLabs

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

Series 37 Module Cảm Biến – Nguyên Lý Tilt Switch SW-520D: Bi Kim Loại Dẫn Điện, Phát Hiện Nghiêng & Báo Động

Tilt switch là công nghệ cảm biến thô nhất trong bộ kit — không có IC, không có điện tử: chỉ là ống kim loại nhỏ chứa bi dẫn điện. Đơn giản nhưng hoạt động cực kỳ đáng tin cậy cho các ứng dụng phát hiện nghiêng/lật.

Nguyên Lý Hoạt Động

1. Cơ Chế Bi Kim Loại Dẫn Điện

SW-520D là ống trụ kim loại nhỏ (~6mm × 12mm) với 2 đầu dây ở một đầu:

SW-520D — Cắt dọc:

                 Đầu tiếp điểm
              ┌──┴──┐
Bi 1  ○─────→│ ⊙ ⊙ │← 2 chân
Bi 2  ○      │     │
              └─────┘
            ống kim loại
            
Khi ĐẦU TIẾP ĐIỂM XUỐNG DƯỚI:
  ○ ○     ← bi lăn về phía tiếp điểm
  │ │
  ⊙ ⊙     ← bi tiếp xúc 2 chân → mạch ĐÓNG → điện thông

Khi ĐẦU TIẾP ĐIỂM LÊN TRÊN:
        ○ ○  ← bi lăn ra xa
  ⊙ ⊙      ← không tiếp xúc → mạch HỞ → điện không thông

2. Tác Động Của Trọng Lực

Hành vi phụ thuộc hoàn toàn vào trọng lực và định hướng lắp:

Góc nghiêng so với mặt nằm ngang:

  45°+  ─────────────────────────── Bi tiếp xúc tiếp điểm (ĐÓNG)
        ← Vùng "đóng" phụ thuộc
  -45°    vào định hướng lắp
        ─────────────────────────── Bi rời tiếp điểm (HỞ)
  -45°−

Không có ngưỡng góc chính xác — SW-520D không đo góc mà chỉ phát hiện có lật hay không dựa trên lực trọng trường đủ để bi lăn.

3. So Sánh Với Các Tilt Sensor Khác

SW-520D (bi lăn)MPU-6050 (gyro/accel)Mercury switch
Độ chính xác gócKhông đo được0.1°Không đo được
Đo 3 trụcKhôngKhông
Phức tạpRất đơn giảnI2C, libraryĐơn giản
An toànAn toànAn toànThủy ngân độc
RungBounce nhiềuKhôngBounce
Dùng khi nàoPhát hiện lật đơn giảnĐo góc chính xácLỗi thời

Thông Số Kỹ Thuật

Thông sốGiá trị
Điện áp tối đa12V
Dòng tối đa30mA
Điện trở tiếp xúc<1Ω (khi đóng)
Kích thước~6mm × 12mm
Nhiệt độ hoạt động-10°C đến 70°C
Output loạiDigital (ON/OFF)

Sơ Đồ Chân (Pinout)

Module KY-020 (trong kit 37 module)

KY-020 — Nhìn từ mặt trước:

┌──────────────────────────────┐
│   [SW-520D]                  │
│   [Điện trở pull-up 10kΩ]    │
│   [LED trạng thái]           │
└──────────────────────────────┘
   GND   VCC   S
   (-)  (3.3-5V) (Signal OUT)
ChânKý hiệuMô tả
GNDMass
VCC+Nguồn 3.3V-5V
SSignalOutput — LOW khi mạch đóng (bi tiếp xúc)

Logic output (với pull-up trên module):

  • Module thẳng đứng (đầu tiếp điểm xuống): S = LOW (bi đóng mạch)
  • Module nghiêng/lật (bi rời xa tiếp điểm): S = HIGH

Tùy hướng lắp module, logic có thể ngược. Kiểm tra thực tế với Serial Monitor trước khi code.

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

KY-020 với ESP32 DevKit V1

ESP32 DevKit V1           KY-020 Module
─────────────────────     ─────────────────
3V3  ─────────────────→  VCC
GND  ─────────────────→  GND
GPIO4 (Input) ─────────→  S    (Signal)

GPIO4: input-capable, không phải strapping pin.

Định hướng lắp: Module thường lắp dọc với 3 chân kết nối ở dưới. Kiểm tra logic trước khi dùng trong ứng dụng.

KY-020 với Arduino Uno

Arduino Uno               KY-020 Module
─────────────────────     ─────────────────
5V   ─────────────────→  VCC
GND  ─────────────────→  GND
Pin 2 (Input_PU)──────→  S    ← Pin 2: hỗ trợ interrupt

Code Arduino IDE

Code Đọc Trạng Thái Cơ Bản — Arduino Uno

/*
 * Tilt Switch SW-520D — Đọc trạng thái nghiêng cơ bản
 * Board: Arduino Uno
 * Kết nối: VCC→5V, GND→GND, S→Pin2
 *
 * Module có pull-up → khi bi tiếp xúc: S = LOW
 * Kiểm tra thực tế để xác định logic đúng
 */

const int TILT_PIN = 2;
const int LED_PIN  = 13;

void setup() {
  Serial.begin(9600);
  pinMode(TILT_PIN, INPUT); // Module đã có pull-up
  pinMode(LED_PIN, OUTPUT);
  Serial.println("=== Tilt Switch SW-520D ===");
  Serial.println("Xoay module để kiểm tra logic HIGH/LOW");
}

int lastState = -1; // Lưu trạng thái trước để phát hiện thay đổi

void loop() {
  int tiltVal = digitalRead(TILT_PIN);

  // Chỉ in khi có thay đổi (không spam Serial)
  if (tiltVal != lastState) {
    lastState = tiltVal;

    if (tiltVal == LOW) {
      Serial.println("LOW → Bi tiếp xúc (mạch ĐÓNG) — module ở hướng này");
      digitalWrite(LED_PIN, HIGH);
    } else {
      Serial.println("HIGH → Bi không tiếp xúc (mạch HỞ)");
      digitalWrite(LED_PIN, LOW);
    }
  }

  delay(20); // Nhỏ debounce
}

Code Phát Hiện Lật — Đếm Flip Count (Arduino Uno)

/*
 * Tilt Switch — Đếm số lần lật (flip counter)
 * Board: Arduino Uno
 * Kết nối: VCC→5V, GND→GND, S→Pin2
 *
 * Dùng interrupt để đếm chính xác, không bỏ sót
 */

const int TILT_PIN = 2;
const int LED_PIN  = 13;

volatile int flipCount = 0;        // Tổng số lần thay đổi trạng thái
volatile bool tiltChanged = false; // Cờ báo có thay đổi

// Định nghĩa trạng thái logic (điều chỉnh theo module thực tế)
// LOW = "bình thường", HIGH = "nghiêng" — hoặc ngược lại
#define TILTED_STATE HIGH

void onTiltChange() {
  flipCount++;
  tiltChanged = true;
}

void setup() {
  Serial.begin(9600);
  pinMode(TILT_PIN, INPUT);
  pinMode(LED_PIN, OUTPUT);

  // Trigger trên cả 2 chiều (CHANGE): mỗi lần bi lăn = 1 event
  attachInterrupt(digitalPinToInterrupt(TILT_PIN), onTiltChange, CHANGE);

  Serial.println("=== Flip Counter ===");
  Serial.println("Flips: 0");
}

void loop() {
  if (tiltChanged) {
    tiltChanged = false;

    int currentState = digitalRead(TILT_PIN);
    bool isTilted = (currentState == TILTED_STATE);

    digitalWrite(LED_PIN, isTilted ? HIGH : LOW);

    Serial.print("Flip #");
    Serial.print(flipCount);
    Serial.print(" — ");
    Serial.println(isTilted ? "NGHIÊNG" : "THẲNG");
  }
}

Code Anti-Theft Alarm — Báo Động Khi Bị Di Chuyển (Arduino Uno)

/*
 * Tilt Switch — Báo động anti-theft: báo khi thiết bị bị di chuyển
 * Board: Arduino Uno
 * Kết nối: VCC→5V, GND→GND, S→Pin2, Buzzer→Pin9
 *
 * Cách dùng:
 * 1. Đặt thiết bị ở vị trí muốn bảo vệ
 * 2. Nhấn Reset → 5 giây "cài đặt" (arm)
 * 3. Ai di chuyển thiết bị → buzzer kêu
 */

const int TILT_PIN   = 2;
const int BUZZER_PIN = 9;
const int LED_PIN    = 13;
const int ARM_DELAY  = 5000; // 5 giây để đặt thiết bị xuống

volatile bool alarmTriggered = false;
bool armed = false;
int baselineState = LOW; // Trạng thái "bình thường" sau khi arm

void onTiltChange() {
  if (armed) {
    int currentState = digitalRead(TILT_PIN);
    if (currentState != baselineState) {
      alarmTriggered = true;
    }
  }
}

void setup() {
  Serial.begin(9600);
  pinMode(TILT_PIN, INPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(BUZZER_PIN, LOW);

  attachInterrupt(digitalPinToInterrupt(TILT_PIN), onTiltChange, CHANGE);

  Serial.println("=== Anti-Theft Alarm ===");
  Serial.println("Đặt thiết bị xuống, chờ 5 giây...");

  // Blink LED trong lúc đếm ngược
  for (int i = 5; i > 0; i--) {
    Serial.print(i); Serial.print("...");
    digitalWrite(LED_PIN, HIGH); delay(500);
    digitalWrite(LED_PIN, LOW);  delay(500);
  }

  // Ghi lại trạng thái baseline
  baselineState = digitalRead(TILT_PIN);
  armed = true;
  digitalWrite(LED_PIN, HIGH); // LED luôn sáng = đang armed

  Serial.println("\nBÁO ĐỘNG ĐÃ BẬT! (armed)");
  Serial.println("Di chuyển thiết bị sẽ kích hoạt báo động");
}

void loop() {
  if (alarmTriggered) {
    Serial.println("!!! BÁO ĐỘNG - Thiết bị bị di chuyển !!!");

    // Kêu còi liên tục 10 giây
    unsigned long alarmStart = millis();
    while (millis() - alarmStart < 10000) {
      digitalWrite(BUZZER_PIN, HIGH); delay(200);
      digitalWrite(BUZZER_PIN, LOW);  delay(200);
      digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Blink nhanh
    }

    // Reset alarm (để arm lại cần nhấn Reset)
    alarmTriggered = false;
    armed = false;
    Serial.println("Alarm reset. Nhấn Reset để arm lại.");
  }
}

Code ESP32 — Tilt Detection Non-Blocking

/*
 * Tilt Switch KY-020 — ESP32, phát hiện nghiêng non-blocking
 * Board: ESP32 DevKit V1
 * Kết nối: VCC→3V3, GND→GND, S→GPIO4
 */

const int TILT_PIN = 4;
const int LED_PIN  = 5;

volatile bool tiltState = false;
volatile bool stateChanged = false;
unsigned long lastChangeTime = 0;
const unsigned long DEBOUNCE_MS = 50; // Debounce bi lăn

void IRAM_ATTR onTiltISR() {
  // Debounce trong ISR (đơn giản — không dùng millis() trong ISR)
  stateChanged = true;
  tiltState = (digitalRead(TILT_PIN) == LOW); // LOW = bi tiếp xúc
}

void setup() {
  Serial.begin(115200);
  pinMode(TILT_PIN, INPUT);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);

  attachInterrupt(digitalPinToInterrupt(TILT_PIN), onTiltISR, CHANGE);

  Serial.println("=== Tilt Switch ESP32 ===");
}

void loop() {
  if (stateChanged) {
    unsigned long now = millis();
    if (now - lastChangeTime > DEBOUNCE_MS) {
      lastChangeTime = now;
      stateChanged = false;

      if (tiltState) {
        Serial.println("Module nằm — bi tiếp xúc (LOW)");
        digitalWrite(LED_PIN, HIGH);
      } else {
        Serial.println("Module đứng hoặc nghiêng — bi không tiếp xúc (HIGH)");
        digitalWrite(LED_PIN, LOW);
      }
    }
  }
}

Kết Quả Mong Đợi

=== Tilt Switch SW-520D ===
Xoay module để kiểm tra logic HIGH/LOW
LOW → Bi tiếp xúc (mạch ĐÓNG) — module ở hướng này
HIGH → Bi không tiếp xúc (mạch HỞ)
LOW → Bi tiếp xúc (mạch ĐÓNG) — module ở hướng này

Ứng Dụng Thực Tế

Ứng dụngChi tiết
Báo động anti-theftKêu còi khi thiết bị bị di chuyển
Phát hiện ngã (fall detection)Robot ngã → đứng lại
Đèn tự động khi mở nắpMở nắp hộp → đèn sáng
Đếm số lần lật containerLogistics: đếm số lần xử lý
Công tắc vị trí cơ họcArm/disarm theo vị trí đặt

Lưu Ý Khi Sử Dụng

1. Bounce (rung tiếp điểm) rất nhiều

Bi kim loại rung khi lăn → tạo ra hàng chục tín hiệu giả. Debounce ~50ms là minimum. Dùng CHANGE interrupt + bộ lọc thời gian, không dùng delay() trong ISR.

2. Kiểm tra logic thực tế

Logic HIGH/LOW phụ thuộc vào hướng lắp module. Luôn kiểm tra với Serial Monitor trước khi code ứng dụng. Không giả định trước.

3. Không đo được góc

SW-520D chỉ cho biết “lật hay không” — không biết góc nghiêng. Cần đo góc → dùng MPU-6050 (Bài 30) hoặc ADXL345.

4. Rung cơ học gây false trigger

Đặt thiết bị trên bề mặt rung (xe, máy móc) → tilt switch kích hoạt liên tục. Giải pháp: tăng debounce, hoặc cần nhiều lần trigger liên tiếp mới tính là sự kiện thật.

Bài tiếp theo: