Mục lục bài viết

Bài này hướng dẫn điều khiển LED RGB với button bằng Arduino: mỗi lần nhấn nút, LED đổi sang một màu mới. Chỉ cần một nút nhấn, chúng ta có đủ 4 chế độ sáng. Nếu chưa biết cách sử dụng nút bấm với Arduino, bạn xem lại bài lập trình điều khiển led bằng nút bấm trước nhé.

Mục tiêu bài học:

  • Phân biệt được LED RGB cathode chung và anode chung.
  • Nối được LED RGB và nút nhấn vào Arduino Uno.
  • Viết được hàm chống dội phím và đếm số lần nhấn.
  • Dùng được analogWrite() để chỉnh độ sáng LED.

1. LED RGB là gì?

LED RGB thực chất là 3 con LED đỏ (Red), xanh lá (Green) và xanh dương (Blue) gộp chung. Mỗi màu có một chân điều khiển riêng.

LED RGB có 4 chân. Chân dài nhất là chân chung, 3 chân còn lại là R, G, B. Có hai loại:

  • Cathode chung: chân chung nối GND. Xuất mức HIGH thì màu đó sáng.
  • Anode chung: chân chung nối 5V. Xuất mức LOW thì màu đó mới sáng.

Bài này dùng loại cathode chung. Nếu bạn chỉ có loại anode chung, hãy nối chân chung lên 5V và đảo HIGH thành LOW trong code.

Cấu tạo LED RGB anode chung và cathode chung
LED RGB anode chung và cathode chung

2. Mạch điều khiển LED RGB với button

Linh kiện cần chuẩn bị:

  • 1 board Arduino Uno
  • 1 LED RGB cathode chung
  • 3 điện trở 220Ω cho LED
  • 1 nút nhấn và 1 điện trở 10kΩ
  • Breadboard và dây cắm

Ba chân R, G, B nối vào chân 9, 10, 11. Đây đều là chân PWM (có dấu ~ trên board), nên sau này chỉnh được độ sáng. Nút nhấn một đầu lên 5V, đầu kia vào chân 2 và xuống GND qua điện trở 10kΩ.

Linh kiệnChân linh kiệnArduino Uno
LED RGBR (qua điện trở 220Ω)9
LED RGBChân chung (dài nhất)GND
LED RGBG (qua điện trở 220Ω)10
LED RGBB (qua điện trở 220Ω)11
Nút nhấnChân 15V
Nút nhấnChân 2 (kèm 10kΩ xuống GND)2
Sơ đồ mạch điều khiển LED RGB với button bằng Arduino Uno
Sơ đồ mạch điều khiển LED RGB với button

Lưu ý: Không nối thẳng chân R, G, B vào Arduino mà thiếu điện trở. Dòng quá lớn có thể làm hỏng LED và chân Arduino. Nếu bạn dùng module LED RGB đã hàn sẵn điện trở thì bỏ qua 3 điện trở này. Thứ tự chân có thể khác nhau tùy hãng, hãy xem datasheet của LED bạn đang có.

3. Chương trình điều khiển LED RGB với button

Yêu cầu bài toán như sau:

  • Nhấn lần 1: LED sáng màu đỏ.
  • Nhấn lần 2: LED sáng màu xanh lá.
  • Nhấn lần 3: LED sáng màu xanh dương.
  • Nhấn lần 4: cả 3 màu cùng sáng dần lên.
  • Nhấn lần 5: quay lại màu đỏ, cứ thế lặp lại.

Đây là code đầy đủ, viết cho LED RGB cathode chung (chân chung nối GND, xuất HIGH là sáng):

// Code dành cho LED RGB cathode chung: HIGH = sáng, LOW = tắt
// Dùng LED anode chung thì phải đảo HIGH/LOW

// Chân nối với chân R của LED RGB
#define pinLedRed 9
// Chân nối với chân G của LED RGB
#define pinLedGreen 10
// Chân nối với chân B của LED RGB
#define pinLedBlue 11
// Chân nối với nút nhấn (có điện trở kéo xuống 10kΩ)
#define pinButton 2

