To establish a reliable Bluetooth Arduino to Arduino link, you are not actually writing a wireless protocol from scratch; you are building a transparent wireless UART bridge. By using Classic Serial Port Profile (SPP) modules like the HC-05, the microcontrollers communicate via standard hardware serial (TX/RX), while the module handles the 2.4 GHz ISM band RF modulation and packetization. The direct answer for a robust point-to-point link is to use two HC-05 modules (one configured as Master, one as Slave), bind them via their MAC addresses using AT commands, and shift the 5V Arduino logic down to the module's 3.3V RX threshold using a simple resistor divider.

The Physical Layer: UART Bridge Mechanics & Wiring

Before writing a single line of code, you must understand that Bluetooth SPP modules act as dumb serial pipes. The "bus" is actually two distinct layers: the local wired UART bus between the ATmega328P and the HC-05, and the wireless RF link between the two HC-05 modules. If the physical UART layer fails, the RF layer never gets the data to transmit.

Table 1: Bus Mechanics & RF Specifications (HC-05 vs JDY-31 BLE)
Parameter Local UART (Wired) Classic SPP (HC-05 RF) BLE 4.0 (JDY-31 RF)
Physical Wires 4 (VCC, GND, TX, RX) N/A (Wireless) N/A (Wireless)
Max Speed (Baud) Up to 115,200 bps ~1380 bps effective payload Variable, MTU dependent
Addressing None (Point-to-Point) 48-bit MAC Address UUID / MAC Address
Max Distance ~15 meters (cable) ~10 meters (Class 2) ~30 meters (Line of sight)
Logic Level 5V (Arduino) / 3.3V (Module) N/A N/A

Mandatory Voltage Division (The Pull-Up/Logic Shift)

The most common hardware failure in these projects is frying the HC-05's RX pin. The Arduino Uno outputs 5V on its TX pin, but the HC-05 operates at 3.3V logic. While the HC-05's VCC pin can tolerate 5V (due to an onboard regulator), its data pins cannot. You must drop the 5V TX signal to ~3.3V.

  • Arduino TX to HC-05 RX: Pass through a voltage divider. Use a 1kΩ resistor in series from Arduino TX, and a 2kΩ resistor pulling down from the HC-05 RX pin to GND. This yields exactly 3.33V.
  • HC-05 TX to Arduino RX: Connect directly. The Arduino's ATmega328P reads any voltage above 2.5V as a logical HIGH, so the HC-05's 3.3V output is perfectly safe and readable without a pull-up.
Warning: Never connect a 5V Arduino TX pin directly to a 3.3V Bluetooth module RX pin. While it might work for a few hours, it will eventually degrade the module's internal ESD diodes and cause silent packet corruption or total silicon failure.

Protocol Selection: Classic SPP vs. BLE for Arduino Links

Which protocol fits your distance, speed, and device count requirements? For a simple Arduino-to-Arduino link where you want to replace a physical serial cable, Classic SPP (HC-05) is the undisputed winner. It requires no custom mobile app or complex GATT characteristic mapping; it just passes raw bytes. However, if you need to connect to modern iOS devices or require lower power consumption, you must pivot to BLE.

Table 2: Protocol Selection Matrix for Embedded Links
Criteria Classic SPP (HC-05) BLE (JDY-31 / HM-10) ESP-NOW (ESP32 Native)
Best For Arduino-to-Arduino cable replacement Arduino-to-Smartphone telemetry High-speed, multi-node mesh
Device Count 1 Master to 1 Slave (Bound) 1 Central to multiple Peripherals Up to 20 peers
Pairing Method AT Command MAC Binding OS-level BLE Pairing / App MAC Address Registration in Code
iOS Compatibility No (Apple blocks SPP) Yes No (Proprietary)

Configuration, Pairing, and the Minimal Working Exchange

To create a dedicated Arduino-to-Arduino link, you must bind the Master HC-05 to the Slave HC-05's MAC address. This prevents the Master from connecting to random nearby Bluetooth devices.

Step 1: AT Command Binding

Connect the Slave HC-05 to a USB-Serial adapter, pull the EN/KEY pin HIGH, and power it on to enter AT mode (default baud 38400). Send AT+ADDR? to get its MAC address (e.g., 98:D3:34:90:5C:33).
Next, configure the Master HC-05 in AT mode:

AT+ROLE=1       // Set as Master
AT+BIND=98d3,34,905c33  // Bind to Slave MAC (Note: use commas, not colons)
AT+CMODE=0      // Connect only to bound address
AT+RESET        // Reboot into transparent mode
Pro-Tip: The HC-05 firmware expects the MAC address in NAP, UAP, LAP format separated by commas. If you use colons (e.g., 98:D3...), the module will return an ERROR and fail to bind.

Step 2: Minimal Working Exchange Code

Once paired, the modules act as a transparent wire. We use SoftwareSerial on the Uno to leave the hardware UART free for debugging via the Serial Monitor. This code sends a counter from the Master and expects an acknowledgment from the Slave.

// MASTER ARDUINO CODE
#include <SoftwareSerial.h>

// Pin 10 = RX (from HC-05 TX), Pin 11 = TX (to HC-05 RX via voltage divider)
SoftwareSerial BTSerial(10, 11); 

int packetCount = 0;

void setup() {
  Serial.begin(9600);      // Debug monitor
  BTSerial.begin(9600);    // HC-05 default transparent baud
  Serial.println("Master initialized. Waiting for link...");
}

void loop() {
  // Send payload
  BTSerial.print("PING:");
  BTSerial.println(packetCount);
  Serial.print("Sent PING: ");
  Serial.println(packetCount);
  
  // Wait for ACK with timeout
  unsigned long timer = millis();
  while(millis() - timer < 1000) {
    if(BTSerial.available()) {
      String response = BTSerial.readStringUntil('\n');
      Serial.print("Received: ");
      Serial.println(response);
      break;
    }
  }
  
  packetCount++;
  delay(2000);
}
// SLAVE ARDUINO CODE
#include <SoftwareSerial.h>

SoftwareSerial BTSerial(10, 11);

void setup() {
  Serial.begin(9600);
  BTSerial.begin(9600);
  Serial.println("Slave listening...");
}

void loop() {
  if(BTSerial.available()) {
    String incoming = BTSerial.readStringUntil('\n');
    Serial.print("Got: ");
    Serial.println(incoming);
    
    // Send Acknowledgment
    BTSerial.println("ACK:OK");
  }
}

Debugging the Airwaves: Classic Failures and Bus Sniffing

When your Bluetooth link drops packets or refuses to connect, the issue is almost never "Bluetooth interference." It is almost always a local UART configuration error. Here is how to diagnose the classic failures.

The Classic Failures

  1. Baud Rate Mismatch: The HC-05 defaults to 9600 bps in transparent (data) mode, but switches to 38400 bps when entering AT command mode. If your Arduino code initializes SoftwareSerial.begin(38400) for normal data transfer, you will receive garbage characters. Always use 9600 for the sketch, and 38400 only for AT configuration.
  2. Unbound MAC Addresses: If you set AT+ROLE=1 but forget AT+CMODE=0, the Master will attempt to connect to the first SPP device it finds (often a nearby laptop or phone), leaving your Slave Arduino ignored.
  3. Power Supply Brownouts: The HC-05 draws up to 50mA during transmission bursts. If powered directly from the Arduino Uno's 3.3V regulator (which is only rated for ~50mA), the voltage will sag, causing the module to reset mid-packet. Always power the HC-05 VCC pin from the Arduino's 5V pin.

How to Sniff and Debug the Bus

Because Classic SPP uses proprietary RF hopping sequences, you cannot easily sniff the 2.4 GHz airwaves without a $500 spectrum analyzer. Instead, sniff the local UART bus.

To debug, take a third Arduino or a $12 USB-to-TTL adapter (like an FT232RL breakout). Connect its RX pin directly to the wire bridging your transmitting Arduino's TX pin and the HC-05's RX pin. Open a serial terminal on your PC at 9600 baud. You will now see exactly what the Arduino is pushing to the Bluetooth module. If the data looks correct on your PC sniff, but doesn't arrive at the remote Arduino, the issue is RF pairing (check your AT+BIND MAC address). If the data looks like garbage on your PC sniff, your local baud rate or voltage divider is at fault.

For deeper module diagnostics, you can temporarily wire the HC-05's STATE pin to an Arduino input. The STATE pin goes HIGH when a Bluetooth link is successfully established. Polling this pin in your setup() loop prevents your code from firing serial data into the void before the RF handshake is complete.

For more on the underlying serial mechanics, refer to the Arduino SoftwareSerial documentation and the foundational UART theory guide on All About Circuits.