IoTLabs

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

Series 37 Module Cảm Biến – Nguyên Lý RGB LED Module KY-016: Điốt 3 Màu, PWM Mix Màu 16 Triệu Sắc & Hiệu Ứng

RGB LED KY-016 là module đơn giản nhưng cho phép tạo ra 16.7 triệu màu khác nhau bằng cách điều chỉnh PWM từng kênh đỏ-xanh-xanh dương. Bài này giải thích tại sao 3 LED có điện áp thuận khác nhau, cách điện trở hạn dòng trên module được tính toán, và code tạo hiệu ứng fade, rainbow, breathing trên Arduino và ESP32.

Nguyên Lý Hoạt Động

1. RGB LED — Không Phải 1 LED Mà Là 3 LED Riêng Biệt

Một RGB LED thực ra là 3 LED riêng biệt trong cùng một vỏ nhựa:

  • 1 LED đỏ (Red)
  • 1 LED xanh lá (Green)
  • 1 LED xanh dương (Blue)

Chúng dùng chung 1 cực (cathode hoặc anode), nhưng mỗi LED có cực riêng để điều khiển độc lập:

Common Cathode (KY-016):           Common Anode:
            GND (chung)                      VCC (chung)
             │                                │
        ┌────┼────┐                      ┌────┼────┐
       [R]  [G]  [B]                    [R]  [G]  [B]
        │    │    │                      │    │    │
       R    G    B pins               R    G    B pins
      (nối lên VCC)                  (nối xuống GND)

KY-016 là common cathode: Chân GND là chung; các chân R, G, B nối lên nguồn qua GPIO (HIGH = sáng).

2. Tại Sao 3 Màu Có Điện Áp Thuận Khác Nhau

Điện áp thuận (forward voltage V_f) của LED phụ thuộc vào vật liệu bán dẫn tạo màu sắc đó:

MàuVật liệuBước sóngV_f điển hình
ĐỏGaAsP / AlGaInP620–750nm1.8V – 2.2V
VàngGaAsP570–590nm2.0V – 2.4V
Xanh láInGaN / GaP495–570nm2.8V – 3.5V
Xanh dươngInGaN450–490nm2.8V – 3.5V
TrắngInGaN + phosphorBroadband2.8V – 3.5V

Hệ quả quan trọng:

  • Đỏ: V_f ≈ 2V → với nguồn 5V cần điện trở lớn hơn để hạn dòng
  • Xanh/Xanh dương: V_f ≈ 3V → ít điện áp rơi trên điện trở hơn

3. Điện Trở Hạn Dòng Trên KY-016

KY-016 có 3 điện trở SMD trên PCB, mỗi chân một điện trở:

Tính toán điện trở (nguồn 5V, dòng mục tiêu ~20mA):

R = (VCC - V_f) / I_target

Đỏ:   R = (5V - 2V) / 20mA = 3V / 0.02A = 150Ω
Xanh: R = (5V - 3V) / 20mA = 2V / 0.02A = 100Ω
Xanh dương: R = (5V - 3.2V) / 20mA = 1.8V / 0.02A = 90Ω ≈ 100Ω

Module KY-016 thường dùng 150Ω cho đỏ100Ω cho xanh/xanh dương.

Với nguồn 3.3V (ESP32):

Đỏ:   I = (3.3V - 2V) / 150Ω = 1.3/150 ≈ 8.7mA (đủ sáng)
Xanh: I = (3.3V - 3V) / 100Ω = 0.3/100 ≈ 3mA (hơi tối nhưng thấy được)

Với 3.3V, màu xanh/xanh dương sẽ kém sáng hơn so với 5V, nhưng vẫn dùng được cho demonstration.

4. PWM Mix Màu — 16.7 Triệu Màu

PWM (Pulse Width Modulation) điều chỉnh duty cycle 0–100% → điều chỉnh cường độ từng màu:

  • Duty cycle 0% (analogWrite 0) → LED tắt hoàn toàn
  • Duty cycle 100% (analogWrite 255) → LED sáng tối đa
  • Giá trị trung gian → mắt người nhìn thấy cường độ trung gian (persistence of vision)

16.7 triệu màu: 256 cấp × 256 cấp × 256 cấp = 16,777,216 tổ hợp màu.

Phối màu cơ bản (additive color mixing):