// Trạng thái trước đó của nút nhấn
boolean lastPinButton = LOW;
// Trạng thái hiện tại của nút nhấn
boolean currentPinButton = LOW;
// Chế độ sáng hiện tại của LED (0 = tắt)
int ledMode = 0;

void setup() {
  pinMode(pinLedRed, OUTPUT);
  pinMode(pinLedGreen, OUTPUT);
  pinMode(pinLedBlue, OUTPUT);
  pinMode(pinButton, INPUT);
}

// Hàm chống dội phím: đọc lại nút sau 20 ms nếu trạng thái thay đổi
boolean debounce(boolean lastState) {
  boolean currentState = digitalRead(pinButton);
  if (lastState != currentState) {
    delay(20);
    currentState = digitalRead(pinButton);
  }
  return currentState;
}

// Hàm bật LED theo chế độ
void setMode(int mode) {
  if (mode == 1) {          // Nhấn lần 1: màu đỏ
    digitalWrite(pinLedRed, HIGH);
    digitalWrite(pinLedGreen, LOW);
    digitalWrite(pinLedBlue, LOW);
  } else if (mode == 2) {   // Nhấn lần 2: màu xanh lá
    digitalWrite(pinLedRed, LOW);
    digitalWrite(pinLedGreen, HIGH);
    digitalWrite(pinLedBlue, LOW);
  } else if (mode == 3) {   // Nhấn lần 3: màu xanh dương
    digitalWrite(pinLedRed, LOW);
    digitalWrite(pinLedGreen, LOW);
    digitalWrite(pinLedBlue, HIGH);
  } else if (mode == 4) {   // Nhấn lần 4: cả 3 màu sáng dần rồi giữ sáng
    for (int brightness = 0; brightness <= 255; brightness += 5) {
      analogWrite(pinLedRed, brightness);
      analogWrite(pinLedGreen, brightness);
      analogWrite(pinLedBlue, brightness);
      delay(20);
    }
  }
}

void loop() {
  currentPinButton = debounce(lastPinButton);

  // Nút vừa được thả ra (HIGH -> LOW) => tính là 1 lần nhấn
  if (lastPinButton == HIGH && currentPinButton == LOW) {
    ledMode++;
    if (ledMode == 5) {
      ledMode = 1;  // Quay lại màu đỏ
    }
    setMode(ledMode);  // Chỉ đổi màu ngay sau mỗi lần nhấn
  }
  lastPinButton = currentPinButton;
}

Vì sao điều khiển LED RGB với button cần chống dội phím?

Nút nhấn là tiếp điểm cơ khí. Lúc nhấn hoặc thả, hai lá kim loại không chạm nhau ngay mà nảy lên nảy xuống trong vài mili giây. Hiện tượng này gọi là dội phím (bounce).

Mắt chúng ta không thấy, nhưng Arduino thì thấy rõ. Hàm loop() lặp hàng nghìn lần mỗi giây. Mỗi lần tiếp điểm nảy đều bị đọc thành một lần nhấn.

Hiện tượng dội phím khi nhấn nút bấm
Hiện tượng dội phím khi nhấn nút

Muốn tận mắt thấy dội phím, bạn nạp thử đoạn code đếm số lần nhấn dưới đây. Đoạn này chỉ so sánh trạng thái trước và sau, chưa chống dội.

#define pinButton 2

boolean lastState = LOW;  // Trạng thái lần đọc trước
int count = 0;            // Số lần nhấn đếm được

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

void loop() {
  boolean currentState = digitalRead(pinButton);
  // LOW -> HIGH: nút vừa được nhấn xuống
  if (lastState == LOW && currentState == HIGH) {
    count++;
    Serial.println(count);
  }
  lastState = currentState;
}

Mở Serial Monitor rồi nhấn nút đúng 10 lần. Con số in ra lớn hơn 10 nghĩa là nút của bạn đang bị dội. Có nút rung nhiều, có nút gần như không, nên mỗi bạn sẽ thấy một kết quả khác nhau.

