Trang Tổng Quan / Tuần 4: Cảm Biến Siêu Âm, Quang Trở & Còi Báo
Tuần 4 Note chính thức: w4-10-10.md • 10/10/2026

CẢM BIẾN SIÊU ÂM (HC-SR04), QUANG TRỞ (LDR) & CÒI BÁO (BUZZER)

Nội dung thực hành chuyên sâu Tuần 4: Đo khoảng cách không tiếp xúc bằng sóng siêu âm (nguyên lý phản xạ âm, chân Trig/Echo, vận tốc 0.034 cm/µs, hàm pulseIn), nhận biết cường độ ánh sáng bằng quang trở Photoresistor (đặc tính điện trở nghịch biến, tín hiệu Digital D0 & Analog A0), phát âm thanh cảnh báo và nhạc giai điệu bằng còi chip áp điện Piezo Buzzer, mini project thực tế Đèn học thông minh đa chức năng và trọn bộ 12 câu hỏi trắc nghiệm/tự luận có đáp án chi tiết.

Mục 1.6

Cảm Biến Sóng Siêu Âm (Ultrasonic Sensor HC-SR04)

Khoảng cách: 2cm → 400cm
Hình ảnh linh kiện: Cảm biến siêu âm HC-SR04 (Mắt phát T & Mắt thu R)
Cảm biến siêu âm HC-SR04

Hình 1: Hai loa siêu âm gắn chữ T (Transmitter - phát chùm sóng âm 40kHz) và R (Receiver - thu nhận sóng dội lại từ vật cản).

• Chức năng 4 chân cắm của HC-SR04:
Tên chân Điện áp / Tín hiệu Chế độ pinMode Chức năng & Nguyên lý hoạt động
VCC 5V DC Nguồn Cấp nguồn dương 5V ổn định cho module cảm biến hoạt động.
GND 0V Nối đất Nối về chân cực âm GND chung của Arduino UNO.
Trig (Trigger) Digital Output pinMode(trigPin, OUTPUT); Nhận xung kích phát từ Arduino (kéo HIGH tối thiểu 10 microsecond). Cảm biến sẽ tự động phát ra 8 chu kỳ xung sóng siêu âm ở tần số 40 kHz.
Echo Digital Input pinMode(echoPin, INPUT); Chân trả về thời gian. Ngay khi phát sóng, chân Echo chuyển lên mức HIGH. Khi nhận được sóng dội về từ vật cản, chân Echo lập tức rớt về LOW.
Nguyên Lý Vật Lý & Công Thức Tính Khoảng Cách
  • Vận tốc truyền sóng âm trong không khí: v = 340 m/s = 0.034 cm/microsecond (µs) (tương đương 1 cm mất 29.41 µs).
  • Thời gian đo được bởi hàm pulseIn: Là tổng thời gian sóng âm di chuyển 2 chiều (từ cảm biến phát tới vật cản + dội ngược trở lại).
  • Công thức suy ra khoảng cách d (cm):
    Khoảng cách (cm) = (Thời gian duration [µs] × 0.034) / 2 = duration / 58.8
  • Ví dụ: Nếu thời gian đo được là 1 millisecond = 1000 µs thì: d = (1000 × 0.034) / 2 = 17 cm.

• Đoạn mã chuẩn kích phát xung Trig và đọc thời gian Echo:

const int trigPin = 9;
const int echoPin = 10;

void setup() {
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  Serial.begin(9600);
}

void loop() {
  // 1. Kích hoạt chân Trig bằng xung HIGH kéo dài chính xác 10 microseconds
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  // 2. Đo thời gian chân Echo duy trì ở trạng thái HIGH (đơn vị: microsecond)
  unsigned long duration = pulseIn(echoPin, HIGH);

  // 3. Tính khoảng cách ra centimet (cm)
  float distance = (duration * 0.034) / 2.0;

  // 4. In ra Serial Monitor
  Serial.print("Khoang cach: ");
  Serial.print(distance);
  Serial.println(" cm");

  delay(100); // Tạm dừng 100ms giữa các lần đo
}
Bài Tập 1 Cảm biến lùi xe: Khoảng cách vật cản càng gần thì đèn LED nhấp nháy càng nhanh!

