ESP32-C3 SuperMini and buck converter on a breadboard driving a glowing WS2812B RGB LED strip, controlled from a phone color-picker app

ระดับกลาง

สร้าง LED ควบคุมด้วยโทรศัพท์ผ่านบลูทูธ

ไร้สายจอแสดงผลIoT

ควบคุม LED สีสันสดใสได้จากโทรศัพท์ของคุณผ่านบลูทูธโดยตรง ไม่ต้องใช้อุปกรณ์ไร้สายแยกต่างหาก

รวมชิ้นส่วนจริง 6 รายการ

ราคารวมชุดนี้: 1,555.00 ฿

ยังไม่รวมส่วนลดคำสั่งซื้อที่คุณอาจได้รับตอนชำระเงิน

สิ่งที่คุณต้องใช้

เป้าหมายของโปรเจกต์

โปรเจกต์นี้จะเปลี่ยนบอร์ดควบคุมราคาประหยัดธรรมดาให้เป็นตัวควบคุมไฟ RGB แบบไร้สายที่คุณสามารถควบคุมได้โดยตรงจากโทรศัพท์ของคุณ — ไม่ต้องใช้อุปกรณ์เสริมเฉพาะแอปพลิเคชัน ไม่ต้องใช้โมดูลไร้สายเพิ่มเติม คุณจะเชื่อมต่อผ่าน Bluetooth Low Energy (BLE) ส่งค่าสีหรือความสว่างจากแอปบนโทรศัพท์ และดูแถบ LED จริงตอบสนองแบบเรียลไทม์

ตัวควบคุมทำอะไรได้บ้าง

ESP32-C3 เป็นสมองของโปรเจกต์ทั้งหมด และเหมาะสมอย่างยิ่งด้วยเหตุผลเฉพาะ: มันมี Bluetooth 5 (BLE) ในตัวชิปโดยตรง ไม่ต้องมีโมดูล Bluetooth แยกต่างหากเพื่อเดินสายหรือกำหนดค่า — บอร์ดเดียวกันที่รันโปรแกรมของคุณยังจัดการวิทยุไร้สายอีกด้วย หน้าที่ของตัวควบคุมมีสามประการ: โฆษณาตัวเองผ่าน BLE เพื่อให้โทรศัพท์ค้นหาได้, ฟังค่าที่เข้ามาที่เขียนไปยัง BLE characteristic, และแปลค่าเหล่านั้นเป็นคำสั่งสำหรับแถบ LED

แถบ LED ทำอะไรได้บ้าง

แถบ WS2812B เป็นแถบ LED RGB ที่สามารถระบุตำแหน่งแต่ละดวงได้ — LED แต่ละดวงมีชิปไดรเวอร์ขนาดเล็กในตัว ดังนั้นตัวควบคุมจึงสามารถตั้งค่า LED แต่ละดวงให้มีสีของตัวเองได้ แทนที่จะส่องสว่างทั้งแถบด้วยสีเดียว ข้อมูลทั้งหมดจะถูกส่งผ่านสายข้อมูลเส้นเดียว, สตรีมบิตเดียว, ตามลำดับ, จาก LED ดวงแรกไปจนถึงดวงสุดท้าย

Buck Converter ทำอะไรได้บ้าง

หน้าที่ของ LM2596 buck converter ที่นี่เกี่ยวกับพลังงานล้วนๆ ไม่ใช่ข้อมูล แถบที่มี LED จำนวนมากสว่างพร้อมกันสามารถดึงกระแสไฟได้มากกว่าที่ตัวควบคุมบนบอร์ดจะสามารถจ่ายได้ — ตัวควบคุมนั้นมีขนาดสำหรับตรรกะของตัวควบคุมเอง ไม่ใช่สำหรับขับเคลื่อนแถบ LED Buck converter จะลดแรงดันและจ่ายกระแสไฟที่สะอาดและเพียงพอให้กับแถบ LED บนเส้นทางพลังงานเฉพาะของตัวเอง แยกจากพลังงานตรรกะของตัวควบคุม ดังนั้นแถบจึงได้รับสิ่งที่ต้องการโดยไม่ทำให้ตัวควบคุมขาดพลังงานหรือดับ

BLE เชื่อมต่อโทรศัพท์กับตัวควบคุมได้อย่างไร

ในระดับง่ายๆ: ESP32 จะโฆษณา "บริการ" BLE ที่มี "คุณสมบัติ" หนึ่งอย่างหรือมากกว่า — ลองนึกถึงคุณสมบัติว่าเป็นกล่องจดหมายขนาดเล็กที่มีชื่อที่ตัวควบคุมกำลังเฝ้าดูอยู่ แอปบนโทรศัพท์จะสแกนหาอุปกรณ์, เชื่อมต่อ, และเขียนค่าลงในกล่องจดหมายนั้น — ตัวอย่างเช่น, สีเป็นสามไบต์ RGB, หรือไบต์ความสว่างเดียว โค้ดของตัวควบคุมเพียงแค่รอให้กล่องจดหมายนั้นเปลี่ยนแปลง; เมื่อเป็นเช่นนั้น, มันจะอ่านค่าใหม่และอัปเดตสิ่งที่ส่งไปยังแถบ LED ไม่จำเป็นต้องมีวงจรการสำรวจบนฝั่งโทรศัพท์และไม่จำเป็นต้องประดิษฐ์โปรโตคอลไร้สายที่กำหนดเอง — BLE จะจัดการการเชื่อมต่อและการจัดส่ง, โค้ดของคุณเพียงแค่ตัดสินใจว่าจะทำอะไรกับไบต์ที่ได้รับ

แนวคิดซอฟต์แวร์และไลบรารี

คุณจะใช้ประโยชน์จากไลบรารีสองตัวที่แยกจากกันและเป็นที่ยอมรับอย่างดีที่นี่: ไลบรารีเซิร์ฟเวอร์ BLE เพื่อจัดการการโฆษณาและเหตุการณ์การอ่าน/เขียนลักษณะเฉพาะ และไลบรารี LED ที่สามารถระบุตำแหน่งได้เพื่อจัดการโปรโตคอลข้อมูลและเวลาของแถบ รักษาข้อกังวลทั้งสองให้แยกจากกันในโค้ดของคุณ — ฟังก์ชันเรียกกลับ BLE ที่เพียงแค่จัดเก็บค่าที่เข้ามา และลูปหลัก (หรือเรียกกลับที่สอง) ที่ใช้ค่าที่จัดเก็บปัจจุบันกับแถบ ทำให้แต่ละไลบรารีทำงานได้ด้วยตัวเองด้วยค่าทดสอบที่ฮาร์ดโค้ดก่อนที่จะนำมารวมกัน

การทดสอบและการแก้ไขปัญหา

  • โทรศัพท์ไม่สามารถค้นหาหรือเชื่อมต่อกับอุปกรณ์ได้ — ตรวจสอบให้แน่ใจว่าโค้ดโฆษณา BLE กำลังทำงานอยู่จริง และชื่ออุปกรณ์/UUID บริการในโค้ดของคุณตรงกับสิ่งที่แอปของคุณกำลังสแกนหา
  • ไฟ LED ไม่ตอบสนองแม้ว่าโทรศัพท์จะแสดงว่า "เชื่อมต่อแล้ว" — ตรวจสอบการเดินสายของพินข้อมูลของแถบ LED ก่อน จากนั้นยืนยันความเข้ากันได้ของระดับตรรกะระหว่างเอาต์พุตของตัวควบคุมและอินพุตข้อมูลของแถบ
  • สี LED ออกมาผิด — ตัวอย่างเช่น สีแดงแสดงเป็นสีเขียว — นี่เป็นข้อผิดพลาดทั่วไปของ WS2812B: การตั้งค่าลำดับสีไม่ตรงกัน (RGB เทียบกับ GRB) ในไลบรารี LED ตรวจสอบการตั้งค่านั้นก่อนที่จะสันนิษฐานว่าเกิดความผิดปกติของฮาร์ดแวร์
  • การเชื่อมต่อหลุดบ่อยครั้งหรือค่ามาถึงแต่ดูเหมือนจะล่าช้า — ยืนยันว่าคุณไม่ได้บล็อกการเรียกกลับ BLE ด้วยโค้ดที่ช้า (เช่น การหน่วงเวลานาน) ภายในตัวจัดการการเขียนเอง; ทำให้ตัวจัดการนั้นทำงานเร็วและปล่อยให้ลูปหลักทำงานที่หนักกว่า

การอัปเกรดในอนาคต (ทางเลือก): โซนแสงหลายโซน

เมื่อการควบคุมสีและความสว่างของแถบเดียวมั่นคงแล้ว ขั้นตอนต่อไปคือการระบุช่วงย่อยของแถบเดียวกันเป็นโซนอิสระ — การส่งดัชนีโซนพร้อมกับค่าสีผ่าน BLE และอัปเดตเฉพาะส่วนนั้นของแถบในโค้ด — โดยไม่ต้องเพิ่มฮาร์ดแวร์ใหม่ใดๆ

การเดินสาย

  • แหล่งจ่ายไฟ DC ภายนอก (ข้ามหากเป็น 5V อยู่แล้ว) → LM2596 IN+ / IN−
  • LM2596 OUT+ → แถบ WS2812B 5V (ปรับ LM2596 ให้เป็น 5.0V ที่ผ่านการตรวจสอบแล้วก่อนเชื่อมต่อแถบ)
  • LM2596 OUT− → แถบ WS2812B GND, เชื่อมต่อกับ ESP32-C3 GND (กราวด์ร่วม)
  • WS2812B DIN → ESP32-C3 SuperMini GPIO5, ผ่านตัวต้านทาน ~330–470Ω แบบอนุกรม

