IoTLabs

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

Series 37 Module Cảm Biến – Nguyên Lý Hoạt Động IR Receiver VS1838B: Demodulate 38kHz, NEC Protocol & Điều Khiển Từ Xa

VS1838B là IC nhận hồng ngoại tích hợp — bên trong không chỉ là photodiode mà còn có toàn bộ mạch demodulate, lọc nhiễu, và khuếch đại tự động. Kết nối với MCU chỉ cần 1 chân digital và vài dòng code. Bài này phân tích cách VS1838B lọc tín hiệu 38kHz ra khỏi nhiễu môi trường, giải thích NEC protocol, và code decode remote bất kỳ.

Nguyên Lý Hoạt Động

1. Tại Sao Dùng 38kHz — Tránh Nhiễu Môi Trường

Ánh sáng môi trường (đèn, nắng) cũng chứa IR nhưng không dao động ở 38kHz. Remote điều khiển từ xa điều chế (modulate) tín hiệu: LED IR bật tắt 38.000 lần/giây (38kHz).

Remote TV gửi:
  Bit "1" = [ 38kHz burst 562µs ] + [ không phát 1687µs ]
  
Dạng sóng thực tế:
  ──┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌──────────────────
    └┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└
    ←────── 38kHz carrier ──────────→←── không phát ──→
           562µs                         1687µs

Ánh sáng nền (đèn huỳnh quang, nắng):
  DC IR không điều chế hoặc 50/100Hz — hoàn toàn khác 38kHz
  → Bộ lọc bandpass loại bỏ hoàn toàn

38kHz là chuẩn chung: Ngoài ra còn 36kHz (Sony), 40kHz, 56kHz — nhưng 38kHz là phổ biến nhất.

2. Bên Trong VS1838B — 4 Khối Chức Năng

            IR Light (modulated 38kHz)
                     ↓
        ┌──────────────────────┐
        │  PIN Photodiode      │ ← Thu IR, tạo dòng
        └──────────┬───────────┘
                   ↓
        ┌──────────────────────┐
        │  Bandpass Filter     │ ← Chỉ cho 38kHz qua, lọc nhiễu DC và tần số khác
        │  (centered at 38kHz) │
        └──────────┬───────────┘
                   ↓
        ┌──────────────────────┐
        │  AGC                 │ ← Automatic Gain Control: điều chỉnh khuếch đại
        │  (Automatic Gain     │   để nhận tín hiệu từ remote xa/gần đều OK
        │   Control)           │
        └──────────┬───────────┘
                   ↓
        ┌──────────────────────┐
        │  Comparator + Output │ ← Xuất digital (active LOW)
        └──────────┬───────────┘
                   ↓
                OUT pin (active LOW)

Ngõ ra active LOW (đảo):

  • Remote gửi burst 38kHz → VS1838B phát hiện → OUT = LOW
  • Remote không gửi → OUT = HIGH (nhờ pull-up nội bộ trong VS1838B)

Vì vậy, sóng dạng tại OUT pin là đảo ngược so với tín hiệu remote gốc:

Remote LED IR:  ──┐   ┌──┐  ┌──────
                  └───┘  └──┘
VS1838B OUT:    ──┘   └──┘  └──────  ← Đảo ngược
                  ┌───┐  ┌──┐

Library IRremote đã xử lý việc đảo ngược này tự động.

3. NEC Protocol — Chuẩn Phổ Biến Nhất

Phần lớn remote tivi, điều hòa, quạt Asia dùng NEC protocol.

Cấu trúc một lần gửi lệnh (frame):

[ 9ms AGC burst ] [ 4.5ms space ] [ 32 bits data ] [ final burst 562µs ]

32 bits = [ Address 8-bit ] [ ~Address 8-bit ] [ Command 8-bit ] [ ~Command 8-bit ]
          └── Địa chỉ thiết bị ──┘              └── Lệnh cụ thể ─────────────────┘
          └── Kiểm tra (inverted) ──────────────────────────────────────────────┘

~Address = bitwise NOT của Address (dùng để kiểm tra lỗi)

Mã hóa bit:

Bit "0":  [ 562µs burst ] [ 562µs space ] = tổng 1.125ms
Bit "1":  [ 562µs burst ] [ 1687µs space ] = tổng 2.25ms

MCU đo khoảng thời gian giữa các xung:
  ~562µs = bit 0
  ~1687µs = bit 1

Repeat code (giữ nút):