RGBMàu hiển thị
25500Đỏ thuần
02550Xanh lá thuần
00255Xanh dương thuần
2552550Vàng
2550255Tím (Magenta)
0255255Cyan
255255255Trắng
128128128Xám

5. HSV Color Space — Chọn Màu Tự Nhiên Hơn

Thay vì nhớ giá trị R/G/B, dùng HSV (Hue, Saturation, Value):

  • H (Hue): Góc màu 0°–360° (0°=đỏ, 120°=xanh lá, 240°=xanh dương)
  • S (Saturation): Độ bão hòa 0–100% (0=xám, 100=màu thuần)
  • V (Value/Brightness): Độ sáng 0–100% (0=tắt, 100=sáng tối đa)

Hiệu ứng Rainbow: Tăng H từ 0° đến 360° liên tục với S=100%, V=100% → tạo cầu vồng.

Thông Số Kỹ Thuật

Thông sốGiá trị
Điện áp hoạt động3.3V – 5V (điện trở module tính cho 5V)
Dòng mỗi kênh~8-20mA (tùy nguồn)
Loại LEDCommon cathode
Điện trở tích hợp~150Ω (đỏ), ~100Ω (xanh, xanh dương)
Độ sáng (typ)200–1000mcd mỗi kênh
Bước sóngR:630nm, G:530nm, B:470nm
Góc nhìn30° (phụ thuộc model)

Sơ Đồ Chân (Pinout)

KY-016 Module — 4 chân:

[LED RGB] ────────────────────────
  ┌──────────────────────────┐
  │   [RGB LED]              │
  │   [R 150Ω][G 100Ω][B 100Ω]│
  └──────────────────────────┘
   GND    R    G    B
ChânMàu sắcChức năng
GNDĐất (common cathode)
RĐỏPWM input đỏ — HIGH = sáng
GXanh láPWM input xanh lá — HIGH = sáng
BXanh dươngPWM input xanh dương — HIGH = sáng

Thứ tự chân thực tế: Có thể khác nhau tùy module. Kiểm tra marking trên PCB.

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

KY-016 với ESP32 DevKit V1

ESP32 DevKit V1           KY-016 Module
─────────────────────     ────────────────────
GND  ─────────────────→  GND
GPIO5  (PWM) ──────────→  R  (Đỏ)
GPIO18 (PWM) ──────────→  G  (Xanh lá)
GPIO19 (PWM) ──────────→  B  (Xanh dương)

ESP32 cung cấp 3.3V HIGH → đỏ sáng bình thường, xanh/xanh dương sẽ hơi tối hơn so với 5V. Có thể cấp 5V từ VIN nếu có nguồn 5V và thêm transistor/MOSFET để chuyển 3.3V → 5V logic cho từng kênh.

KY-016 với Arduino Uno

Arduino Uno               KY-016 Module
─────────────────────     ────────────────────
GND  ─────────────────→  GND
Pin 9 (PWM~) ──────────→  R  (Đỏ)
Pin 10 (PWM~) ─────────→  G  (Xanh lá)
Pin 11 (PWM~) ─────────→  B  (Xanh dương)

Pin 9, 10, 11 của Arduino Uno đều là PWM (ký hiệu ~). Cho phép analogWrite().

Code Arduino IDE

Code Cơ Bản — Hiển Thị Các Màu — Arduino Uno

/*
 * RGB LED KY-016 — Hiển thị màu cơ bản
 * Board: Arduino Uno
 * Kết nối: GND→GND, R→Pin9, G→Pin10, B→Pin11
 *
 * Common Cathode: 0=tắt, 255=sáng tối đa
 */

const int RED_PIN   = 9;
const int GREEN_PIN = 10;
const int BLUE_PIN  = 11;

// Đặt màu RGB (0-255 mỗi kênh)
void setColor(int r, int g, int b) {
  analogWrite(RED_PIN,   r);
  analogWrite(GREEN_PIN, g);
  analogWrite(BLUE_PIN,  b);
}

void setup() {
  Serial.begin(9600);
  pinMode(RED_PIN, OUTPUT);
  pinMode(GREEN_PIN, OUTPUT);
  pinMode(BLUE_PIN, OUTPUT);
  setColor(0, 0, 0); // Tắt ban đầu
  Serial.println("=== RGB LED KY-016 - Arduino Uno ===");
}

