การสร้าง LEDController Class ทำให้โค้ดควบคุม LED มีระเบียบ เป็นระบบ และขยายไปเป็น “ไฟวิ่ง / ไฟเตือน / ไฟสถานะหลายดวง” ได้ง่ายมาก ออกแบบคลาสสำหรับควบคุม LED หนึ่งดวงหรือหลายดวง แล้วใช้ร่วมกับ Button Class จาก EP1.1
🎯 เป้าหมายการเรียนรู้เมื่อจบ EP1.2 นักเรียนจะ:
- เข้าใจแนวคิด “แยกหน้าที่” เป็นคลาส:
Button= จัดการปุ่มLEDController= จัดการไฟ
- ใช้คลาสควบคุม LED ได้ เช่น:
- เปิด/ปิด (On/Off)
- Toggle (สลับสถานะ)
- กระพริบด้วยเวลา (Blink แบบไม่บล็อกด้วย
millis())
- ทำระบบ “ปุ่มกด → ควบคุม LED หลายดวง / หลายรูปแบบ” ได้อย่างเป็นระเบียบ
🧩 1) ทบทวนแนวคิด: แยก “Input Logic” ออกจาก “Output Logic”
- คลาส
Button→ ทำหน้าที่จัดการปุ่ม: debounce, ตรวจ wasPressed(), isPressed() - คลาส
LEDController→ ทำหน้าที่จัดการ LED: on/off/toggle/blink
ข้อดี:
- โค้ดใน
loop()จะอ่านเป็นประโยคภาษาไทยได้เลย: “อัปเดตปุ่ม → ถ้าปุ่มกด → สั่ง LED นี้ toggle หรือ blink”
💻 2) ตัวอย่างคลาส LEDController (แบบควบคุม LED 1 ดวง)
วางคลาสนี้ไว้ด้านบนของไฟล์ .ino
C++
class LEDController {
private:
int pin;
bool state; // ON/OFF ปัจจุบัน
bool blinking; // โหมดกระพริบหรือไม่
unsigned long interval; // ช่วงเวลาการกระพริบ (ms)
unsigned long lastToggle; // เวลาที่เปลี่ยนสถานะล่าสุด
public:
LEDController(int pinNumber) {
pin = pinNumber;
state = false;
blinking = false;
interval = 500;
lastToggle = 0;
}
void begin() {
pinMode(pin, OUTPUT);
off();
}
void on() {
state = true;
blinking = false; // ถ้าเปิดค้าง ให้หยุดโหมดกระพริบ
digitalWrite(pin, HIGH);
}
void off() {
state = false;
blinking = false;
digitalWrite(pin, LOW);
}
void toggle() {
state = !state;
blinking = false;
digitalWrite(pin, state ? HIGH : LOW);
}
void startBlink(unsigned long ms) {
interval = ms;
blinking = true;
lastToggle = millis();
}
void stopBlink() {
blinking = false;
// ไม่บังคับเปลี่ยนสถานะไฟ ให้คงตาม state ปัจจุบัน
digitalWrite(pin, state ? HIGH : LOW);
}
// ต้องเรียกใน loop() เสมอ เพื่อให้โหมด blink ทำงาน
void update() {
if (blinking) {
unsigned long now = millis();
if (now - lastToggle >= interval) {
lastToggle = now;
state = !state;
digitalWrite(pin, state ? HIGH : LOW);
}
}
}
bool isOn() {
return state;
}
};
💡 3) ใช้ร่วมกับ Button Class (รีวิวตัวอย่างย่อจาก EP1.1)
สมมติเรามี Button แบบ EP1.1 (begin(), update(), wasPressed()) ตัวอย่าง:
C++
class Button {
private:
int pin;
bool usePullup;
unsigned long lastChangeTime;
unsigned long debounceMs;
bool lastStableState;
bool currentState;
bool pressedEvent;
public:
Button(int pinNumber, bool enablePullup = true, unsigned long debounce = 50) {
pin = pinNumber;
usePullup = enablePullup;
debounceMs = debounce;
lastChangeTime = 0;
lastStableState = HIGH;
currentState = HIGH;
pressedEvent = false;
}
void begin() {
if (usePullup) {
pinMode(pin, INPUT_PULLUP);
lastStableState = HIGH;
} else {
pinMode(pin, INPUT);
lastStableState = LOW;
}
currentState = lastStableState;
}
void update() {
int reading = digitalRead(pin);
unsigned long now = millis();
pressedEvent = false;
if (reading != currentState) {
currentState = reading;
lastChangeTime = now;
}
if (now - lastChangeTime > debounceMs) {
if (lastStableState != currentState) {
if (usePullup) {
if (lastStableState == HIGH && currentState == LOW) {
pressedEvent = true;
}
} else {
if (lastStableState == LOW && currentState == HIGH) {
pressedEvent = true;
}
}
lastStableState = currentState;
}
}
}
bool wasPressed() {
return pressedEvent;
}
bool isPressed() {
if (usePullup) return (lastStableState == LOW);
else return (lastStableState == HIGH);
}
};
💻 4) ตัวอย่างโปรแกรม: ปุ่ม 1 ปุ่ม ควบคุม LEDController 1 ดวง
โจทย์:
- กดปุ่มครั้งที่ 1 → LED ติดค้าง
- กดครั้งที่ 2 → LED กระพริบช้า (1 วินาที)
- กดครั้งที่ 3 → LED กระพริบเร็ว (200ms)
- กดครั้งที่ 4 → LED ดับ
- แล้ววนลูปกลับไปสถานะแรก
C++
Button btn(4, true, 80); // ปุ่มที่ขา 4, ใช้ PULLUP
LEDController led(2); // LED ที่ขา 2
int mode = 0; // 0 = off, 1 = on, 2 = blink slow, 3 = blink fast
void setup() {
Serial.begin(115200);
btn.begin();
led.begin();
}
void loop() {
btn.update(); // อัปเดตสถานะปุ่ม
led.update(); // ให้ LEDController ทำงานโหมด blink ถ้ามี
if (btn.wasPressed()) {
mode = (mode + 1) % 4; // 0 → 1 → 2 → 3 → 0 → ...
Serial.print("Mode: ");
Serial.println(mode);
switch (mode) {
case 0:
led.off();
break;
case 1:
led.on();
break;
case 2:
led.startBlink(1000); // 1 วินาที
break;
case 3:
led.startBlink(200); // 0.2 วินาที
break;
}
}
}
จะเห็นว่า:
- logics (โหมด, การเปลี่ยนสถานะ) → อยู่ใน
loop() - การจัดการปุ่ม → ฝั่ง
Button - การจัดการ LED → ฝั่ง
LEDController
โค้ดใน loop() เลยอ่านง่ายมาก:
“อัปเดตปุ่ม → ถ้าปุ่มถูกกด → เปลี่ยนโหมด → สั่ง LED”
💡 5) ต่อยอด: หลาย LED + หลายปุ่ม
สมมติครูอยากทำ “ป้ายไฟเล็ก ๆ” หรือ “แผงสถานะ 3 ดวง” แบบนี้:
- ปุ่ม 1: Toggle ไฟ LED1
- ปุ่ม 2: ให้ LED2 กระพริบ
- ปุ่ม 3: ปิดทุกดวง
C++
Button btn1(4, true, 80);
Button btn2(5, true, 80);
Button btn3(18, true, 80);
LEDController led1(2);
LEDController led2(16);
LEDController led3(17);
void setup() {
btn1.begin();
btn2.begin();
btn3.begin();
led1.begin();
led2.begin();
led3.begin();
}
void loop() {
// อัปเดตปุ่มและ LED ทุกตัว
btn1.update();
btn2.update();
btn3.update();
led1.update();
led2.update();
led3.update();
// ปุ่ม 1: toggle LED1
if (btn1.wasPressed()) {
led1.toggle();
}
// ปุ่ม 2: toggle โหมดกระพริบ LED2
if (btn2.wasPressed()) {
if (led2.isOn()) {
led2.startBlink(300);
} else {
led2.on();
}
}
// ปุ่ม 3: ปิดทุกดวง
if (btn3.wasPressed()) {
led1.off();
led2.off();
led3.off();
}
}
🧪 6) แบบฝึกหัด EP1.2
ปรับ LEDController ให้มีฟังก์ชัน
setInterval(ms)เพื่อเปลี่ยนความเร็วตอน blink โดยไม่ต้องเรียกstartBlinkซ้ำ
- ทำ “โหมดไฟจราจร” ด้วย 3 LED:
- แดงติด 3 วิ → เขียวติด 3 วิ → เหลืองติด 1 วิ → วนซ้ำ
- ใช้ปุ่ม 1 ปุ่ม เป็น “สวิตช์เปลี่ยน Pattern”
- Pattern 1 = ไฟจราจร
- Pattern 2 = ไฟวิ่งซ้าย–ขวา
🧠 7) สรุป
| แนวคิด | สรุป |
|---|---|
| การใช้ Class หลายตัว | ทำให้โค้ดแบ่ง “หน้าที่” ชัดเจน |
LEDController | เป็นตัวจัดการไฟ ON/OFF/BLINK |
update() | แนวคิดสำคัญสำหรับงานที่ต้องใช้เวลา (millis(), non-blocking) |
| การชั้นเชิง (Layering) | Input (Button) → Logic (Mode) → Output (LEDController) |
| การขยายโค้ด | เพิ่ม LED/ปุ่มได้โดยไม่ทำให้โค้ดเละ |