[ 9ms burst ] [ 2.25ms space ] [ 562µs burst ]

Cho biết nút đang được giữ nhưng không gửi lại địa chỉ/lệnh.

Giá trị kết quả decode (HEX):

Kết quả results.value từ IRremote library là 32-bit: 0xAABBCCDD

  • AA = Address (hex)
  • BB = ~Address
  • CC = Command
  • DD = ~Command

Ví dụ nút “1” trên remote điều hòa: 0x00FF30CF → Address=0x00, Command=0x30.

Thông Số Kỹ Thuật

Thông sốGiá trị
Điện áp hoạt động2.7V – 5.5V
Dòng tiêu thụ (standby)~0.4mA
Tần số trung tâm38kHz
Dải tần chấp nhận36.7kHz – 39kHz
Bước sóng IR nhạy nhất940nm
Góc nhận±45°
Khoảng cách tối đa~18m (trong điều kiện tốt)
Ngõ raDigital, active LOW
Thời gian đáp ứng<50µs

Sơ Đồ Chân (Pinout)

        [Mắt nhận IR]
     ┌─────────────────┐
     │  VS1838B        │
     └─────────────────┘
      OUT   GND   VCC
       1     2     3

Nhìn từ phía trước (mặt lồi hướng về bạn):
  Chân 1 (trái) = OUT
  Chân 2 (giữa) = GND
  Chân 3 (phải) = VCC

QUAN TRỌNG: Thứ tự chân của VS1838B và TSOP1838 có thể khác nhau giữa các nhà sản xuất. Luôn kiểm tra datasheet hoặc nhìn dấu in trên linh kiện. Cắm sai VCC và OUT → có thể gây khói hoặc hỏng.

Module trong kit 37 module (KY-022):

┌────────────────────────────────┐
│  [VS1838B]  module board       │
└────────────────────────────────┘
  GND   VCC   S (Signal/OUT)

Module đã có điện trở bảo vệ và tụ lọc nguồn — dễ dùng hơn dùng linh kiện rời.

So Sánh Các IR Protocol Phổ Biến

ProtocolTần sốCấu trúcNhà sản xuất
NEC38kHz9ms+4.5ms start, 32-bitGeneric, nhiều hãng Asia
Sony SIRC40kHz2.4ms+0.6ms start, 12/15/20-bitSony
Philips RC536kHzBiphase Manchester, 14-bitPhilips
Philips RC636kHzMode bits, 20-32-bitPhilips
Samsung38kHz4.5ms+4.5ms start, 32-bitSamsung

IRremote library hỗ trợ tất cả các protocol trên tự động.

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

VS1838B Rời với ESP32 DevKit V1

ESP32 DevKit V1           VS1838B (3-pin rời)
─────────────────────     ────────────────────
3V3  ─────────────────→  VCC (Chân 3 — phải)
GND  ─────────────────→  GND (Chân 2 — giữa)
GPIO4 (Input) ←──────────  OUT (Chân 1 — trái)  [active LOW]

Thêm tụ lọc 100nF giữa VCC và GND gần VS1838B để tránh nhiễu nguồn (quan trọng với linh kiện rời, không cần với module).

Module KY-022 với Arduino Uno

Arduino Uno              KY-022 Module
─────────────────────    ─────────────────
5V   ─────────────────→  VCC (hoặc middle pin)
GND  ─────────────────→  GND
Pin 11 (Input) ←─────────  S (Signal/OUT)

Pin 11 là pin mặc định của IRremote library trên Arduino Uno.

Code Arduino IDE

Cài Library

IRremote của Arduino-IRremote (tác giả: shirriff, z3t0, ArminJo) — tìm trong Library Manager.

Lưu ý phiên bản: IRremote v3+ thay đổi API so với v2. Code dưới đây dùng v3+.

Code Đọc Remote Bất Kỳ — Arduino Uno

/*
 * IR Receiver VS1838B — Đọc và hiển thị mã HEX từ remote bất kỳ
 * Board: Arduino Uno
 * Library: IRremote (v3+) — tác giả Arduino-IRremote
 * Kết nối: VCC→5V, GND→GND, S→Pin11
 *
 * Dùng code này để "học" mã HEX của từng nút remote
 * Sau đó ghi lại và dùng trong code điều khiển thực tế
 */

#include <IRremote.hpp>   // IRremote v3+ dùng .hpp không phải .h

const int IR_RECEIVE_PIN = 11;

