Arduino to Arduino by Bluetooth

Updated 12.06.2016: Added example 2

In the Connecting 2 Arduinos by Bluetooth using a HC-05 and a HC-06: Pair, Bind, and Link post I explained how to connect a HC-05 to a HC-06 so that when powered they automatically made a connection. Here we look at using that connection to get Arduinos talking over Bluetooth. Before continuing you need to have the Arduinos and BT modules set up as per the previous post. Here I am using 2 HC-05s. One in master mode the other in slave mode. The setup process for the slave mode HC-05 is the same as the HC-06 in the previous post.

Arduino2ArdionoBT_Breadboards_01_1600

Set Up

I am using 5V Arduino Nanos but any kind of 5V AVR based Arduino can be used.
I have designated one of the Arduinos as the master device. This is the one that initiates the connection and in the first example it is the one that sends the commands. Having a master and slave setup makes the programming a little easier.

To communicate with the BT modules I am using AltSoftSerial which uses pin 8 and pin 9. The AltSoftSerial library can be downloaded from https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html and it will need to be added before you can compile the example sketches.

Both BT modules are set with a communication baud rate of 9600. This can be changed but make sure you match the baud rate used when opening the software serial connection.

    //  open software serial connection to the Bluetooth module.
    BTserial.begin(9600);

Connecting the Bluetooth Modules

Most HC-05s and HC-06s have 3.3v TX and RX pins. 5V Arduinos will read 3.3v as HIGH so the BT modules TX pin can be connected directly to the Arduino RX pin. However, the Arduino TX pin needs to be converted to 3.3v before connecting to the BT modules RX pin. A simple way to do this is by using a voltage divider made from 2 resistors; I generally use 1 x 1K and 1 x 2K.

Arduino RX (pin 8) to BT module TX pin
Arduino TX (pin 9) to BT module RX pin via a voltage divider

Both Arduinos have the same connections to the BT modules.

Arduino2Arduino_1200

 
 

Example 1: Remote Control an LED

In the first example we get one Arduino to control an LED connected to a second Arduino. Communication is one way only and there is no error checking. Arduino #1 simply sends the commands LEDON and LEDOFF to the Arduino #2. When the Arduino #2 gets the commands it sets the LED accordingly.

Example 1: Circuit

Arduino #1, the master device, just has the Bluetooth module. Arduino #2, the slave device we have the Bluetooth module and an LED (with a suitable resistor) on pin D3.

Arduino2ArduinoExample1_circuit_1800

Arduino2ArdionoBT_Breadboards_01_1600

Example 1: Sketches

The Sketch on Arduino #1, the master device connected to the HC-05, simply sends the command LEDON, waits a second, sends the commands LEDOFF waits another second and then repeats indefinitely.

/*
* Sketch: Arduino2Arduino_MASTER_01
* By Martyn Currey
* 08.04.2016
* Written in Arduino IDE 1.6.3
*
* Send commands through a serial connection to turn a LED on and OFF on a remote Arduino
* There is no error checking and this sketch sends only
* Commands should be contained within the start and end markers < and >
*
* D8 - AltSoftSerial RX
* D9 - AltSoftSerial TX
*
*/
 
// AltSoftSerial uses D9 for TX and D8 for RX. While using AltSoftSerial D10 cannot be used for PWM.
// Remember to use a voltage divider on the Arduino TX pin / Bluetooth RX pin
// Download AltSoftSerial from https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html
 
#include <AltSoftSerial.h>
AltSoftSerial BTserial; 
 
// Change DEBUG to true to output debug information to the serial monitor
boolean DEBUG = true;
 
void setup()  
{
    if (DEBUG)
    {
        // open serial communication for debugging and show 
        // the sketch filename and the date compiled
        Serial.begin(9600);
        Serial.println(__FILE__);
        Serial.println(__DATE__);
        Serial.println(" ");
    }
 
    //  open software serial connection to the Bluetooth module.
    BTserial.begin(9600); 
    if (DEBUG)  {   Serial.println("BTserial started at 9600");     }
 
} // void setup()
 
 
void loop()  
{
    BTserial.println("<LEDON>");
    if (DEBUG) {Serial.println("LEDON command sent");}    
    delay (1000);
 
    BTserial.println("<LEDOFF>");
    if (DEBUG) {Serial.println("LEDOFF command sent");}      
    delay (1000);    
}

