The HC-05 is a natural fit for the Leonardo, because the Leonardo’s D0/D1 are a free hardware UART (Serial1) — USB has its own port inside the chip. No SoftwareSerial, no unplugging the module to upload.
Wire TXD → D0 directly and D1 → RXD through a divider. The sketch bridges the phone and the Serial Monitor and switches the on-board LED when the phone sends 1 or 0.
Wiring
| Arduino Leonardo | HC-05 Bluetooth serial module | Wire | Notes |
|---|---|---|---|
| 5V | VCC | red | |
| GND | GND | black | |
| D0 | TXD | green | HC-05 TX → D0 (RX of Serial1). |
| D1 | RXD | yellow | Via 1 kΩ / 2 kΩ divider — D1 (TX of Serial1) → HC-05 RX, 5 V brought down to ~3.3 V. |
3.6–6 V on VCC (on-board 3.3 V regulator) — power from 5 V part, 5 V board. The module runs at 3.3 V logic. Its TXD connects straight to any board’s RX. Its RXD must not see 5 V: from an Uno or Nano TX, use a 1 kΩ / 2 kΩ divider. From ESP32 or Pico, connect directly.
Board quirks
- On the Leonardo, Serial is the native USB port and Serial1 is D0/D1. Unlike an Uno, the HC-05 can sit on D0/D1 permanently — uploads go over native USB and are not disturbed.
- Uno sketches that use
Serialfor the HC-05 must change toSerial1on a Leonardo. while (!Serial && millis() < 3000)waits for the PC briefly; the barewhile (!Serial);would hang forever when the robot runs on batteries.- The sketch writes to USB Serial only while a PC has the port open (
if (Serial)), so the Bluetooth side keeps working when it is unplugged.
Code
// HC-05 Bluetooth on an Arduino Leonardo's hardware Serial1 (D0 = RX, D1 = TX).
// HC-05 TXD → D0, RXD ← D1 through a 1 kΩ / 2 kΩ divider, VCC → 5V, GND → GND.
// USB Serial is native on the Leonardo, so D0/D1 are free — no SoftwareSerial needed.
// Bridges the phone and the Serial Monitor; 1 / 0 from the phone switches the on-board LED.
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(115200);
while (!Serial && millis() < 3000) {} // works on a charger too: gives up after 3 s
Serial1.begin(9600); // HC-05 data-mode default
Serial.println(F("HC-05 on Serial1 - pair the phone, then send 1 or 0"));
}
void loop() {
while (Serial1.available()) {
char c = Serial1.read();
if (c == '1') digitalWrite(LED_BUILTIN, HIGH);
if (c == '0') digitalWrite(LED_BUILTIN, LOW);
if (Serial) Serial.write(c); // only when a PC has the port open
}
while (Serial.available()) Serial1.write(Serial.read());
}// HC-05 Bluetooth on an Arduino Leonardo's hardware Serial1 (D0 = RX, D1 = TX).
// HC-05 TXD → D0, RXD ← D1 through a 1 kΩ / 2 kΩ divider, VCC → 5V, GND → GND.
// USB Serial is native on the Leonardo, so D0/D1 are free — no SoftwareSerial needed.
// Bridges the phone and the Serial Monitor; 1 / 0 from the phone switches the on-board LED.
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(115200);
while (!Serial && millis() < 3000) {} // works on a charger too: gives up after 3 s
Serial1.begin(9600); // HC-05 data-mode default
Serial.println(F("HC-05 on Serial1 - pair the phone, then send 1 or 0"));
}
void loop() {
while (Serial1.available()) {
char c = Serial1.read();
if (c == '1') digitalWrite(LED_BUILTIN, HIGH);
if (c == '0') digitalWrite(LED_BUILTIN, LOW);
if (Serial) Serial.write(c); // only when a PC has the port open
}
while (Serial.available()) Serial1.write(Serial.read());
}Expected serial output
HC-05 on Serial1 - pair the phone, then send 1 or 0
1
0
hello from phoneHC-05 on Serial1 - pair the phone, then send 1 or 0 1 0 hello from phone
Common errors
Nothing from the phone
Code still uses Serial for the module. On the Leonardo it must be Serial1.
Sketch doesn’t run on battery power
A bare while (!Serial); waits for a PC forever. Use the timed version from this sketch.