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àu | Vật liệu | Bước sóng | V_f điển hình |
|---|---|---|---|
| Đỏ | GaAsP / AlGaInP | 620–750nm | 1.8V – 2.2V |
| Vàng | GaAsP | 570–590nm | 2.0V – 2.4V |
| Xanh lá | InGaN / GaP | 495–570nm | 2.8V – 3.5V |
| Xanh dương | InGaN | 450–490nm | 2.8V – 3.5V |
| Trắng | InGaN + phosphor | Broadband | 2.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 đỏ và 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):
| R | G | B | Màu hiển thị |
|---|---|---|---|
| 255 | 0 | 0 | Đỏ thuần |
| 0 | 255 | 0 | Xanh lá thuần |
| 0 | 0 | 255 | Xanh dương thuần |
| 255 | 255 | 0 | Vàng |
| 255 | 0 | 255 | Tím (Magenta) |
| 0 | 255 | 255 | Cyan |
| 255 | 255 | 255 | Trắng |
| 128 | 128 | 128 | Xá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 động | 3.3V – 5V (điện trở module tính cho 5V) |
| Dòng mỗi kênh | ~8-20mA (tùy nguồn) |
| Loại LED | Common 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óng | R:630nm, G:530nm, B:470nm |
| Góc nhìn | 30° (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ân | Màu sắc | Chức năng |
|---|---|---|
| GND | — | Đất (common cathode) |
| R | Đỏ | PWM input đỏ — HIGH = sáng |
| G | Xanh lá | PWM input xanh lá — HIGH = sáng |
| B | Xanh dương | PWM 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ụng | Chi tiết |
|---|---|
| Đèn trạng thái hệ thống | Xanh=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àu | Xanh=lạnh, Đỏ=nóng |
| Phản hồi cảm xúc chatbot | Vui=vàng, Buồn=xanh |
| Đèn Night light thông minh | Remote→chọn màu |
| Hiệu ứng sân khấu mini | Breathing, 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.