You will notice that the commands are contained within start and end markers, < and >.

    BTserial.println("<LEDON>");
    BTserial.println("<LEDOFF>");

Using start and end markers allows the receiving device to check that it has a full command before acting upon it.

 
The Sketch on Arduino #2, the slave device, checks for data and if there is a start marker it starts to put the recieved data in to the variable receivedChars[ ]. When an end marker is received it sets the newData flag to TRUE. Any data not within the start and end markers is ignored.

When newData is TRUE we know we have a command to process. In this case we set pin D3 HIGH or LOW to turn the LED on or off.

    if      (strcmp ("LEDON",receivedChars) == 0)  { digitalWrite(3,HIGH);   }
    else if (strcmp ("LEDOFF",receivedChars) == 0) { digitalWrite(3,LOW);    }

 

/*
* Sketch: Arduino2Arduino_SLAVE_01
* By Martyn Currey
* 08.04.2016
* Written in Arduino IDE 1.6.3
*
* Receive commands through a serial connection and turn a LED on or OFF
* There is no error checking and this sketch receives only
* Commands should be contained within the start and end markers < and >
*
* D8 - software serial RX
* D9 - software serial TX
* D3 - LED
*
*/
 
// AltSoftSerial uses D9 for TX and D8 for RX. While using AltSoftSerial D10 cannot be used for PWM.
// Remember to use a voltage divider on the Arduino TX pin / Bluetooth RX pin
// Download AltSoftSerial from https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html
 
#include <AltSoftSerial.h>
AltSoftSerial BTserial; 
 
// Change DEBUG to true to output debug information to the serial monitor
boolean DEBUG = true;
 
 
// Variables used for incoming data
 
 
const byte maxDataLength = 20;          // maxDataLength is the maximum length allowed for received data.
char receivedChars[maxDataLength+1] ;
boolean newData = false;               // newData is used to determine if there is a new command
 
 
 
void setup()  
{
    // LED on pin 3
    pinMode(3, OUTPUT); 
    digitalWrite(3,LOW);
 
 
    if (DEBUG)
    {
        // open serial communication for debugging and show the sketch name and the date compiled
        Serial.begin(9600);
        Serial.println(__FILE__);
        Serial.println(__DATE__);
        Serial.println(" ");
    }
 
    //  open software serial connection to the Bluetooth module.
    BTserial.begin(9600); 
    if (DEBUG)  {   Serial.println(F("AltSoftSerial started at 9600"));     }
 
    newData = false;
 
} // void setup()
 
 
 
void loop()  
{
         recvWithStartEndMarkers();                // check to see if we have received any new commands
         if (newData)  {   processCommand();  }    // if we have a new command do something
}
 
 
void processCommand()
{
    newData = false;
    if (DEBUG)  {   Serial.print("recieved data = ");  Serial.println(receivedChars);         }
 
    if      (strcmp ("LEDON",receivedChars) == 0)  { digitalWrite(3,HIGH);   }
    else if (strcmp ("LEDOFF",receivedChars) == 0) { digitalWrite(3,LOW);    }
}
 
// function recvWithStartEndMarkers by Robin2 of the Arduino forums
// See  http://forum.arduino.cc/index.php?topic=288234.0
void recvWithStartEndMarkers() 
{
     static boolean recvInProgress = false;
     static byte ndx = 0;
     char startMarker = '<';
     char endMarker = '>';
 
     if (BTserial.available() > 0) 
     {
          char rc = BTserial.read();
          if (recvInProgress == true) 
          {
               if (rc != endMarker) 
               {
                    if (ndx < maxDataLength) { receivedChars[ndx] = rc; ndx++;  }
               }
               else 
               {
                     receivedChars[ndx] = '\0'; // terminate the string
                     recvInProgress = false;
                     ndx = 0;
                     newData = true;
               }
          }
          else if (rc == startMarker) { recvInProgress = true; }
     }
 
}

 
 

Example 2: Remote Temperature Monitor