void setup() {
  Serial.begin(9600);
  IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);
  // ENABLE_LED_FEEDBACK: LED onboard Arduino nhấp nháy khi nhận IR
  Serial.println("=== IR Receiver - Học Mã Remote ===");
  Serial.println("Nhấn từng nút remote rồi xem mã HEX bên dưới:");
}

void loop() {
  if (IrReceiver.decode()) {
    // Nhận được tín hiệu hợp lệ

    Serial.print("Protocol: ");
    Serial.println(IrReceiver.getProtocolString());

    Serial.print("Mã HEX: 0x");
    Serial.println(IrReceiver.decodedIRData.decodedRawData, HEX);

    Serial.print("Address: 0x");
    Serial.print(IrReceiver.decodedIRData.address, HEX);
    Serial.print(" | Command: 0x");
    Serial.println(IrReceiver.decodedIRData.command, HEX);

    // Kiểm tra nút đang được giữ
    if (IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT) {
      Serial.println("(Repeat — đang giữ nút)");
    }

    Serial.println("---");

    // Quan trọng: phải gọi resume() để nhận tín hiệu tiếp theo
    IrReceiver.resume();
  }
}

Code Điều Khiển LED Theo Nút Remote — Arduino Uno

/*
 * IR Receiver — Điều khiển LED bằng remote
 * Board: Arduino Uno
 * Library: IRremote (v3+)
 * Kết nối: VCC→5V, GND→GND, S→Pin11; LED→Pin13
 *
 * BƯỚC 1: Dùng code "Học Mã Remote" ở trên để tìm HEX của các nút cần dùng
 * BƯỚC 2: Điền vào MAP bên dưới
 */

#include <IRremote.hpp>

const int IR_RECEIVE_PIN = 11;
const int LED_PIN        = 13; // LED onboard

// Mã HEX của từng nút — thay bằng mã thực của remote bạn
// Đây là ví dụ cho remote hồng ngoại mini phổ biến
#define BTN_ON   0xFFA25D  // Nút "ON"
#define BTN_OFF  0xFF629D  // Nút "OFF"
#define BTN_UP   0xFF22DD  // Nút tăng
#define BTN_DOWN 0xFF02FD  // Nút giảm

int brightness = 128; // Độ sáng hiện tại (0-255)

void setup() {
  Serial.begin(9600);
  IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);
  pinMode(LED_PIN, OUTPUT);
  analogWrite(LED_PIN, brightness);
  Serial.println("=== Điều Khiển LED Bằng Remote ===");
}

void loop() {
  if (IrReceiver.decode()) {
    // Bỏ qua tín hiệu repeat (giữ nút) — chỉ xử lý nhấn mới
    if (!(IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT)) {
      uint32_t code = IrReceiver.decodedIRData.decodedRawData;

      Serial.print("Nhận: 0x"); Serial.println(code, HEX);

      switch (code) {
        case BTN_ON:
          analogWrite(LED_PIN, 255);
          brightness = 255;
          Serial.println("LED: Bật tối đa");
          break;

        case BTN_OFF:
          analogWrite(LED_PIN, 0);
          brightness = 0;
          Serial.println("LED: Tắt");
          break;

        case BTN_UP:
          brightness = min(255, brightness + 30);
          analogWrite(LED_PIN, brightness);
          Serial.print("LED: Tăng sáng → "); Serial.println(brightness);
          break;

        case BTN_DOWN:
          brightness = max(0, brightness - 30);
          analogWrite(LED_PIN, brightness);
          Serial.print("LED: Giảm sáng → "); Serial.println(brightness);
          break;

        default:
          Serial.print("Nút không rõ: 0x"); Serial.println(code, HEX);
          break;
      }
    }

    IrReceiver.resume(); // Tiếp tục nhận tín hiệu
  }
}

Code ESP32 — Điều Khiển PWM LED Bằng Remote

/*
 * IR Receiver VS1838B — ESP32, điều khiển LED PWM bằng remote
 * Board: ESP32 DevKit V1
 * Library: IRremote (v3+)
 * Kết nối: VCC→3V3, GND→GND, OUT→GPIO4
 * LED: GPIO5 (PWM)
 *
 * Thay BTN_* bằng mã HEX thực từ remote của bạn
 */

#include <IRremote.hpp>

const int IR_RECEIVE_PIN = 4;
const int LED_PIN        = 5; // PWM GPIO