Ý tưởng: Dùng hàm map(distance, 5, 50, 50, 600) để chuyển đổi khoảng cách đo được (từ 5cm đến 50cm) sang chu kỳ chớp tắt (từ 50ms rất nhanh đến 600ms chớp chậm).

const int trigPin = 9;
const int echoPin = 10;
const int ledPin = 13;

void setup() {
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  unsigned long duration = pulseIn(echoPin, HIGH);
  int distance = (duration * 0.034) / 2;

  // Giới hạn dải khoảng cách từ 5cm đến 50cm
  if (distance >= 5 && distance <= 50) {
    int blinkSpeed = map(distance, 5, 50, 50, 600); // Gần: delay 50ms, Xa: delay 600ms
    digitalWrite(ledPin, HIGH);
    delay(blinkSpeed);
    digitalWrite(ledPin, LOW);
    delay(blinkSpeed);
  } else if (distance < 5) {
    digitalWrite(ledPin, HIGH); // Quá gần nguy hiểm: LED sáng liên tục
  } else {
    digitalWrite(ledPin, LOW);  // Quá xa: Tắt LED
    delay(100);
  }
}
Mục 1.7

Cảm Biến Quang Trở (Photoresistor Sensor / LDR)

Quang điện trở CdS
Hình ảnh linh kiện: Module cảm biến ánh sáng Quang trở 4 chân (LM393)
Module cảm biến quang trở LDR

Hình 2: Module quang trở tích hợp IC so sánh điện áp LM393, chiết áp biến trở xoay màu xanh tinh chỉnh ngưỡng sáng và 4 chân giao tiếp (VCC, GND, D0, A0).

• Mối quan hệ giữa ánh sáng & điện trở:
  • Linh kiện quang trở (Light Dependent Resistor - LDR) được chế tạo từ vật liệu bán dẫn Cadmium Sulfide (CdS).
  • Điện trở của quang trở có mối quan hệ TỶ LỆ NGHỊCH với cường độ ánh sáng chiếu vào:
    • Trời càng sáng: Photon giải phóng nhiều electron tự do → Điện trở giảm mạnh (còn vài trăm Ω).
    • Trời càng tối: Ít hạt mang điện → Điện trở tăng cực đại (hàng trăm kΩ đến hàng MΩ).
• Chức năng 4 chân của module LDR:
  • VCC: Nối nguồn dương 5V DC.
  • GND: Nối về cực âm GND chung.
  • D0 (Digital Output): Xuất mức nhị phân 0 hoặc 1 so sánh qua IC LM393:
    • Trời SÁNG: Xuất mức 0 (LOW).
    • Trời TỐI: Xuất mức 1 (HIGH).
  • A0 (Analog Output): Xuất điện áp liên tục từ 0V đến 5V tỉ lệ với cường độ ánh sáng, đọc qua bộ ADC Arduino (giá trị từ 0 đến 1023).

• Đoạn mã đọc giá trị Analog A0 & Digital D0 từ quang trở:

const int ldrDigitalPin = 7; // Nối vào chân D0
const int ldrAnalogPin = A0; // Nối vào chân A0

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

void loop() {
  int isDark = digitalRead(ldrDigitalPin); // 1: Trời tối, 0: Trời sáng
  int lightLevel = analogRead(ldrAnalogPin); // 0 (cực sáng) -> 1023 (cực tối)

  Serial.print("Digital D0: ");
  Serial.print(isDark ? "Troi TOI (1)" : "Troi SANG (0)");
  Serial.print(" | Analog A0: ");
  Serial.println(lightLevel);

  delay(200);
}
Mục 1.5

Còi Báo Động (Buzzer) & Nguyên Lý Gốm Áp Điện (Piezo)

Piezoelectric Speaker
Hình ảnh linh kiện: Còi chíp 2 chân
Còi chip Buzzer

Hình 3: Còi chíp 2 chân có cực tính tương tự LED: Chân dài là cực dương (+), Chân ngắn là cực âm (-).

Cấu tạo bên trong: Màng gốm áp điện Piezo
Cấu trúc bên trong còi chíp Piezo

Hình 4: Tấm màng kim loại phủ gốm Piezoelectric co giãn theo xung điện trường để rung không khí tạo sóng âm thanh.

Tiêu chí Còi Chủ Động (Active Buzzer) Còi Thụ Động (Passive Buzzer / Piezo)
Mạch dao động nội Có sẵn mạch dao động tạo tần số cố định bên trong còi. Không có mạch dao động, chỉ có màng loa piezo thuần túy.
Cách phát âm thanh Chỉ cần cấp điện áp 5V (HIGH) là tự động kêu tiếng bíp liên tục. Phải cấp xung vuông PWM hoặc đổi trạng thái HIGH/LOW liên tục ở tần số mong muốn.
Khả năng phát nhạc Không đổi được tần số (chỉ phát 1 tone duy nhất). Phát được mọi nốt nhạc Đồ Rê Mi và các bài hát phức tạp.

• Kỹ thuật phát âm thanh tần số F trong thời gian D bằng xung vuông thủ công:

// Hàm playTone: Tự tạo xung vuông với tần số frequency (Hz) và độ dài duration (ms)
void playTone(int buzzerPin, long frequency, long duration) {
  long period = 1000000 / frequency; // Chu kỳ sóng (tính bằng microsecond)
  long numCycles = duration * frequency / 1000; // Số chu kỳ cần lặp

  for (long i = 0; i < numCycles; i++) {
    digitalWrite(buzzerPin, HIGH);
    delayMicroseconds(period / 2); // Nửa chu kỳ ở mức cao
    digitalWrite(buzzerPin, LOW);
    delayMicroseconds(period / 2); // Nửa chu kỳ ở mức thấp
  }
}

// Lưu ý: Trong Arduino có sẵn hàm hỗ trợ chính thức:
// tone(buzzerPin, frequency, duration);
// noTone(buzzerPin);

* Kho mã nguồn phát các bản nhạc nổi tiếng (Super Mario, Star Wars, Harry Potter, v.v.): https://github.com/robsoncouto/arduino-songs

Mục 4

Bài Tập Tổng Hợp: Dự Án "Đèn Học Thông Minh" (Smart Lamp)

Tích hợp Đa Cảm Biến
• Đề bài yêu cầu hệ thống hoạt động qua 3 cấp độ:
  1. Cấp độ 1: Khi trời tối (quang trở phát hiện) VÀ có người lại gần bàn học (< 50 cm đo bằng HC-SR04) → Tự động BẬT đèn LED. Nếu trời sáng hoặc không có người → TẮT đèn.
  2. Cấp độ 2 (Chống mỏi mắt / Cảnh báo thời gian): Nếu người học ngồi liên tục quá 5 giây (trong thực tế là 45-60 phút) → Đèn LED chuyển sang nhấp nháy liên tục để nhắc nhở người học đứng dậy giải lao (dùng hàm millis() để tính giờ).
  3. Cấp độ 3 (Âm thanh tạm biệt): Khi người học đứng dậy đi ra ngoài bàn học (> 50 cm) sau khi đã ngồi học → Còi Buzzer phát ra một đoạn nhạc giai điệu chúc mừng thư giãn!

• Toàn bộ mã nguồn hoàn chỉnh (C++ / Arduino IDE):

/* 
 * DU AN: DEN HOC THONG MINH (SMART STUDY LAMP)
 * Fit HCMUS - Thuc hanh IoT Tuan 4
 * Linh kien: Arduino UNO, HC-SR04, Quang tro LDR, Den LED, Coi Buzzer
 */