This example is a little more complex and unlike example 1, where the master device starts to send data as soon as it runs, this time it requests data from the slave. The slave receives the request from the master device and replies.

Arduino2Ardiono_Example2_01_1600

The slave device waits until it it gets the “sendTemp” request, it then reads the value of the temperature sensor on pin A0, converts the value to degrees celsius and then sends it out as ascii via the software serial channel. The sketches use the same recvWithStartEndMarkers() function as before and so the data is wrapped in the < start marker and the > end marker.

As before, the Bluetooth modules are set to automatically connect on start up. However, this time I an using 2 HC-05s; one in master mode, 1 in slave mode.

On start up, the master device initialises the LCD and starts a timer. When the timer finishes it sends out a request for the temperature. The Timer is then reset. Within the main loop, the sketch is continuously checking for received data. When it receives a temperature it displays it on the LCD.

The slave simply sits and waits for the request. When it receives the request it sends out the temperature and then goes back to waiting.

Example 2: Circuit

Arduino2ArduinoExample2Circuit_1800

Example 2: Sketches

The sketch on the master device is fairly simple. Once a second it sends a request to the slave device and waits for a reply. You can change the frequency of the request by changing the value of waitTime. There is no error checking or time out and the sketch does not know if it ever gets a reply or not.

/*
* Sketch: Arduino2Arduino_example2_RemoteTemp_Master
* By Martyn Currey
* 11.05.2016
* Written in Arduino IDE 1.6.3
*
* Send a temperature reading by Bluetooth
* Uses the following pins
*
* D8 - software serial RX
* D9 - software serial TX
* A0 - single wire temperature sensor
*
*
* AltSoftSerial uses D9 for TX and D8 for RX. While using AltSoftSerial D10 cannot be used for PWM.
* Remember to use a voltage divider on the Arduino TX pin / Bluetooth RX pin
* Download from https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html
*/
#include <AltSoftSerial.h>
AltSoftSerial BTserial; 
 
 
// If you don't have an LCD you can use the serial monitor.
// I use the LCD library from https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home
// if you use a different library change the following lines
#include <Wire.h>  
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
 
 
 
// define the pattern for a custom degree character. You can also use chr 233
byte degreeChr[8] = { B00111, B00101, B00111, B00000, B00000, B00000, B00000,}; 
 
 
 
// Set DEBUG to true to output debug information to the serial monitor
boolean DEBUG = true;
 
 
// Variables used for incoming data
const byte maxDataLength = 20;
char receivedChars[21] ;
boolean newData = false;
 
// Variables used for the timer
unsigned long startTime = 0;
unsigned long waitTime = 1000;
 
const byte TEMP_PIN = A0;
 
 
void setup()  
{
  lcd.begin(20,4); 
  lcd.createChar(1, degreeChr);
  lcd.setCursor(0,0);  lcd.print("Remote Temp Monitor"); 
  lcd.setCursor(0,1);  lcd.print("Starting..."); 
 
  if (DEBUG)
  {
       // open serial communication for debugging
       Serial.begin(9600);
       Serial.println(__FILE__);
       Serial.println(" ");
  }
 
    BTserial.begin(9600); 
    if (DEBUG)  {  Serial.println("AltSoftSerial started at 9600");     }
 
    newData = false; 
    startTime = millis();
 
} // void setup()
 
 
 
 
void loop()  
{
    if (  millis()-startTime > waitTime ) 
    {
       BTserial.print("<sendTemp>");  
       if (DEBUG) { Serial.println("Request sent"); }
       startTime = millis();
    }
 
    recvWithStartEndMarkers(); 
    if (newData)  
    {    
         if (DEBUG) { Serial.println("Data received"); }
         lcd.setCursor(0,1);   lcd.print("Temp = "); 
         lcd.setCursor(7,1);   lcd.print(receivedChars);  
         lcd.write(1);  lcd.print("C"); 
         newData = false;  
         receivedChars[0]='\0';     
    }    
}
 
 
 
 
// function recvWithStartEndMarkers by Robin2 of the Arduino forums
// See  http://forum.arduino.cc/index.php?topic=288234.0
/*
****************************************
* Function recvWithStartEndMarkers
* reads serial data and returns the content between a start marker and an end marker.
* 
* passed:
*  
* global: 
*       receivedChars[]
*       newData
*
* Returns:
*          
* Sets:
*       newData
*       receivedChars
*
*/
void recvWithStartEndMarkers()
{
     static boolean recvInProgress = false;
     static byte ndx = 0;
     char startMarker = '<';
     char endMarker = '>';
     char rc;
 
     if (BTserial.available() > 0) 
     {
          rc = BTserial.read();
          if (recvInProgress == true) 
          {
               if (rc != endMarker) 
               {
                    receivedChars[ndx] = rc;
                    ndx++;
                    if (ndx > maxDataLength) { ndx = maxDataLength; }
               }
               else 
               {
                     receivedChars[ndx] = '\0'; // terminate the string
                     recvInProgress = false;
                     ndx = 0;
                     newData = true;
               }
          }
          else if (rc == startMarker) { recvInProgress = true; }
     }
}