// Ví dụ mã NEC từ remote mini phổ biến — thay bằng mã thực của bạn
#define BTN_1  0xFF30CF   // Nút 1
#define BTN_2  0xFF18E7   // Nút 2
#define BTN_3  0xFF7A85   // Nút 3
#define BTN_OK 0xFF38C7   // Nút OK

void setup() {
  Serial.begin(115200);
  IrReceiver.begin(IR_RECEIVE_PIN, DISABLE_LED_FEEDBACK);
  // DISABLE_LED_FEEDBACK: ESP32 không có LED onboard tiêu chuẩn

  // Cấu hình PWM LED
  ledcAttachPin(LED_PIN, 0);
  ledcSetup(0, 5000, 8); // Channel 0, 5kHz, 8-bit

  Serial.println("=== IR Remote ESP32 ===");
}

void loop() {
  if (IrReceiver.decode()) {
    if (!(IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT)) {
      uint32_t code = IrReceiver.decodedIRData.decodedRawData;

      Serial.printf("Code: 0x%08X | Protocol: %s\n",
        code, IrReceiver.getProtocolString());

      switch (code) {
        case BTN_1:
          ledcWrite(0, 64);  // 25% brightness
          Serial.println("LED: 25%");
          break;
        case BTN_2:
          ledcWrite(0, 128); // 50% brightness
          Serial.println("LED: 50%");
          break;
        case BTN_3:
          ledcWrite(0, 255); // 100% brightness
          Serial.println("LED: 100%");
          break;
        case BTN_OK:
          ledcWrite(0, 0);   // Tắt
          Serial.println("LED: Tắt");
          break;
        default:
          Serial.printf("Không rõ: 0x%08X\n", code);
          break;
      }
    }
    IrReceiver.resume();
  }
}

Kết Quả Mong Đợi (Khi Học Mã)

=== IR Receiver - Học Mã Remote ===
Nhấn từng nút remote rồi xem mã HEX bên dưới:
Protocol: NEC
Mã HEX: 0xFF30CF
Address: 0xFF | Command: 0x30
---
Protocol: NEC
Mã HEX: 0xFF18E7
Address: 0xFF | Command: 0x18
---
Protocol: NEC
Mã HEX: 0xFF30CF
(Repeat — đang giữ nút)
---

Ứng Dụng Thực Tế

Ứng dụngChi tiết
Điều khiển đèn/quạt bằng remote TV cũMap nút remote → relay/dimmer
Robot điều khiển từ xaRemote → di chuyển tiến/lùi/rẽ
Điều khiển âm lượngRemote → tăng/giảm PWM loa
Home automation đơn giảnRemote → bật/tắt nhiều thiết bị khác nhau
Điều khiển màn hình OLEDRemote → chuyển màn hình, điều hướng menu
Emulator remoteGhi mã → phát lại bằng LED IR để điều khiển TV/điều hòa

Lưu Ý Khi Sử Dụng

1. Gọi IrReceiver.resume() sau mỗi lần decode

Nếu không gọi resume(), receiver sẽ không nhận tín hiệu tiếp theo. Đây là lỗi phổ biến nhất khi mới dùng IRremote — code chỉ nhận được nút đầu tiên rồi không phản ứng nữa.

2. Kiểm tra thứ tự chân VS1838B thực tế

Chân OUT/GND/VCC có thể khác nhau giữa nhà sản xuất và phiên bản (VS1838, TSOP1838, TSOP38238). Không giả định thứ tự — kiểm tra datasheet hoặc marking trên linh kiện. Cắm ngược → VS1838B nóng ngay lập tức → hỏng.

3. Thêm tụ 100nF giữa VCC và GND

Đặc biệt với linh kiện rời VS1838B: nhiễu nguồn cao → nhận sai hoặc không nhận. Tụ 100nF đặt gần nhất có thể cạnh chân VCC-GND của VS1838B.

4. IRremote v2 và v3 API khác nhau

#include (v2) vs #include (v3). Cú pháp decode, cách đọc value, cách gọi resume đều thay đổi. Code mẫu trên dùng v3. Kiểm tra phiên bản library đã cài.

5. Nhiễu đèn huỳnh quang 50Hz

Đèn huỳnh quang chớp 50Hz (hoặc 100Hz harmonic) có thể tạo nhiễu. Thường không đủ mạnh ở 38kHz để gây vấn đề, nhưng nếu nhận tín hiệu giả liên tục trong phòng đèn huỳnh quang: che góc nhìn sensor hoặc giảm độ nhạy bằng resistor nối tiếp với OUT pin.

Bài tiếp theo: