Two HC-05 modules won't stay paired

One HC-05 is connected to an Uno, the other to a Mega. They pair up fine (based on both LEDs blinking twice about 5 seconds apart) after uploading a blank sketch to both, disconnecting them from the laptop, and powering both up, so I believe I have the AT commands correct. The pairing is stable and has good range (other end of the house).

The problem is that the pairing becomes unstable after uploading sketches that include data transfer. On the slave (Uno), I Serial.write a '1' or '0' based on the state of a button. On the master (Mega), I Serial1.read and turn on/off an LED based on the result.

When both sketches have been uploaded, I unhook the laptop and power both boards. The modules initially pair up, and sometimes stay paired long enough to push the button and get the LED to turn on/off. Therefore, it seems the wiring is correct and the code is correct (or close?). Most times, though, the paired-up blinking only lasts 1 or 2 cycles on the master, then goes solid on or solid off, while the slave continues blinking as if it is still paired. The data transfer (button push = LED on) doesn't work, usually. Sometimes it works for a while then they become unpaired. I'm super frustrated! Any help appreciated.

For informed help, do yourself a favor and follow the forum rules. Posting instructions are given in the "How to get the best out of this forum" post, linked at the head of every forum category.

Excellent description of your code. Show your code and draw your circuit.

Don't forget that the HC-05 is a 3.3V only device, and a voltage divider or logic level shifter is required when connecting it to a 5V Arduino. See these tutorials: https://www.martyncurrey.com/

I'm new here and didn't realize there are rules for posting. Where do I find those? Anyway, here is the code. I'll have to work on making drawings of the circuits.

Code for the slave (Uno) module (not sure how the code formatting is supposed to be):

const int button = 8;
int buttonState = 0;

void setup() 
{
  pinMode(button, INPUT);
  Serial.begin(38400); //
}
void loop() 
{
    // Reading the button
    buttonState = digitalRead(button);
        if (buttonState == HIGH) 
        {
        Serial.write('1'); // Sends '1' to the master to turn on LED
        }
        else 
        {
        Serial.write('0');
        }  
}

and here is for the master (Mega) module:

#define ledPin 7
int state = 0;

void setup() {
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  Serial1.begin(38400); // UART communication rate set on the HC05
}
void loop() {
 if(Serial1.available() > 0){ // Checks whether data is coming from the serial port  
 state = Serial1.read(); // Reads the data from the serial port
 }
 // Controlling the LED
  if (state == '1') {
  digitalWrite(ledPin, HIGH); // LED ON
  state = 0;
 }
 else if (state == '0') {
  digitalWrite(ledPin, LOW); // LED ON
  state = 0;
 }
 delay(10);
 
}

1 Like

I do have a voltage divider set up on the RX pin of both HC-05. Do I need to power the module with 3.3V also?

You posted the code just right. Make a wiring diagram to post, paper and pen is good enough.

No, there is a 5V to 3.3V regulator on the module. The Martyn Currey tutorials linked above really are the best.

Do you realize that this loop floods the "air waves" with a nearly continuous stream of 1s and 0s? That flood of data might cause the disconnection.

   // Reading the button
    buttonState = digitalRead(button);
        if (buttonState == HIGH) 
        {
        Serial.write('1'); // Sends '1' to the master to turn on LED
        }
        else 
        {
        Serial.write('0');
        } 
     delay(10);

It would make much more sense to send the switch state at longer intervals, or better, when the switch state changes.

Thanks for posting the schematic. Assuming that the triangle in the button circuit is an LED, that is not a good idea, as the Arduino is not guaranteed to read a HIGH when the button is pressed.

Instead, connect the button directly between GND and the digital pin, and use pinMode(button, INPUT_PULLUP); so that the pin reads HIGH when the button is open, LOW when it is closed.

jremington thanks for your thoughtful help. I made some code changes as you suggest. What does it mean when the sketch compiles OK, but uploading never finishes - just says "uploading" indefinitely?

Problem with the PC, Arduino or the connection. Make sure you are using a data USB cable, not a charging USB cable.

Disconnect the Arduino from everything, reconnect the naked Arduino to the PC with a data USB cable and try uploading the Blink example.

When I get this endless "uploading" (and ten sync errors if you wait long enough), I verify IDE >> PROCESSOR >> OLD BOOTLOADER (or) IDE >> PROCESSOR >> 328P

Back from a short fishing trip. The problem of never completing uploading was solved by simply removing the wires from the RX and TX (pins 0 and 1) when uploading.

I think the UNO, with only one hardware serial port, is not the best for what I'm trying to do because the port is shared by the USB connection (if I understand this correctly). So I decided to try using SoftwareSerial for my connection to the HC-05. I have the TX and RX pins on the HC05 connected to UNO pins 2 and 3, respectively.

Pushing the button changes the buttonState variable successfully. However, mySerial.available and mySerial.availableForWrite return a zero, and prevState never changes. (The LED on the master doesn't change either).

What value should I get from mySerial.available and mySerial.availableForWrite? What am I doing wrong?

#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // RX, TX
const int button = 8;
int buttonState = 0;
int prevState = 0;

void setup() 
{
  pinMode(button, INPUT_PULLUP);
  
  // Set data rate for the serial monitor:
  Serial.begin(9600); 
  delay(5);
  // set the data rate for the SoftwareSerial port to match the UART baud on HC05
  mySerial.begin(38400);
  delay(5);
}
void loop() 
{
    // Reading the button
    buttonState = digitalRead(button);
    Serial.print("buttonState = ");
    Serial.println(buttonState);
    Serial.print("prevState = ");
    Serial.println(prevState);
    Serial.print("mySerial.availableForWrite = ");
    Serial.println(mySerial.availableForWrite());
    delay(1000);
    if (buttonState != prevState) // if button has been pushed or released
    {
        if (buttonState == LOW && (mySerial.availableForWrite()>0)) // becomes LOW when button is pushed
        {
            mySerial.write('1'); // Sends '1' to the master to turn on LED
            prevState = LOW;
            delay(5); 
        }
        else if (buttonState == HIGH && (mySerial.availableForWrite()>0))
        { 
            mySerial.write('0');
            prevState = HIGH;
            delay(5);
        } 
    }
      
}

Sorry. Please ignore the previous photo of the circuit. Here is the correct one:

Forgot to mention: the good news is that the slave and master are now staying paired rather than losing the connection.

If you get 0 from mySerial.available(), then no characters have been received.

If you have not attempted to transmit any characters, then mySerial.avalailableForWrite() should return the buffer size. With that 5 ms delay, you should never need to use mySerial.availableForWrite().

Baud rates of 38400 and higher tend to be unreliable with SoftwareSerial.

It works! Thanks so much for all of your help. The last thing I did that made it come around was remove the commands with mySerial.availableForWrite from the slave code.

After all that, did you catch any fish??

5 small fish in 3 days - wow. But the weather was nice.