BLE UART LED Remote
Seeed XIAO nRF52840·Arduino C++·Updated Jul 27, 2026·by FluxBench TeamIncludes Lab + Schematic
Control an LED over Bluetooth LE from a phone - the first nRF52 demo in the gallery. The XIAO nRF52840 advertises a BLE UART (Nordic UART Service); in the simulator a virtual phone connects about 2 seconds after boot and sends "led on", "blink" and "led off" every 3 seconds, so you can watch the LED react and the serial monitor echo each command without any hardware. On the real board, open Bluefruit Connect or nRF Connect, attach to FluxBench-BLE and type the same commands. Note the nRF52 gotcha the sketch handles for you: Serial needs #include <Adafruit_TinyUSB.h> on this core or the build fails to link.
sketch.ino
// BLE UART LED Remote - control an LED from your phone over Bluetooth LE.
// Board: Seeed XIAO nRF52840 (Adafruit Bluefruit nRF52 API).
// In the FluxBench simulator there is no real radio: a virtual phone connects
// about 2 seconds after Bluefruit.begin() and then sends the demo commands
// "led on", "blink" and "led off" over the BLE UART every 3 seconds, so you
// can watch the whole connect-receive-act flow without hardware.
// On the real board, use a BLE terminal app (Bluefruit Connect / nRF Connect)
// and type the same commands.
#include <bluefruit.h>
#include <Adafruit_TinyUSB.h> // REQUIRED on this core for Serial to link
#define LED_PIN 2 // D2 - external LED through a 330 ohm resistor
BLEUart bleuart; // BLE UART service (Nordic UART Service)
BLEDis bledis; // Device Information Service
bool wasConnected = false;
bool blinking = false;
bool ledState = false;
unsigned long lastBlink = 0;
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
Bluefruit.begin();
Bluefruit.setTxPower(4);
Bluefruit.setName("FluxBench-BLE");
bledis.setManufacturer("FluxBench");
bledis.setModel("XIAO nRF52840");
bledis.begin();
bleuart.begin();
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
Bluefruit.Advertising.addService(bleuart);
Bluefruit.Advertising.addName();
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244);
Bluefruit.Advertising.setFastTimeout(30);
Bluefruit.Advertising.start(0);
Serial.println("Advertising as FluxBench-BLE ...");
Serial.println("Connect with a BLE terminal and send: led on / led off / blink");
}
void loop() {
if (Bluefruit.connected()) {
if (!wasConnected) {
wasConnected = true;
Serial.println("Central connected!");
}
while (bleuart.available()) {
String cmd = bleuart.readStringUntil('\n');
Serial.print("RX: ");
Serial.println(cmd);
if (cmd.equals("led on")) {
blinking = false;
ledState = true;
digitalWrite(LED_PIN, HIGH);
bleuart.println("OK led is ON");
} else if (cmd.equals("led off")) {
blinking = false;
ledState = false;
digitalWrite(LED_PIN, LOW);
bleuart.println("OK led is OFF");
} else if (cmd.equals("blink")) {
blinking = true;
lastBlink = millis();
bleuart.println("OK blinking");
} else {
bleuart.println("? try: led on / led off / blink");
}
}
} else if (wasConnected) {
wasConnected = false;
Serial.println("Central disconnected - advertising again");
}
if (blinking && millis() - lastBlink >= 250) {
lastBlink = millis();
ledState = !ledState;
digitalWrite(LED_PIN, ledState ? HIGH : LOW);
}
delay(20);
}Built with FluxBench.AI — the AI workbench for embedded projects.