The slave device sketch is equally simple. It waits for a request, when it gets the request it sends out the current temperature.

/*
* Sketch: Arduino2Arduino_example2_RemoteTemp_Slave
* By Martyn Currey
* 11.05.2016
* Written in Arduino IDE 1.6.3
*
* Send a temperature reading by Bluetooth
* Uses the following pins
*
* D8 - software serial RX
* D9 - software serial TX
* A0 - single wire temperature sensor
*
*
* AltSoftSerial uses D9 for TX and D8 for RX. While using AltSoftSerial D10 cannot be used for PWM.
* Remember to use a voltage divider on the Arduino TX pin / Bluetooth RX pin
* Download from https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html
*/
#include <AltSoftSerial.h>
AltSoftSerial BTserial; 
 
// Set DEBUG to true to output debug information to the serial monitor
boolean DEBUG = true;
 
 
// Variables used for incoming data
const byte maxDataLength = 20;
char receivedChars[21] ;
boolean newData = false;
 
const byte TEMP_PIN = A0;
 
 
void setup()  
{
    if (DEBUG)
    {
        // open serial communication for debugging
        Serial.begin(9600);
        Serial.println(__FILE__);
        Serial.println(" ");
    }
 
    //  open a software serial connection to the Bluetooth module.
    BTserial.begin(9600); 
    if (DEBUG)  {   Serial.println(F("AltSoftSerial started at 9600"));     }
    newData = false;
 
} // void setup()
 
 
 
 
void loop()  
{
    recvWithStartEndMarkers(); 
    if (newData)  {   processCommand();  }    
}
 
 
 
 
/*
****************************************
* Function getTemp
* read a analogue pin and converts the value to a temperature
* based on the adafruit thermistor guide https://learn.adafruit.com/thermistor/testing-a-thermistor 
* 
* passed:
*  
* global: 
*
* Returns:
*        float temp  
* Sets:
*
*/
float getTemp()
{
    float reading = analogRead(TEMP_PIN);
    reading = 1023 / reading - 1;
    reading = 10000  / reading;
    float steinhart;
    steinhart = reading / 10000;          // (R/Ro)
    steinhart = log(steinhart);           // ln(R/Ro)
    steinhart /= 3950;                    // 1/B * ln(R/Ro)
    steinhart += 1.0 / (25 + 273.15);     // + (1/To)
    steinhart = 1.0 / steinhart;          // Invert
    steinhart -= 273.15;                  // convert to C
    return steinhart;
 
}
 
 
 
/*
****************************************
* Function processCommand
* parses data commands contained in receivedChars[]
* receivedChars[] has not been checked for errors
* 
* passed:
*  
* global: 
*       receivedChars[]
*       newData
*
* Returns:
*          
* Sets:
*       receivedChars[]
*       newData
*
*/
void processCommand()
{
 
     Serial.println(receivedChars);
 
     if (strcmp ("sendTemp",receivedChars) == 0) 
     { 
         float temp = getTemp();
         BTserial.print("<");  BTserial.print( temp ); BTserial.print(">");
         if (DEBUG) { Serial.print("Temp is ");   Serial.print(temp);  Serial.println("");   }
     }
 
     newData = false;
     receivedChars[0]='\0'; 
 
}
 
 
 
 
 
