Connecting Bluetooth with Arduino requires either a UART-based external module (like the HC-05 for Classic SPP or HM-10 for BLE) wired via a logic-level voltage divider, or upgrading to an ESP32 for native BLE. The physical layer for external modules is almost always asynchronous serial (UART). If you are using a 5V Arduino Uno or Nano with a 3.3V Bluetooth module, you must drop the TX voltage to prevent frying the module's RX pin. Below is the exact physical wiring, bus mechanics, and code required to establish a reliable wireless serial link.
Physical Layer and UART Bus Mechanics
Unlike I2C or SPI, UART is a point-to-point asynchronous protocol. It does not use a shared clock line, meaning both the Arduino and the Bluetooth module must agree on the baud rate beforehand. Furthermore, UART TX/RX lines do not require pull-up resistors for data transmission. However, the HC-05 EN/KEY pin requires a pull-up to 3.3V to force the module into AT command mode on boot.
The HC-05 breakout board's VCC pin has an onboard LDO regulator (usually an AMS1117-3.3) allowing you to power it from the Arduino's 5V pin. However, the logic pins operate strictly at 3.3V. Sending 5V from the Arduino's TX pin directly into the HC-05's RX pin will degrade or destroy the module over time. You must use a voltage divider on the Arduino TX to Module RX line.
| Parameter | Specification | Notes & Constraints |
|---|---|---|
| Wires Required | 4 (VCC, GND, TX, RX) | EN/KEY and STATE are optional for basic data mode. |
| Bus Speed (Baud) | 9600 bps (Default Data) 38400 bps (AT Mode) |
Configurable up to 1382400 bps via AT commands, but 9600 is standard for SoftwareSerial. |
| Addressing | MAC Address Pairing | No bus addresses like I2C; point-to-point pairing only. |
| Max Distance | ~10 meters (33 ft) | Class 2 radio. Line-of-sight can reach 30m; walls drop this to <5m. |
| Pull-up Requirements | None on TX/RX | EN pin needs 3.3V pull-up only when entering AT mode. |
Required Voltage Divider Wiring:
Use a 1kΩ resistor in series with the Arduino TX pin, and a 2kΩ resistor from the HC-05 RX pin to GND. This yields exactly 3.33V at the module's RX pin when the Arduino outputs 5V. The Module TX to Arduino RX line can be connected directly, as the Arduino's ATmega328P reliably reads 3.3V as a logical HIGH.
Minimal Working Exchange: HC-05 SPP Wiring and Code
To get a minimal working exchange, we will use the Arduino SoftwareSerial library. This allows us to keep the hardware serial port (Pins 0 and 1) free for debugging via the Serial Monitor.
Wiring Table (Arduino Uno to HC-05):
- HC-05 VCC → Arduino 5V
- HC-05 GND → Arduino GND
- HC-05 TX → Arduino Pin 10 (SoftwareSerial RX)
- HC-05 RX → Voltage Divider Midpoint (Arduino Pin 11 via 1kΩ resistor)
#include <SoftwareSerial.h>
// Pin 10 is RX, Pin 11 is TX on the Arduino side
SoftwareSerial BTSerial(10, 11);
void setup() {
// Initialize hardware serial for PC debugging
Serial.begin(9600);
Serial.println("Enter AT commands or serial data:");
// Initialize software serial for HC-05 (Default baud is 9600)
BTSerial.begin(9600);
}
void loop() {
// Read from Bluetooth module and send to Serial Monitor
if (BTSerial.available()) {
Serial.write(BTSerial.read());
}
// Read from Serial Monitor and send to Bluetooth module
if (Serial.available()) {
BTSerial.write(Serial.read());
}
}
Upload this sketch, open the Serial Monitor at 9600 baud (with 'No line ending' or 'Both NL & CR' depending on your target app), and pair your phone or PC to the HC-05 (default PIN is usually 1234 or 0000). Any text typed in the monitor will be transmitted over Bluetooth, and vice versa.
Debugging the Bus: Sniffing and Classic Failures
When Bluetooth with Arduino fails, it is almost always a physical layer or baud rate mismatch. Here is how to diagnose the classic failures.
The Classic Failures
- Baud Rate Mismatch: The HC-05 operates at 9600 baud in data mode, but defaults to 38400 baud in AT command mode. If you are sending AT commands but your
SoftwareSerialis initialized at 9600, you will receive garbage characters. Always verify the module's state (blinking LED pattern) and match the baud rate. - Missing Voltage Divider: If the module pairs but drops connection randomly, or the RX pin reads 0V, the 5V logic from the Arduino has likely damaged the module's input protection diodes. Replace the module and add the 1k/2k divider.
- Power Brownouts: The HC-05 draws ~30mA idle but spikes to 50mA+ during pairing and transmission. If powered from a weak USB hub or a 3.3V LDO with insufficient current, the module will reset mid-transmission. Power it directly from the Arduino's 5V rail, ensuring your USB source can supply at least 500mA.
How to Sniff and Debug the Bus
If the Arduino is transmitting but the receiving device sees nothing, you need to sniff the UART lines. Do not guess; measure.
- Logic Analyzer: Connect a cheap 24MHz 8-channel USB logic analyzer (compatible with PulseView/sigrok) to the TX and RX lines. Set the decoder to UART, 9600 baud, 8N1. This will visually show you if the Arduino is actually pushing bytes onto the wire.
- Hardware Serial Bridge: If you are using an Arduino Mega (which has multiple hardware serial ports), connect the HC-05 to
Serial1(Pins 18/19) instead of SoftwareSerial. Hardware serial is vastly more reliable at higher baud rates and eliminates software timing jitter that causes dropped bytes at 38400+ baud. - Direct USB-Serial Test: Bypass the Arduino entirely. Use an FTDI FT232RL USB-to-Serial adapter, wire it to the HC-05 (with a voltage divider on the FTDI TX line), and use a terminal program like PuTTY or TeraTerm on your PC to verify the module itself is functional.
Protocol Selection: Distance, Speed, and Device Count
Not all wireless protocols fit every use case. If you are deciding which protocol fits your distance, speed, and device count requirements, use this framework.
| Criteria | Bluetooth Classic SPP (HC-05) | Bluetooth Low Energy (HM-10 / ESP32) | Wi-Fi (ESP8266 / ESP32) |
|---|---|---|---|
| Max Distance | ~10m (Class 2) | ~15-30m (with clear line of sight) | ~30-50m (depends heavily on AP) |
| Throughput Speed | 1-2 Mbps (Actual ~115kbps serial) | 1 Mbps (Actual ~10-20kbps payload) | 72 Mbps (Actual 1-5 Mbps TCP/UDP) |
| Device Count (1-to-Many) | 1-to-1 (Point to Point only) | 1-to-Many (Broadcast / GATT) | 1-to-Many (MQTT / WebSockets) |
| Power Consumption | High (~30mA active) | Ultra-Low (<1mA sleep, 15mA peak) | High (~80mA active, 20µA deep sleep) |
| Best Use Case | Legacy serial terminal apps, RC cars | Battery-powered sensor beacons, iOS apps | High-bandwidth data logging, cloud IoT |
For modern projects in 2026, native ESP32 BLE is generally preferred over the HM-10 module due to the ESP32's lower cost, dual-core processing, and robust Espressif BLE stack. However, if you must interface with legacy industrial equipment that expects a raw RFCOMM serial port, the HC-05 remains the standard bridge.
Frequently Asked Questions
Can I connect multiple Bluetooth modules to one Arduino?
No, not using standard UART modules like the HC-05. UART is strictly point-to-point. To communicate with multiple devices simultaneously, you must use Bluetooth Low Energy (BLE) in a broadcast/beacon mode, or switch to a Wi-Fi module running an MQTT client, which inherently supports one-to-many pub/sub architectures.
Why does my HC-05 blink continuously but won't pair with my iPhone?
This is the most common issue when interfacing Bluetooth with Arduino. Apple's iOS does not support the Bluetooth Classic Serial Port Profile (SPP) used by the HC-05. iOS only supports Bluetooth Low Energy (BLE) or MFi-certified Classic devices. To connect an Arduino to an iPhone, you must use a BLE module like the HM-10, an Adafruit Bluefruit LE, or an ESP32 running BLE.
How do I put the HC-05 into AT command mode?
There are two methods. First, press and hold the tiny pushbutton on the HC-05 breakout board while applying power, then release it once the LED starts blinking slowly (once every 2 seconds). Second, if your board lacks a button, wire the EN/KEY pin to 3.3V before powering the module. Once in AT mode, remember to change your SoftwareSerial baud rate to 38400 to send commands like AT+NAME or AT+PSWD.
Is Bluetooth with Arduino reliable for industrial sensor logging?
For short-range, local diagnostics (e.g., a technician walking up to a machine with a tablet), Bluetooth Classic SPP is highly reliable. However, for continuous, unattended 24/7 sensor logging, Bluetooth is a poor choice due to pairing state fragility and lack of native routing. For industrial logging, use an RS-485 bus for wired reliability, or an ESP32 pushing data via Wi-Fi/MQTT to a local broker, adhering to standard Bluetooth SIG limitations regarding continuous high-duty-cycle connections.