// Dinh nghia cac chan cam
const int trigPin = 9;
const int echoPin = 10;
const int ldrDigitalPin = 7; // Hoac doc qua A0
const int ledPin = 8;
const int buzzerPin = 6;

// Bien trang thai va hen gio bang millis()
bool isStudying = false;
unsigned long studyStartTime = 0;
const unsigned long OVER_TIME_LIMIT = 5000; // 5 giay (demo)

// Ham do khoang cach sieu am (cm)
float getDistance() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  unsigned long duration = pulseIn(echoPin, HIGH, 30000); // Timeout 30ms
  if (duration == 0) return 999.0;
  return (duration * 0.034) / 2.0;
}

// Giai dieu vui tuoi phat qua buzzer khi nguoi dung dung day
void playGoodbyeMelody() {
  int notes[] = { 262, 294, 330, 349, 392, 440, 494, 523 }; // C4 -> C5
  for (int i = 0; i < 8; i++) {
    tone(buzzerPin, notes[i], 120);
    delay(150);
  }
  noTone(buzzerPin);
}

void setup() {
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(ldrDigitalPin, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(buzzerPin, OUTPUT);
  Serial.begin(9600);
  Serial.println("=== HE THONG DEN HOC THONG MINH KHOI DONG ===");
}

void loop() {
  float distance = getDistance();
  int isDark = digitalRead(ldrDigitalPin); // 1 la troi toi, 0 la troi sang

  bool personNear = (distance > 0 && distance <= 50.0); // Nguoi cach ban < 50cm

  // Kiem tra dieu kien bat den hoc: Troi toi VA co nguoi lai gan
  if (isDark == 1 && personNear) {
    if (!isStudying) {
      // Bat dau phien ngoi hoc
      isStudying = true;
      studyStartTime = millis();
      digitalWrite(ledPin, HIGH);
      Serial.println("[BAT DEN] Nguoi hoc da vao ban!");
    } else {
      // Da ngoi hoc, kiem tra da qua 5s chua
      unsigned long duration = millis() - studyStartTime;
      if (duration >= OVER_TIME_LIMIT) {
        // Canh bao ngoi qua lau: Nhap nhay den LED
        digitalWrite(ledPin, (millis() / 250) % 2 == 0 ? HIGH : LOW);
        Serial.println("[CANH BAO] Ban da ngoi hoc qua 5 giay! Hay nghi ngoi.");
      } else {
        digitalWrite(ledPin, HIGH); // Van trong thoi gian an toan
      }
    }
  } else {
    // Khong thoa man dieu kien (Nguoi di ra ngoai hoac troi da sang)
    if (isStudying) {
      // Nguoi hoc vua roi ban! Phat nhac chao tam biet
      Serial.println("[TAM BIET] Nguoi hoc da roi ban, phat nhac thu gian...");
      digitalWrite(ledPin, LOW);
      playGoodbyeMelody();
      isStudying = false;
    } else {
      digitalWrite(ledPin, LOW);
    }
  }

  delay(100);
}
Mục 5

12 Câu Hỏi Ôn Tập Cuối Buổi & Lời Giải Chi Tiết

Trọn bộ 12 câu kiểm tra
Câu 1: Ultrasonic sensor có bao nhiêu chân xử lý tín hiệu? Tên gì?

Đáp án: Có 2 chân xử lý tín hiệu là chân Trig (Trigger) và chân Echo (ngoài ra còn 2 chân cấp nguồn là VCC 5V và GND).

Câu 2: Loại tín hiệu điện tử được sử dụng cho mỗi chân Echo và Trig này?

Đáp án: Cả 2 chân đều sử dụng tín hiệu Digital (mức logic HIGH và LOW).

Câu 3: Khi sử dụng pinMode cho Echo và Trig thì sẽ khai báo những chân này là IN hay OUT?

Đáp án:
• Chân Echo: khai báo là INPUT (vi điều khiển nhận xung phản hồi từ cảm biến).
• Chân Trig: khai báo là OUTPUT (vi điều khiển xuất xung kích phát sang cảm biến).

Câu 4: Hãy viết đoạn code để kích hoạt cho chân Trig.
Đáp án: Tạo một xung HIGH với độ rộng tối thiểu 10 microseconds:
digitalWrite(trigPin, LOW);
delayMicroseconds(10);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
Câu 5: Viết đoạn code để đo thời gian chân Echo ở trạng thái cao (HIGH).
Đáp án: Sử dụng hàm pulseIn() trả về thời gian bằng microsecond:
unsigned long duration = pulseIn(echoPin, HIGH);
Câu 6: Giả sử tổng thời gian sóng siêu âm từ lúc phát ra đến lúc thu về là 1 millisecond. Tính khoảng cách theo cm.

Đáp án: Kết quả là 17 cm.
Giải thích chi tiết:
• Thời gian t = 1 millisecond = 1000 microsecond (µs).
• Vận tốc sóng âm v = 0.034 cm/µs.
• Do sóng đi 2 chiều (phát tới vật cản và dội về) nên khoảng cách một chiều là:
    d = (v × t) / 2 = (0.034 × 1000) / 2 = 34 / 2 = 17 cm.

Câu 7: Viết dòng code để tạm dừng chương trình trong 0,1s.
Đáp án: 0,1 giây = 100 milliseconds, sử dụng hàm:
delay(100);
Câu 8: Viết đoạn code để tạm dừng chương trình trong 0,1 millisecond.
Đáp án: 0,1 millisecond = 100 microseconds, sử dụng hàm:
delayMicroseconds(100);
Câu 9: Trong photoresistor (quang trở), giá trị điện trở tỷ lệ thuận hay nghịch với cường độ ánh sáng chiếu vào?

Đáp án: Tỷ lệ nghịch. Cường độ ánh sáng chiếu vào càng tăng thì giá trị điện trở của quang trở càng giảm mạnh.

Câu 10: Thành phần nào trong buzzer phát ra âm thanh?

Đáp án: Màng gốm áp điện (Piezo / Piezoelectric element). Khi có điện áp biến thiên cấp vào, tinh thể gốm áp điện co giãn cơ học với tần số cao làm rung màng loa kim loại, từ đó tạo ra sóng âm thanh trong không khí.

Câu 11: Viết đoạn code để buzzer phát ra âm thanh tần số F trong khoảng thời gian D.
Đáp án: Định nghĩa hàm tạo chu kỳ xung vuông bằng delayMicroseconds:
void playTone(int buzzerPin, long frequency, long duration) {
  long period = 1000000 / frequency;            // Chu kỳ (µs)
  long numCycles = duration * frequency / 1000; // Số chu kỳ cần lặp
  for (long i = 0; i < numCycles; i++) {
    digitalWrite(buzzerPin, HIGH);
    delayMicroseconds(period / 2);
    digitalWrite(buzzerPin, LOW);
    delayMicroseconds(period / 2);
  }
}
Câu 12: Lắp mạch và lập trình theo yêu cầu sau: Chỉ sử dụng đầu quang trở để bật tắt buzzer. Giá trị quang trở < 500 bật buzzer và ngược lại.

Đáp án:

• Đấu nối: Chân Analog A0 của module quang trở nối vào chân A0 Arduino. Cực dương (+) của còi Buzzer nối vào chân D8, cực âm (-) nối vào GND.

• Đoạn mã lập trình hoàn chỉnh:

const int ldrPin = A0;
const int buzzerPin = 8;

void setup() {
  pinMode(buzzerPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  int ldrValue = analogRead(ldrPin);
  Serial.print("Gia tri quang tro: ");
  Serial.println(ldrValue);

  if (ldrValue < 500) {
    // Gia tri < 500: Bat buzzer (phat am thanh tan so 1000Hz)
    tone(buzzerPin, 1000); 
  } else {
    // Gia tri >= 500: Tat buzzer
    noTone(buzzerPin);
  }

  delay(50);
}
Tổng quan Tuần 3 Tuần 4 Slide PDF Tra cứu