// function recvWithStartEndMarkers by Robin2 of the Arduino forums
// See  http://forum.arduino.cc/index.php?topic=288234.0
/*
****************************************
* Function recvWithStartEndMarkers
* reads serial data and returns the content between a start marker and an end marker.
* 
* passed:
*  
* global: 
*       receivedChars[]
*       newData
*
* Returns:
*          
* Sets:
*       newData
*       receivedChars
*
*/
void recvWithStartEndMarkers()
{
     static boolean recvInProgress = false;
     static byte ndx = 0;
     char startMarker = '<';
     char endMarker = '>';
     char rc;
 
     if (BTserial.available() > 0) 
     {
          rc = BTserial.read();
          if (recvInProgress == true) 
          {
               if (rc != endMarker) 
               {
                    receivedChars[ndx] = rc;
                    ndx++;
                    if (ndx > maxDataLength) { ndx = maxDataLength; }
               }
               else 
               {
                     receivedChars[ndx] = '\0'; // terminate the string
                     recvInProgress = false;
                     ndx = 0;
                     newData = true;
               }
          }
          else if (rc == startMarker) { recvInProgress = true; }
     }
 
}

 
 

61 thoughts on “Arduino to Arduino by Bluetooth”

  1. i am using above code with arduino mega But its not working on the slave module ?? i am using build in led on Arduino mega at pin 13. so i changed the code accordingly.
    if i burn an empty code on both devices and start communicating. it transfer messages. i have linked both devices using AT+Link command ONly.

    Reply
  2. Hey Martyn,

    So tried doing this to connect a nano(master) to an uno(slave). Everything is paired correctly and the master seems to be sending the signal from the serial monitor but the LED isn’t turning on. Any advice/help?

    Reply
    • Actually never mind. I managed to figure it out !

      But if you’re willing to help I’m trying to send gyroscope data over the bluetooth. Could really use the advice of someone who knows what they’re doing. I’m using the MPU 6050

      Reply
      • Hi Roy,

        I can’t help with the MPU6050 but there are many guides online.

        I have added a second example which has 2 way communication between the Arduinos.

        Reply
      • We are having the same problem. The bluetooths are paired correctly but the LED is not turning on. Please help us out as soon as possible!

        Reply
        • We are also having this problem. The Bluetooth modules are paired and the master (with the Nano) is sending the signal. The LED doesn’t turn on, though.

          Reply
          • Print the received data to the serial monitor.
            Make sure you are receiving the data and the data is what you think it is.

            Reply
  3. Great tutorial! I haven’t messed with the Bluetooth modules much, but plan to soon as I have three hc-05 modules, and about to order three hc-06 modules to go with it. What I would like to do with them is incorporate them into a pixel poi setup.

    I’m building a POV poi setup with two teensy 3.2 controllers, because of the bigger flash memory. I was thinking that maybe I could use one teensy for one display and a trinket for the other display, connected to each other via Bluetooth, feeding the images from one to the other as images change. That way I can store all the images on one poi stick and not have to alter the other to sync with the first.

    Anyway it’s an idea, and if I can get it to work then it would make it possible to use a less expensive microcontroller for one display, and invest that money into a bigger flash memory. Also to be able to send other images via Bluetooth through a phone or other device would be awesome.

    Reply
  4. Hi, I’m not very good at English. I can Connecting 2 Arduinos by Bluetooth using a HC-05 and a HC-06. I need help My project turn signal LED for bicycle.
    I need send Arduino to Arduino via Bluetooth HC-05(master) and HC-06(slave)
    This my code ,need you more help code send Arduino to Arduino.
    This code need use HC-05 and arduino
    int led1 = 0;
    int led2 = 1;
    int led3 = 2;
    int sw1 = 8; //turn left
    int sw2 = 9; // turn right
    int sw3 = 10; // middle signal
    int val;
    void setup()
    {
    pinMode(led1, OUTPUT);
    pinMode(led2, OUTPUT);
    pinMode(led3, OUTPUT);
    pinMode(sw1, INPUT);
    pinMode(sw2, INPUT);
    pinMode(sw3, INPUT);
    }
    void loop()
    {
    val=digitalRead(sw1);
    if(val==HIGH)
    {
    digitalWrite(led1, HIGH);
    delay(1000);

    {
    digitalWrite(led1,LOW);
    }
    val=digitalRead(sw2);
    if(val==HIGH)
    {
    digitalWrite(led2, HIGH);
    delay(1000);
    }
    if(val==HIGH)
    {
    digitalWrite(led2,LOW);
    }
    val=digitalRead(sw3);
    if(val==HIGH)
    {
    digitalWrite(led3, HIGH);
    delay(1000);
    }
    if(val==HIGH)
    {
    digitalWrite(led3,LOW);
    }
    }
    ——————————————————–
    and i need help make code for HC-06 recive

    Reply
    • For the examples above any 5V Arduino can be used without any changes.

      3V Arduino can also be used but you would need to remove the voltage dividers and give the BT module at least 3.6v power

      Reply
  5. i have successfully configured both modules, and i can now turn-on and turn-off an LED wirelessly.. but my problem is, how can i control 4 LEDS?? is it possible??

    Reply
    • Extend example 1.

      Instead of using LEDON & LEDOFF use something like LED1ON, LED2ON, LED3ON, etc. Or even simpler use:
      L11 = LED 1 on
      L10 = LED1 off
      L21 – LED 2 on
      L20 = LED 2 off

      Reply
  6. hello. i was in search of this for past few weeks but finally found what i wanted.
    i am using master code on mega and slave on uno.
    however uno is not receiving any command. Can you please help?

    Reply
  7. Hi i would like to know instead of using 2 arduino uno boards can i use i arduino with BT as a slave and nodeMcu with BT as a master to execute example2

    Reply
  8. Hi. I have tried the example 2 and while compiling the master program it is showing error as
    POSITIVE was not declared in this scope.
    How to clear this error.

    Reply
      • Can you please forward the exact link for the library..Because i have arduino Liquid Crystal Master library given below…

        #include “LiquidCrystal_I2C.h”
        #include
        #include
        #include

        // When the display powers up, it is configured as follows:
        //
        // 1. Display clear
        // 2. Function set:
        // DL = 1; 8-bit interface data
        // N = 0; 1-line display
        // F = 0; 5×8 dot character font
        // 3. Display on/off control:
        // D = 0; Display off
        // C = 0; Cursor off
        // B = 0; Blinking off
        // 4. Entry mode set:
        // I/D = 1; Increment by 1
        // S = 0; No shift
        //
        // Note, however, that resetting the Arduino doesn’t reset the LCD, so we
        // can’t assume that its in that state when a sketch starts (and the
        // LiquidCrystal constructor is called).

        LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_addr, uint8_t lcd_cols, uint8_t lcd_rows, uint8_t charsize)
        {
        _addr = lcd_addr;
        _cols = lcd_cols;
        _rows = lcd_rows;
        _charsize = charsize;
        _backlightval = LCD_BACKLIGHT;

        }

        void LiquidCrystal_I2C::begin() {
        Wire.begin();
        _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;

        if (_rows > 1) {
        _displayfunction |= LCD_2LINE;
        }

        // for some 1 line displays you can select a 10 pixel high font
        if ((_charsize != 0) && (_rows == 1)) {
        _displayfunction |= LCD_5x10DOTS;
        }

        // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
        // according to datasheet, we need at least 40ms after power rises above 2.7V
        // before sending commands. Arduino can turn on way befer 4.5V so we’ll wait 50
        delay(50);

        // Now we pull both RS and R/W low to begin commands
        expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1)
        delay(1000);

        //put the LCD into 4 bit mode
        // this is according to the hitachi HD44780 datasheet
        // figure 24, pg 46

        // we start in 8bit mode, try to set 4 bit mode
        write4bits(0x03 << 4);
        delayMicroseconds(4500); // wait min 4.1ms

        // second try
        write4bits(0x03 << 4);
        delayMicroseconds(4500); // wait min 4.1ms

        // third go!
        write4bits(0x03 << 4);
        delayMicroseconds(150);

        // finally, set to 4-bit interface
        write4bits(0x02 < _rows) {
        row = _rows-1; // we count rows starting w/0
        }
        command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
        }

        // Turn the display on/off (quickly)
        void LiquidCrystal_I2C::noDisplay() {
        _displaycontrol &= ~LCD_DISPLAYON;
        command(LCD_DISPLAYCONTROL | _displaycontrol);
        }
        void LiquidCrystal_I2C::display() {
        _displaycontrol |= LCD_DISPLAYON;
        command(LCD_DISPLAYCONTROL | _displaycontrol);
        }

        // Turns the underline cursor on/off
        void LiquidCrystal_I2C::noCursor() {
        _displaycontrol &= ~LCD_CURSORON;
        command(LCD_DISPLAYCONTROL | _displaycontrol);
        }
        void LiquidCrystal_I2C::cursor() {
        _displaycontrol |= LCD_CURSORON;
        command(LCD_DISPLAYCONTROL | _displaycontrol);
        }

        // Turn on and off the blinking cursor
        void LiquidCrystal_I2C::noBlink() {
        _displaycontrol &= ~LCD_BLINKON;
        command(LCD_DISPLAYCONTROL | _displaycontrol);
        }
        void LiquidCrystal_I2C::blink() {
        _displaycontrol |= LCD_BLINKON;
        command(LCD_DISPLAYCONTROL | _displaycontrol);
        }

        // These commands scroll the display without changing the RAM
        void LiquidCrystal_I2C::scrollDisplayLeft(void) {
        command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
        }
        void LiquidCrystal_I2C::scrollDisplayRight(void) {
        command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
        }

        // This is for text that flows Left to Right
        void LiquidCrystal_I2C::leftToRight(void) {
        _displaymode |= LCD_ENTRYLEFT;
        command(LCD_ENTRYMODESET | _displaymode);
        }

        // This is for text that flows Right to Left
        void LiquidCrystal_I2C::rightToLeft(void) {
        _displaymode &= ~LCD_ENTRYLEFT;
        command(LCD_ENTRYMODESET | _displaymode);
        }

        // This will ‘right justify’ text from the cursor
        void LiquidCrystal_I2C::autoscroll(void) {
        _displaymode |= LCD_ENTRYSHIFTINCREMENT;
        command(LCD_ENTRYMODESET | _displaymode);
        }

        // This will ‘left justify’ text from the cursor
        void LiquidCrystal_I2C::noAutoscroll(void) {
        _displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
        command(LCD_ENTRYMODESET | _displaymode);
        }

        // Allows us to fill the first 8 CGRAM locations
        // with custom characters
        void LiquidCrystal_I2C::createChar(uint8_t location, uint8_t charmap[]) {
        location &= 0x7; // we only have 8 locations 0-7
        command(LCD_SETCGRAMADDR | (location << 3));
        for (int i=0; i<8; i++) {
        write(charmap[i]);
        }
        }

        // Turn the (optional) backlight off/on
        void LiquidCrystal_I2C::noBacklight(void) {
        _backlightval=LCD_NOBACKLIGHT;
        expanderWrite(0);
        }

        void LiquidCrystal_I2C::backlight(void) {
        _backlightval=LCD_BACKLIGHT;
        expanderWrite(0);
        }

        /*********** mid level commands, for sending data/cmds */

        inline void LiquidCrystal_I2C::command(uint8_t value) {
        send(value, 0);
        }

        inline size_t LiquidCrystal_I2C::write(uint8_t value) {
        send(value, Rs);
        return 1;
        }

        /************ low level data pushing commands **********/

        // write either command or data
        void LiquidCrystal_I2C::send(uint8_t value, uint8_t mode) {
        uint8_t highnib=value&0xf0;
        uint8_t lownib=(value<450ns

        expanderWrite(_data & ~En); // En low
        delayMicroseconds(50); // commands need > 37us to settle
        }

        void LiquidCrystal_I2C::load_custom_character(uint8_t char_num, uint8_t *rows){
        createChar(char_num, rows);
        }

        void LiquidCrystal_I2C::setBacklight(uint8_t new_val){
        if (new_val) {
        backlight(); // turn backlight on
        } else {
        noBacklight(); // turn backlight off
        }
        }

        void LiquidCrystal_I2C::printstr(const char c[]){
        //This function is not identical to the function used for “real” I2C displays
        //it’s here so the user sketch doesn’t have to be changed
        print(c);
        }

        Reply
  9. hi I have successfully uploaded the program for both master and slave ..but my BT modules are not getting paired each other. Can you let me know the chances of reason behind it. And if i want to do the pairing of BT modules with out using serial monitor should i go for “AT” Command method?

    Reply
  10. Hi Martyn,

    Thanks for a great tutorial!

    Easy to follow, nice level of detail, first time right.

    /Christian

    Reply
    • Yes but the master can only connect to one slave at a time so you need to:
      connect to slave 1. Read/write data, disconnect
      connect to slave 2. Read/write data, disconnect
      connect to slave 3. Read/write data, disconnect
      etc

      Reply
  11. In your doc Arduino to Arduino by BlueTooth which uses HC-05’s and Hc06’s has this been updated to work with HM-10’s, or HC-12’s or even the nRf24l01’s. While my project is not dependent on one over the other, I would like to have as much distance as possible which I think would be the 12’s or rf24’s.
    Thanks in advance for your reply.
    Dwight

    Reply
  12. I’ve tested my HM-10’s using code from the mentioned site, I don’t see much difference between that code and the code for the arduino to arduino you used with the two 05’s. What i’m wondering will the 05 code work with the 10’s. I have the slave code ready to go and will get the master ready to try later today at which time I’ll probably have the answer. Just thought you might save me the time or give me some pointers, if the code (can or could be ) modified to work with the 10’s. The sensor code is exactly what I need for my project.
    Thanks again
    Dwight

    Reply
    • The HC-05, HC-06 and HM-10 are all serial/UART devices and have a serial interface that is used to talk to the Arduino. This means the Arduino code is basically the same for all modules. It would also be the same for any other serial device.

      The HC-06/05 are Bluetooth Classic and the HM-10 is BLE. The two are different and cannot talk to each other.

      After the modules are connected, either 2 BT Classic modules or 2 HM-10s, how you use them is exactly the same.

      Reply
  13. Hi Martyn,

    Ive followed the above example 1, the master is sending the turn ON LED command but the slave is NOT receiving the command. Am using Arduino UNO for my project

    Reply
  14. I saw that you are using hm-5 and hm-6 for the bluetooth temperature sensor. If I want to implement hm-10, what do you think I have to take into account? Because the bluetooth that you have, one is master and the other one is slave, but the hm-10 are master/slave modules.

    Reply
  15. Hi,

    Thank you for your tuto !!
    I have a question :
    I would like to use the same process, but instead turn “on” or “off” a led when a new command comes, i want to turn “on” the LED when there is no more signal…

    it looks likes turn “on” the LED when the bluetooth module is too far away, and do nothing when the bluetooth module is near and send bip…

    Could anyone halp me ?

    thank you :)))

    Reply
  16. hey i have done the first step of pairing bluetooths. Now i want my infrared signals detected to show output on led in another arduino. Can you please help me

    Reply
  17. What if you wanted to include another data source like Humidity into the project? How much of the code would change? I’m personally doing something similar to your setup, was wondering how would you go about it?

    Reply
  18. Hi, i was looking at your example 2, it is very similar to what i wanna build, i wanna measure, display and compare two currents, one from the master and one from the slave, im using two hm-10 bluetooth modules, current sensors, two arduino unos and two lcd Displays

    please assist where you can thank you

    Reply
  19. I was wondering if and how I can use HC05 modules with Arduino Micro on Hardware serial to decrease the transmission last for my worked head mouse project. I have not been about to do that from other tutorials. Please reply with a brief explanation how I can do it using hardware serial.,

    Reply
  20. The comment says:
    //AltSoftSerial uses D9 for TX and D8 for RX.
    But in the program we see:
    AltSoftSerial BTserial;
    I think it should be:
    AltSoftSerial BTserial(8,9);

    Reply
  21. I was able to connect two BT modules together, however I am having trouble pairing to a Windows 11 computer as well as a Raspberry Pi4B. When pairing to either I am able to connect only for 3 seconds only for the BT module to disconnect. The Arduino/HC-05 is powered by a separate power supply. What are the requirements to just pair the BT Module to a Raspberry pi 4B?

    Reply

Leave a Reply to mohan Cancel reply