void loop() {
  Serial.println("ĐỎ");   setColor(255, 0, 0);   delay(1000);
  Serial.println("XANH"); setColor(0, 255, 0);   delay(1000);
  Serial.println("XANH DƯƠNG"); setColor(0, 0, 255); delay(1000);
  Serial.println("VÀNG");  setColor(255, 255, 0); delay(1000);
  Serial.println("TÍM");   setColor(255, 0, 255); delay(1000);
  Serial.println("CYAN");  setColor(0, 255, 255); delay(1000);
  Serial.println("TRẮNG"); setColor(255, 255, 255); delay(1000);
  Serial.println("TẮT");   setColor(0, 0, 0);     delay(500);
}

Code Hiệu Ứng Fade và Rainbow — Arduino Uno

/*
 * RGB LED KY-016 — Hiệu ứng Fade và Rainbow
 * Board: Arduino Uno
 * Kết nối: GND→GND, R→Pin9, G→Pin10, B→Pin11
 */

const int RED_PIN   = 9;
const int GREEN_PIN = 10;
const int BLUE_PIN  = 11;

void setColor(int r, int g, int b) {
  analogWrite(RED_PIN, r);
  analogWrite(GREEN_PIN, g);
  analogWrite(BLUE_PIN, b);
}

// Chuyển đổi HSV → RGB
// h: 0-360, s: 0-255, v: 0-255
void hsvToRgb(int h, int s, int v, int &r, int &g, int &b) {
  int region = h / 60;
  int remainder = (h % 60) * 255 / 60;

  int p = (v * (255 - s)) / 255;
  int q = (v * (255 - (s * remainder) / 255)) / 255;
  int t = (v * (255 - (s * (255 - remainder)) / 255)) / 255;

  switch (region) {
    case 0: r = v; g = t; b = p; break;
    case 1: r = q; g = v; b = p; break;
    case 2: r = p; g = v; b = t; break;
    case 3: r = p; g = q; b = v; break;
    case 4: r = t; g = p; b = v; break;
    default: r = v; g = p; b = q; break;
  }
}

// Hiệu ứng rainbow: cycle qua 360° màu
void rainbowEffect(int delayMs = 10) {
  for (int h = 0; h < 360; h++) {
    int r, g, b;
    hsvToRgb(h, 255, 200, r, g, b); // Saturation=255, Brightness=200
    setColor(r, g, b);
    delay(delayMs);
  }
}

// Hiệu ứng fade một màu
void fadeColor(int r, int g, int b, int steps = 50) {
  // Fade in
  for (int i = 0; i <= steps; i++) {
    setColor(r * i / steps, g * i / steps, b * i / steps);
    delay(20);
  }
  delay(300);
  // Fade out
  for (int i = steps; i >= 0; i--) {
    setColor(r * i / steps, g * i / steps, b * i / steps);
    delay(20);
  }
  delay(100);
}

// Hiệu ứng breathing (sin wave)
void breathingEffect(int r, int g, int b, int cycles = 3) {
  for (int c = 0; c < cycles; c++) {
    for (float angle = 0; angle < 2 * PI; angle += 0.05) {
      float brightness = (sin(angle) + 1.0) / 2.0; // 0.0 đến 1.0
      setColor(r * brightness, g * brightness, b * brightness);
      delay(15);
    }
  }
}

void setup() {
  Serial.begin(9600);
  setColor(0, 0, 0);
  Serial.println("RGB LED Effects Demo");
}

void loop() {
  Serial.println("Rainbow...");
  rainbowEffect(8);

  Serial.println("Fade đỏ...");
  fadeColor(255, 0, 0);

  Serial.println("Fade xanh...");
  fadeColor(0, 255, 0);

  Serial.println("Breathing tím...");
  breathingEffect(255, 0, 255);
}

Code ESP32 — RGB LED với LEDC PWM

/*
 * RGB LED KY-016 — ESP32 dùng LEDC PWM
 * Board: ESP32 DevKit V1
 * Kết nối: GND→GND, R→GPIO5, G→GPIO18, B→GPIO19
 *
 * LEDC: LED Control — PWM hardware của ESP32
 * Dùng 3 LEDC channels riêng biệt cho R, G, B
 */

// GPIO pins
const int RED_PIN   = 5;
const int GREEN_PIN = 18;
const int BLUE_PIN  = 19;

// LEDC channels (0-15 có sẵn trên ESP32)
const int CH_RED   = 0;
const int CH_GREEN = 1;
const int CH_BLUE  = 2;