Code chạy đúng vài lần chưa chắc là đúng. Chỉ cần đổi sang nút cũ hơn, LED lại nhảy màu lung tung. Vì vậy chống dội là bước bắt buộc, không phải tùy chọn.

Hàm debounce() hoạt động thế nào?

Ý tưởng rất đơn giản: thấy nút đổi trạng thái thì đừng tin ngay. Chờ một chút cho tiếp điểm hết rung rồi đọc lại.

  1. Đọc trạng thái hiện tại của nút vào biến currentState.
  2. So với trạng thái lần trước lastState. Giống nhau thì nút không đổi, trả kết quả về luôn.
  3. Khác nhau thì có thể nút đang rung. Hàm chờ 20 ms bằng delay(20).
  4. Đọc lại nút lần nữa. Lúc này tiếp điểm đã ổn định, kết quả đọc được là trạng thái thật.

Mức 20 ms thường đủ cho nút nhấn nhỏ trong bộ kit Arduino. Nút cũ rung lâu hơn thì bạn tăng lên 50 ms. Đừng tăng quá nhiều, vì trong lúc delay() Arduino không làm được việc gì khác.

Mẹo: Ngoài cách dùng delay(), bạn có thể chống dội bằng millis() để chương trình không bị dừng. Một cách khác là mắc thêm tụ điện song song với nút để lọc nhiễu bằng phần cứng.

Đếm số lần nhấn để đổi chế độ

Trong loop(), biến ledMode tăng 1 khi nút chuyển từ HIGH sang LOW. Với mạch điện trở kéo xuống, nhấn nút là HIGH, thả ra là LOW. Vậy chương trình đếm một lần nhấn ở thời điểm bạn thả nút.

Việc so sánh trạng thái trước và sau chỉ giúp giữ nút lâu không bị đếm liên tục. Nó không lọc được dội phím, vì mỗi lần tiếp điểm nảy cũng tạo ra một cặp HIGH/LOW mới. Do đó hai bước phải đi cùng nhau: debounce() lọc nhiễu trước, sau đó mới so sánh để đếm.

Khi ledMode lên tới 5, ta gán lại về 1 để quay vòng. Lúc mới cấp điện, ledMode bằng 0 nên LED tắt. Hàm setMode() chỉ được gọi ngay sau mỗi lần nhấn, nên hiệu ứng sáng dần ở chế độ 4 chạy đúng một lần rồi giữ sáng.

Hàm setMode() và analogWrite()

Chế độ 1 đến 3 dùng digitalWrite(): bật đúng một màu, tắt hai màu còn lại. Chế độ 4 thì khác. Nó dùng analogWrite() để xuất xung PWM (Pulse Width Modulation – điều chế độ rộng xung).

Giá trị truyền vào từ 0 (tắt) đến 255 (sáng nhất). Vòng for tăng độ sáng mỗi bước 5 đơn vị, nghỉ 20 ms, đến 255 thì dừng và giữ sáng. Cả 3 màu cùng sáng nên LED sẽ ra màu gần trắng.

4. Bài tập

  1. Giữ nút 2 giây để tắt LED, giống nút nguồn của nhiều thiết bị. Nhấn nhanh vẫn đổi màu như cũ. Gợi ý: dùng millis() đo thời gian giữ nút.
  2. Nhấn lúc nào cũng ăn. Chế độ 4 dùng delay() nên lúc LED đang sáng dần, nhấn nút có thể bị bỏ qua. Hãy viết lại bằng millis() để nút luôn phản hồi ngay.
Tác giả

HV Lee

500+ bài viết về lập trình, phần cứng, mạng máy tính và công nghệ. Chia sẻ kiến thức từ những gì đã học, đã dạy và đã trải nghiệm — để người học CNTT hiểu sâu hơn và làm được nhiều hơn.

Gợi ý tiếp theo

Cài đặt Python và môi trường lập trình với Visual Studio Code

Học tiếp