ESP32-C3 รองรับเฉพาะ BLE (Bluetooth Low Energy) ไม่ใช่ Bluetooth รุ่นเก่า ดังนั้นจึงจะไม่ปรากฏเป็นเป้าหมายการจับคู่แบบ "ลำโพง Bluetooth" ทั่วไป — คุณเชื่อมต่อกับมันด้วยแอปที่รองรับ BLE (เครื่องมือ GATT ทั่วไปเช่น nRF Connect เป็นวิธีที่เร็วที่สุดในการทดสอบคุณสมบัติก่อนที่จะสร้างแอปโทรศัพท์ที่กำหนดเอง) UUID ของบริการ/คุณสมบัติ ด้านล่างเป็นเพียง UUID กำหนดเองโดยพลการ (เป็นแนวทางปฏิบัติมาตรฐาน — สร้างของคุณเองด้วยเครื่องมือสร้าง UUID ใดๆ สำหรับผลิตภัณฑ์จริง); พวกเขาเพียงแค่ต้องตรงกันระหว่างเฟิร์มแวร์นี้กับแอปใดก็ตามที่คุณเขียน ตัวจัดการการเขียนยอมรับได้ทั้ง 3 ไบต์ดิบ (R,G,B) หรือคำสั่งข้อความเช่น `"255,0,0"` ดังนั้นให้ทดสอบทั้งสองวิธีขึ้นอยู่กับสิ่งที่ไคลเอนต์ BLE ของคุณส่ง

แผนภาพการต่อสาย

IN− OUT+ → 5V OUT− → GND DIN → GPIO5 ESP32-C3 SuperMini WS2812B LM2596 External DC supply

โค้ดเริ่มต้น

#include <Adafruit_NeoPixel.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

#define LED_DATA_PIN 5
#define NUM_LEDS 30

#define SERVICE_UUID        "5f1a3a2e-6b0e-4a7a-9b6e-2b6e2f3a9d10"
#define CHARACTERISTIC_UUID "5f1a3a2f-6b0e-4a7a-9b6e-2b6e2f3a9d10"

Adafruit_NeoPixel strip(NUM_LEDS, LED_DATA_PIN, NEO_GRB + NEO_KHZ800);
BLECharacteristic *pColorCharacteristic;
bool deviceConnected = false;

void setStripColor(uint8_t r, uint8_t g, uint8_t b) {
  uint32_t color = strip.Color(r, g, b);
  for (int i = 0; i < NUM_LEDS; i++) {
    strip.setPixelColor(i, color);
  }
  strip.show();
}

class ServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer *pServer) override {
    deviceConnected = true;
    Serial.println("BLE client connected");
  }
  void onDisconnect(BLEServer *pServer) override {
    deviceConnected = false;
    Serial.println("BLE client disconnected — advertising again");
    pServer->getAdvertising()->start();
  }
};

class ColorWriteCallback : public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *pCharacteristic) override {
    std::string value = pCharacteristic->getValue();
    if (value.length() == 0) return;

    uint8_t r = 0, g = 0, b = 0;

    if (value.length() == 3) {
      // Raw RGB byte triplet
      r = (uint8_t)value[0];
      g = (uint8_t)value[1];
      b = (uint8_t)value[2];
    } else {
      // Text command like "255,0,0"
      int r1, g1, b1;
      if (sscanf(value.c_str(), "%d,%d,%d", &r1, &g1, &b1) == 3) {
        r = constrain(r1, 0, 255);
        g = constrain(g1, 0, 255);
        b = constrain(b1, 0, 255);
      } else {
        Serial.println("Unrecognized color command");
        return;
      }
    }

    Serial.printf("Setting color: R=%d G=%d B=%d\n", r, g, b);
    setStripColor(r, g, b);
  }
};

void setup() {
  Serial.begin(115200);

  strip.begin();
  strip.setBrightness(180);
  setStripColor(0, 0, 0);

  BLEDevice::init("ESP32 LED Controller");
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new ServerCallbacks());

  BLEService *pService = pServer->createService(SERVICE_UUID);
  pColorCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE
  );
  pColorCharacteristic->setCallbacks(new ColorWriteCallback());
  pColorCharacteristic->addDescriptor(new BLE2902());

  pService->start();

  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->start();

  Serial.println("BLE advertising started.");
}

void loop() {
  // All the work happens in the BLE write callback
  delay(20);
}

ไม่แน่ใจขั้นตอนไหน? ถามเรา