const int PWM_FREQ = 5000; // Hz
const int PWM_RES  = 8;    // 8-bit: 0-255

void setupPWM() {
  ledcSetup(CH_RED,   PWM_FREQ, PWM_RES);
  ledcSetup(CH_GREEN, PWM_FREQ, PWM_RES);
  ledcSetup(CH_BLUE,  PWM_FREQ, PWM_RES);
  ledcAttachPin(RED_PIN,   CH_RED);
  ledcAttachPin(GREEN_PIN, CH_GREEN);
  ledcAttachPin(BLUE_PIN,  CH_BLUE);
}

void setColor(int r, int g, int b) {
  ledcWrite(CH_RED,   r);
  ledcWrite(CH_GREEN, g);
  ledcWrite(CH_BLUE,  b);
}

// HSV → RGB (hue: 0-360, sat/val: 0-255)
void hsvToRgb(int h, int s, int v, int &r, int &g, int &b) {
  int region = h / 60;
  int rem = (h % 60) * 255 / 60;
  int p = v * (255 - s) / 255;
  int q = v * (255 - s * rem / 255) / 255;
  int t = v * (255 - s * (255 - rem) / 255) / 255;
  switch (region) {
    case 0: r=v; g=t; b=p; break;
    case 1: r=q; g=v; b=p; break;
    case 2: r=p; g=v; b=t; break;
    case 3: r=p; g=q; b=v; break;
    case 4: r=t; g=p; b=v; break;
    default: r=v; g=p; b=q; break;
  }
}

void setup() {
  Serial.begin(115200);
  setupPWM();
  setColor(0, 0, 0);
  Serial.println("=== RGB LED ESP32 LEDC ===");
}

void loop() {
  // Rainbow effect — liên tục quét hue
  for (int h = 0; h < 360; h++) {
    int r, g, b;
    hsvToRgb(h, 255, 200, r, g, b);
    setColor(r, g, b);
    delay(5); // Nhanh hơn Arduino Uno vì ESP32 nhanh hơn
  }
}

Kết Quả Mong Đợi

=== RGB LED KY-016 - Arduino Uno ===
ĐỎ
XANH
XANH DƯƠNG
VÀNG
TÍM
CYAN
TRẮNG
TẮT
[Lặp lại vô tận]

Module LED chạy qua tất cả các màu, sau đó vào hiệu ứng rainbow mượt mà.

Ứng Dụng Thực Tế

Ứng dụngChi tiết
Đèn trạng thái hệ thốngXanh=OK, Vàng=Cảnh báo, Đỏ=Lỗi
Đèn tâm trạng (mood light)Đổi màu chậm theo thời gian/nhạc
Hiển thị nhiệt độ bằng màuXanh=lạnh, Đỏ=nóng
Phản hồi cảm xúc chatbotVui=vàng, Buồn=xanh
Đèn Night light thông minhRemote→chọn màu
Hiệu ứng sân khấu miniBreathing, rainbow, stroble effect

Lưu Ý Khi Sử Dụng

1. Common cathode vs Common anode — kiểm tra trước khi code

KY-016 là common cathode. Nếu dùng RGB LED rời: có thể là common anode → logic đảo (0=sáng, 255=tắt). Cắm sai → LED không sáng hoặc sáng tất cả không điều chỉnh được. Kiểm tra: thử analogWrite(PIN, 255) → nếu không sáng thì có thể là common anode.

2. PWM trên Arduino Uno chỉ 6 chân

Chỉ Pin 3, 5, 6, 9, 10, 11 của Arduino Uno có PWM (~). Phải dùng 3 trong số này cho RGB LED. Không thể dùng analogWrite() trên các pin khác.

3. ESP32: LEDC channel cẩn thận không conflict

ESP32 có 16 LEDC channels (0-15). Nếu code cùng lúc dùng LEDC cho servo, buzzer, hay LED khác → đảm bảo không dùng cùng channel number. Mỗi PWM output cần 1 channel riêng.

4. Màu trắng RGB không “trắng” như đèn thực

RGB (255,255,255) cộng 3 màu → trông gần trắng. Nhưng màu trắng thực sự từ đèn LED trắng (với phosphor) sẽ tự nhiên hơn. Với ứng dụng cần trắng chính xác: dùng LED trắng riêng kết hợp với RGB.

Bài tiếp theo: