Arduino Bluetooth Control

Note added 24.03.2017
Added a download for the aia file. See the very bottom of the post.

Note added 28.01.2016
The ABC app is a simple app that I first created to allow me to monitor Arduino pins and to give me basic control functions. It isn’t designed for complex control. I have received many comments and suggestions about the ABC app and as a result I created the new Bluetooth Control Panel app. This features better control functions and was designed around the function rather than the Arduino pin.

 
Arduino Bluetooth Control is a simple to use Android app for controlling and/or monitoring Arduino pins over Bluetooth. The app is self contained and all initialization is done from the Arduino sketch. It is designed around Arduino pins rather than control function.

24.10.2015
Now updated to version 2.
Added facility for renaming the pin descriptions and the app now has better error reporting for bad initialization commands

07.12.2015
Update to the sketches. I was checking the elapsed time incorrectly. Took me longer than it should have to spot it.

14.02.2016
Updated to version 3.
The app now sends a <RESET> code when the RESET button is clicked. This allows the Arduino to detect the app reset and automatically resend the initiation commands. See below for an example sketch.

 

ArduinoBluetoothControl_screenshort_001_1250

 
Different configurations
Only the pins you are using (have initialized) are displayed.
ArduinoBluetoothControl_diffConfigs_800

 
 
There are 3 kinds of pin:
– Digital Pins
– PWM Pins
– Analogue Pins

ArduinoBluetoothControl_pinDescriptions_800

 

Digital Pins

– Digital pins range from D2 to D12.
– Digital pins can be input or output.
– The value can be set to HIGH or LOW.
– The pin state can be controlled by the Arduino and the value displayed by the Android app.
– The pin state can be controlled by the Android app.

 

PWM Pins

– The PWM pins are; D3, D5, D6,D9, D10, and D11
– PWN pins are output only.
– The PWM Pin value is controlled by a slider in the Android app.
– The minimum and maximum values can be set for each pin.
– The smallest minimum is 0.
– The largest maximum is 255.

 

Analogue Pins

– The analogue pins are A0 to A5.
– Analogue pins are input only.
– The value, from 0 to 1023, is displayed in the Android app.

 
 

Initialization Commands

The Arduino sends initialization commands to the Android app and this means how the app displays a pin depends on the initialization command sent from the Arduino.

Examples of initialization commands
ArduinoBluetoothControl_initCommands_800

<D04IL> – Initialize pin D4 for digital input, start value LOW
<P10000255041> – Initialize pin D10 for PWN. Min value is 0. Max value is 255. Start value is 41.
<D11OH> – Initialize pin D11 for digital output, start value HIGH
<D12OH> – Initialize pin D12 for digital output, start value HIGH
<A010102> – Initialize pin A1 for analogue in. Start value is 102.

 

Initialization Commands For Digital Pins

The initialization command for a digital pin is 5 characters (not including the start and end markers).
The 1st character is the pin type. D for digital
The 2nd and 3rd characters are the pin number. The pin number always uses 2 digits.
The 4th character defines if the pin is input or output. I for input. O for output.
The final character is the start value. This is the value displayed in the Android app when it first starts, not the actual value of the pin. H for high. L for LOW.

<D06OL>
D – pin type. D for digital
06 – the pin number
O – Input or output. O for output
L – starting value. L for LOW

<D12DIH>
D – digital
12 – the pin number
I = input
H = Starting value of HIGH

 

Initialization Commands For PWM Pins

The initialization commands for PWM pins are 12 characters long not including the start and end markers.
The 1st character is the pin type. P for PWM
The 2nd and 3rd characters are the pin number. The pin number always uses 2 digits.
The 4th, 5th and 6th characters are the minimum value for the slider. 000 to 255.
The 7th, 8th and 9th characters are the maximum value for the slider. 000 to 255.
The 10th, 11th and 12th characters are the starting value of the slider. 000 to 255.

<P10000255000>
P – pin type. P fop PWM
10 – the pin number
000 – the minimum value
255 – the maximum value
000 – the starting value

<P05000100050>
P – PWM
05 – the pin number
000 – the minmium value
100 – the maximum value
050 – the start value

 

Initialization Commands For Analogue Pins

The initialization command for analogue pins are 7 characters long not including the start and end markers.
The 1st character is the pin type. A for Analogue.
The 2nd and 3rd characters are the pin number. The pin number always uses 2 digits.
The 3rd, 4th, 5th and 6th characters are the starting value displayed in the Android app.

<A011023>
A – analogue
01 – the pin number
1023 – the starting value to be displayed by the Android app.

 

Pin Description / Name Command

The default pin descriptions are:
– Digital in
– Digital out
– Analog in
– PWM out

These can be changed using the “Name” command.

<ND06LED>
N – for Name
D06 – the pin
LED – the name or description you wish to give to the pin

All pins have a default description which is applied when the pin is initialized. If you initialize a pin after changing its name, the given name will be over written by the default name.

 

Number of Commands Command

The final command is the “Number of commands” command. This is used by the Android app to check whether or not it has received all the initialization commands correctly. The command is C followed by the number of commands.

<C7>
C – Number of commands (count)
7 – the number of commands not including itself.
The count command is used to check that all commands have been received by the app. If the app does not receive the number of commands specified by the count command then an error message will be displayed.

The number is the number of commands not including the “Number of commands” command.

 
After the app has been set up you can send and receive pin values. This is done via pin data commands

 
If an incorrect command is received by the Android app an error message will be displayed and the command will be ignored. If the app does not display a pin check the initialization commands for errors.

If you reset the Arduino while the Android app is running you will also need to reset the app. The app will continue to run but the pin values will not be updated. Either restart the app or click the reset button on the Bluetooth page.

 
 

Pin Data Commands

There are 2 types of pin data:
1. Those sent from the Arduino to the Android app.
2. Those sent from the app to the Arduino.

 

Sending data from the Arduino to the Android app.

There are 2 types of pin data that can be sent from the Arduino
1. Digital Pin Data
2. Analogue Pin Data

Pin data commands sent from the Arduino use [ and ] as start and end markers.

Digital pins can be either HIGH or LOW. The command is shortened to H or L.
For digital pins the command is basically the pin number and the status.
[D04H] – pin D4 is HIGH
[D04L] – pin D4 is LOW

The commands are then sent to the Android app with:

BTserial.print("[D04H]");
BTserial.print("[D04L]");

Analogue pins can have a value from 0 to 1023. The value should be converted to a string before sending to the app.
For analogue pins the command is the pin number plus the value sent as a string.
[A010000]
A01 – Analogue pin 1
Value = 0000

[A021023]
A02 – Analogue pin 2
Value = 1023

The command is sent to the Android app in the same way as the digital command:

BTserial.print("[A011023]");

Note that the value is always 4 digits.

 

Receiving data on the Arduino from the the Android app

There are 2 types of data command that can be received from the Android app.
1. Digital pin data
2. PWM pin data

 

Digital pin data

When a digital pin button is clicked in the Android app either a HIGH command or a LOW command is sent to the Arduino. The pin data command consists of the pin number plus the value, H for HIGH. L for LOW.

<D12H> – set pin D12 to HIGH
<D12L> – set pin D12 to LOW
It is up to the sketch to interpret the commands and act accordingly. IE actually set the pin HIGH or LOW using digitalWrite().

 

PWM pin data

PWN values can be between 0 and 255 (unless you have set different limits) and the command is the pin number plus the value:
<P10000> – set pin D10 to an output of 0
<P10255> – set pin D10 to an output of 255
Remember that the commands do not do anything unless you actually write the value to the pin using analogWrite();

The received command is stored in the receivedChars global variable and you will need to check this to see what the pin number is and what the value is. Note that the start and end markers are stripped away so receivedChars contains only the actual command.
P10000
P10255

The value is always 3 digits.

 
 
 

Example 1: Turning an LED on and off

This example uses a single LED on Pin 12. The LEd is controlled via the Android app.

 

Test Circuit 01. Single LED

ArduinoBluetootgControl_Circuit_singleLED_001_1600

The bluetooth module is a HC-06 set for 9600 baud rate. You can use different baud rates if you wish. Match the baud rate in the sketch with the baud rate of your Bluetooth device. A HC-05 can be used as well.

ArduinoBluetoothControl_TestCircuit_01_1200

 

Example 01. Controlling a single LED

There are 2 parts to setting up the pins in the sketch.
1. Set the pin function
2. Send the initialization command

 

Set the pin function

This is the regular Arduino pin set up.

 
// Set the LED pin to output and set LOW
pinMode(12, OUTPUT); 
digitalWrite(12,LOW);

 

Send the initialization command

Send the commands to the Android app. The commands tell the app which pins are input and which pins are output.
The initialization commands start with a <START> command and end with an <END> commands

BTserial.print("<START>");    
BTserial.print("<D12OL>");        
BTserial.print("<C1>");  
BTserial.print("<END>");

Pin 12 is set to digital out with an initial value of LOW.

BTserial.print("<C1>");

C1 is the number of commands (not including iteself in the count) and is used as a check by the app to see if all commands were received correctly.

The Android app counts the number of initialization commands it receives and if this total does not match the total number of commands initialization commands (C1) an error message is displayed. The number of commands does not include the <START> and <END> markers.

On start up, the sketch keeps sending the initialization commands until it receives an “OK” reply from the Android app. Once a reply is received the app starts sending and receiving pin value data.

It is worth noting that the sketch doesn’t know if Bluetooth is connected or not.

Main Functions

recvWithStartEndMarkers() – this checks the software serial in and takes any data that is between the start and end markers (< and >). Any data not within the markers is ignored. The received data is put in to the global variable receivedChars

processCommand() – this checks the received data and if the pin number matches the pin we are using (D12) it is set HIGH or LOW to turn the LED either on or off.

 

/*
* Sketch: ArduinoSketch_ArduinoBluetoothControl_example001_single_LED_b
* By Martyn Currey
* 01.07.2015
* updated 06.12.2015
* Written in Arduino IDE 1.6.3
*
* Requires the Arduino Bluetooth Control Android App. Can be downloaded from Google Play.
* See https://www.martyncurrey.com/arduino-bluetooth-control/
*
* Turn an LED on and off from an Android app
* Uses the following pins
*
* D2 - software serial RX
* D3 - software serial TX
* D12 - LED
*
*/
 
// The Bluetooth module is connected to pin D2 and D3 and uses software serial
// Remember to use a voltage divider on the TX pin
#include <SoftwareSerial.h>
SoftwareSerial BTserial(2,3); // RX | TX
 
// Change DEBUG to true to output debug information to the serial monitor
const boolean DEBUG = true;
 
 
// Variables used for incoming data
char rc = ' ';
const byte maxDataLength = 20;
char receivedChars[21] ;
boolean newData = false;
 
 
void setup()  
{
 
  // Set the LED pin to output
  pinMode(12, OUTPUT); 
  digitalWrite(12,LOW);
 
 
  if (DEBUG)
  {
      // open serial communication for debugging
      Serial.begin(9600);
      Serial.println("Sketch: ArduinoSketch_ArduinoBluetoothControl_example001_single_LED_b");
      Serial.println(" ");
  }
 
 
  //  open software serial connection to the Bluetooth module
  BTserial.begin(9600); 
 
 
  // Send initialization commands and the wait for a receipt   
  newData = false;
 
  boolean done = false;
  unsigned long startTime = millis();
 
  // keep sending the initialization commands until ew receive an "OK"
  while (!done)
  {
        // send the initialization commands once every second. This can be changed to suit your own sketch.
        if ( millis()-startTime > 1000)
        {
            startTime = millis();
            BTserial.print("<START>");                // Start marker
            BTserial.print("<D12OL>");                // Initialize D12 for output. Start value = LOW
            BTserial.print("<C1>");                   // number of commands not including this one
            BTserial.print("<END>");                  // End marker
            if (DEBUG) {  Serial.println( "Initialization commands sent. Waiting for reply" );  }
        }
 
 
        recvWithStartEndMarkers(); // check for new data from the Bluetooth module
 
        if (newData)
        {
            // After the Android app receives the commands it sends an "OK" back.
            if (  (receivedChars[0] == 'O') & (receivedChars[1] == 'K')  )
            { done = true;  }
            else 
            {newData = false; }            
 
            if (DEBUG) { Serial.print("receivedChars = "); Serial.println( receivedChars );  }
        }
 
  } // while (!done) 
 
  if (DEBUG)  { Serial.println("OK received from the app");  } 
 
} // 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
}
 
 
 
/*
****************************************
* Function processCommand
* parses data commands contained in receivedChars[]
* receivedChars[] has not been checked for errors
* 
* passed:
*  
* global: 
*       receivedChars[]
*       newData
*
* Returns:
*          
* Sets:
*
*/
void processCommand()
{
     newData = false;
 
     if (DEBUG) { Serial.print("receivedChars = ");  Serial.println(receivedChars); }
 
     // does the pin data command start with a "D"
     if ( receivedChars[0] == 'D')
     {
           byte pin = ((receivedChars[1]-48) *10 ) + receivedChars[2]-48;    // get the pin number   
           if (pin == 12)
           {
                if ( receivedChars[3] == 'H') { digitalWrite(pin,HIGH); }
                if ( receivedChars[3] == 'L') { digitalWrite(pin,LOW);  }
           }
     }
}
 
 
 
// 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 = '>';
 
     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; }
     }
 
}

Download ArduinoSketch_ArduinoBluetoothControl_example001_single_LED_b

 
 
 

Example 2: Controlling a servo

This example uses a servo on Pin D5.

 

Test Circuit 02. Servo

This example has a single servo connected to pin D5. The servo is controlled by using a slider in the Android app.

The SoftwareSerial and Servo libraries use the same Arduino resources and do not play nice together, therefore, I am using hardware serial to talk to the Bluetooth module.

ArduinoBluetoothControl_Servo_Circuit_800
ArduinoBluetoothControl_Servo_Breadboard_1200

I am using a 5V breadboard power supply to power the servo and the Bluetooth module. The Arduino is powered from the USB, however, once programmed, the Arduino could take power from the breadboard power supply as well. All grounds are connected.

 

Test Sketch 02. Controlling a servo

 
The Initialization is just 2 commands:

Serial.print("<P05000170000>");         // Initialize pin D5 for PWM. min=0, max=170, start val=0
Serial.print("<ND05Servo Pos>");        // Set the name for D5 to Servo Pos

Initialize pin D5 as PWN. Min=0, max=170. Set the pin description to “ServoPos”.

Remember to set the number of commands count to 2:

Serial.print("<C2>");                   // number of commands not including itself.

 
Main Functions

Since I am only controlling a servo all we need to do it check to see if we have new commands and if we do move the servo.

recvWithStartEndMarkers() – this checks serial in and takes any data that is between the start and end markers (< and >) and places it in to the global variable receivedChars. Any data not within the markers is ignored.

processCommand() – this checks receivedChars and if it is a PWM command we move the servo accordingly. The PWN command has a 3 digit value in ascii format, for example “123”, and this is converted to a numeric value.

  byte pin = ((receivedChars[1]-48) *10 ) + receivedChars[2]-48;
 
  // PWM pin
  if ( receivedChars[0] == 'P')
  {
      // convert the ascii value to a numeric value
      byte val = ((receivedChars[3]-48) *100 ) + ((receivedChars[4]-48) * 10)  + (receivedChars[5]-48)   ;
      myservo.write(val);  
  }

 

Sketch

Because this example uses the hardware serial we cannot upload the sketch while the Arduino is connected to the RX and TX pins. Remove the connections, upload the sketch, and then redo the connections.

/*
* Sketch: ArduinoSketch_ArduinoBluetoothControl_example002b_ServoControl
* By Martyn Currey
* 14.11.2015
* Written in Arduino IDE 1.6.3
*
* Requires the Arduino Bluetooth Control Android App.
*
* See https://www.martyncurrey.com/arduino-bluetooth-control/
*
* Control the position of a servo motor
* Uses hardware serial to talk to the Bluetooth module
* Software serial conflicts with the Servo library
*
* The example uses the following pins
* TX1 - hardware serial TX
* RX0 - hardware serial RX
* D5 - servo
*
* It is recommended not to power the servo from the Arduino.
*
*/
 
#include <Servo.h>
Servo myservo;  // create a servo object 
 
char rc = ' ';
const byte maxDataLength = 20;
char receivedChars[21] ;
boolean newData = false;
 
void setup()  
{
    myservo.attach(5);
    myservo.write(0); 
 
    // Use the LED on pin 13 to show status 
    // Flashing means sending initialization commands and waiting for a reply
    // On means the Android app has replied correctly
    pinMode(13, OUTPUT); 
    digitalWrite(13,LOW);
 
    //  open serial connection to the bluetooth module
    Serial.begin(9600); 
    while (!Serial);
 
    // Send initialization commands and the wait for an "OK"   
    boolean LEDisON = false;
    boolean done = false;
    byte count = 0;
    boolean sendInitCodes = true;
 
    newData = false;
    int refreshRate = 250;
    unsigned long startTime = millis();
    while (!done)
    {
        // This bit flashes the LED on pin 13. 
        if ( millis() - startTime > refreshRate)
        {
            startTime = millis();
            if (LEDisON) { LEDisON = false;  digitalWrite(13,LOW);   }
            else         { LEDisON = true;   digitalWrite(13,HIGH);  } 
            count++; 
            // if reply is not received within 3 seconds resend the commands
            if (count==12) { count = 0; sendInitCodes = true;         }
        }
 
 
        // Keep sending the initialization commands until the "OK" reply is received.
        if (sendInitCodes == true)   
        { 
            sendInitCodes = false; 
            Serial.print("<START>");                // Start marker
            Serial.print("<P05000170000>");         // Initialize pin D5 for PWM. min=0, max=170, start val=0
            Serial.print("<ND05Servo Pos>");        // Set the name for D5 to Servo Pos
            Serial.print("<C2>");                   // number of commands not including itself.
            Serial.print("<END>");                  // End marker
        }
 
 
        recvWithStartEndMarkers(); // check for new data from the Bluetooth module
        if (newData)
        {
            // The Android app receives the commands and sends an "OK" back.
            if (  (receivedChars[0] == 'O') & (receivedChars[1] == 'K')  )
            { done = true;  }
            else 
            {newData = false; }            
        }
 
    } // while (!done) 
 
    // Turn on the built in LED to show the app has received the initialization codes
    digitalWrite(13,HIGH); 
    newData = false; 
    receivedChars[0] = '\0';
 
 
} // void setup()
 
 
 
 
void loop()  
{
    recvWithStartEndMarkers();          // check to see if we have received any new commands
    if (newData) { processCommand(); }  // if we have a new command set the Arduino pin accordingly
    delay(5);
}
 
 
/*
****************************************
* Function processCommand
* parses data commands contained in receivedChars[]
* receivedChars[] has not been checked for errors
* 
* Passed:
*
* Returns
*  
* Global: 
*       receivedChars[]
*       newData
*
* Sets/Changes:
*        newData
*
*/
void processCommand()
{
    newData = false;
    byte pin = ((receivedChars[1]-48) *10 ) + receivedChars[2]-48;
 
    // PWM pin
    if ( receivedChars[0] == 'P')
    {
        // convert the ascii value to a numeric value
        byte val = ((receivedChars[3]-48) *100 ) + ((receivedChars[4]-48) * 10)  + (receivedChars[5]-48)   ;
        myservo.write(val);  
    }  
}
 
 
 
// 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:
*  
* Returns:
*
* Global: 
*       receivedChars[]
*       newData
*          
* Sets:
*       newData
*       receivedChars
*
*/
void recvWithStartEndMarkers() 
{
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
 
    if (Serial.available() > 0) 
    {
          rc = Serial.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; }
    }
 
}

Download ArduinoSketch ArduinoBluetoothControl example002b ServoControl

 
 
 

Example 3: 3 LEDs, 1 Push Button Switch. 1 Potentiometer

This is a more complex example that has:
– 3 LEDs.
– push button switch
– potentiometer

It also uses the built in LED on pin D13.

All pins are given a descriptive name using the Name command.

The LEDs are controlled from the app; 2 are on/off and 1 is fade on / fade off.
The state of the push button and the value of the potentiometer are shown in the app.
The button switch can be either HIGH or LOW.
The potentiometer value can be from 0 to 1023.

The LED on pin 13 is used to show the sketch status; blinking means sending initialization commands and waiting for the app to reply. Solid on means initialised and receiving/transmitting pin status data.

Pin D10, D11, and D12 have LEDs. The LEDs on pin D11 and D12 are on/off only. The LED on pin D10 is controlled via a PWM signal and fade in and out.

Pin D6 has a button switch attached. The status of the pin is checked and, if the value has changed, the value is sent to the Android app.

Pin A1 has a potentiometer attached, the pin is checked using analogRead() and the value sent to the Android app.

 

Test Circuit 03. 3 LEDs, Push Button Switch. Potentiometer

ArduinoBluetootgControl_example03_Breadboard_1600

ArduinoBluetootgControl_example03_CircuitDiagram_1200

The bluetooth module is a HC-06 set for 9600 baud rate. You can use different baud rates if you wish. Match the baud rate in the sketch with the baud rate of your Bluetooth device. A HC-05 can be used as well.

 

Test Sketch 03. Controlling 3 LEDs. Monitoring a button switch and a potentiometer

 
Set the pin function
Set the pins; the LED pins for output and D6 for input.

  // set the button switch pin to input
  pinMode(6, INPUT); 
 
  // Set the LED pins to output and turn them off.
  pinMode(12, OUTPUT); // Pin 12
  pinMode(11, OUTPUT); // Pin 11 
  pinMode(10, OUTPUT); // Pin 10
  digitalWrite(12,LOW);
  digitalWrite(11,LOW);  
  digitalWrite(10,LOW);
 
  // potPin (A1) does not need initializing
 
  //Pin 13 LED is used to show status 
  // Flashing means sending initialization commands and waiting for a reply
  // On means the Android app has replied correctly
  pinMode(13, OUTPUT); 
  digitalWrite(13,LOW);

 
Initialization commands
Initialize the pins:

 BTserial.print("<START>");                // Start marker
 BTserial.print("<A010000>");              // Initialize analogue pin A01. Start value 0
 BTserial.print("<D06IL>");                // Set D6 to input. Start value = LOW
 BTserial.print("<P10000255000>");         // Initialize D10 for PWN. Start value = 0
 BTserial.print("<D11OL>");                // set D11 to output. Start value = LOW
 BTserial.print("<D12OL>");                // set D12 to output. Start value = LOW
 
 BTserial.print("<ND12LED #1>");           // set the pin description for D12 to LED #1
 BTserial.print("<ND11LED #2>");           // set the pin description for D11 to LED #2
 BTserial.print("<ND10LED Fader>");        // set the pin description for D10 to LED Fader
 BTserial.print("<ND06BTN Switch>");       // set the pin description for D6 to BTN Switch
 BTserial.print("<NA01Potentiometer>");    // set the pin description for A1 to Potentiometer. This will be truncated
 
 BTserial.print("<C10>");                   // number of commands not including itself.
 BTserial.print("<END>");                   // End marker

 
Main Functions

checkPins() – this reads the input pins status and if changed sends the value out via software serial.

formatNumber – converts a numeric value to an ascii string

recvWithStartEndMarkers() – this checks the software serial in and takes any data that is between the start and end markers (< and >). Any data not within the markers is ignored. The received data is put in to the global variable receivedChars

processCommand() – this checks the received data and if the pin number matches the pin we are using (D12) it is set HIGH or LOW to turn the LED either on or off.

/*
* Sketch: ArduinoSketch_ArduinoBluetoothControl_example003b
* By Martyn Currey
* 01.07.2015
* Written in Arduino IDE 1.6.3
*
* Requires the Arduino Bluetooth Control Android App.
*
* See https://www.martyncurrey.com/arduino-bluetooth-control/
*
* Read pin states / values and send to an Android app over bluetooth
* Receive control commands from the Android app
* The Android app is initialized by commands sent from the Arduino
*
* The example uses the following pins
* A1 - a potentiometer
* D2 - software serial RX
* D3 - software serial TX
* D6 - button switch (pulled LOW)
* D10 - LED
* D11 - LED
* D12 - LED
*/
 
// The Bluetooth module is connected to pin D2 and D3 and uses software serial
#include <SoftwareSerial.h>
SoftwareSerial BTserial(2,3); // RX | TX
 
// Change DEBUG to true to output debug information to the serial monitor
const boolean DEBUG = true;
 
char numberString[10];
// used to hold an ascii representation of a number
// [10] allows for 9 digits but in this example I am only using 4 digits
 
char rc = ' ';
const byte maxDataLength = 20;
char receivedChars[21] ;
boolean newData = false;
 
unsigned long startTime = 0;
unsigned long refreshRate = 100;
 
// I only send a value if the value has changed.
// This means I need to store the old value
unsigned int oldPotVal = 0;
unsigned int newPotVal = 0;
boolean oldButtonSwitchState = false;
boolean newButtonSwitchState = false;
 
 
void setup()  
{
  // set the button switch pin to input
  pinMode(6, INPUT); 
 
  // Set the LED pins to output and turn them off.
  pinMode(12, OUTPUT); // Pin 12
  pinMode(11, OUTPUT); // Pin 11 
  pinMode(10, OUTPUT); // Pin 10
  digitalWrite(12,LOW);
  digitalWrite(11,LOW);  
  digitalWrite(10,LOW);
 
  // potPin (A1) does not need initializing
 
  //Pin 13 LED is used to show status 
  // Flashing means sending initialization commands and waiting for a reply
  // On means the Android app has replied correctly
  pinMode(13, OUTPUT); 
  digitalWrite(13,LOW);
 
 
  if (DEBUG)
  {
      // open serial communication for debugging
      Serial.begin(9600);
      Serial.println("ArduinoSketch_ArduinoBluetoothControl_example003b");
      Serial.println(" ");
  }
 
 
  //  open software serial connection to the Bluetooth module
  BTserial.begin(9600); 
 
  // Send initialization commands and the wait for an "OK"   
  boolean LEDisON = false;
  boolean done = false;
  byte count = 0;
  boolean sendInitCodes = true;
 
  newData = false;
  refreshRate = 500;
  startTime = millis();
  while (!done)
  {
        // This bit flashes the LED on pin 13. 
        if ( millis()-startTime > refreshRate)
        {
            startTime = millis();
 
            if (LEDisON) { LEDisON = false;  digitalWrite(13,LOW);   }
            else         { LEDisON = true;   digitalWrite(13,HIGH);  } 
 
            count++; 
            // if reply is not received within 3 seconds resend the commands
            if (count==6) { count = 0; sendInitCodes = true;         }
        }
 
 
        // Keep sending the initialization commands until the "OK" reply is received.
        if (sendInitCodes == true)   
        { 
            sendInitCodes = false; 
            dumpBTserialBuffer(); // not really required but it makes me feel better :-)
 
            BTserial.print("<START>");                // Start marker
            BTserial.print("<A010000>");              // Initialize analogue pin A01. Start value 0
            BTserial.print("<D06IL>");                // Set D6 to input. Start value = LOW
            BTserial.print("<P10000255000>");         // Initialize D10 for PWN. Start value = 0
            BTserial.print("<D11OL>");                // set D11 to output. Start value = LOW
            BTserial.print("<D12OL>");                // set D12 to output. Start value = LOW
            BTserial.print("<ND12LED #1>");           // set the pin description for D12 to LED #1
            BTserial.print("<ND11LED #2>");           // set the pin description for D11 to LED #2
            BTserial.print("<ND10LED Fader>");        // set the pin description for D10 to LED Fader
            BTserial.print("<ND06BTN Switch>");       // set the pin description for D6 to BTN Switch
            BTserial.print("<NA01Potentiometer>");    // set the pin description for A1 to Potentiometer. This will be truncated            
            BTserial.print("<C10>");                  // number of commands not including itself.
            BTserial.print("<END>");                  // End marker
 
            if (DEBUG) { Serial.println("Sent init commands. Waiting for receipt"); }
        }
 
 
        recvWithStartEndMarkers(); // check for new data from the Bluetooth module
        if (newData)
        {
            // The Android app receives the commands and sends an "OK" back.
            if (  (receivedChars[0] == 'O') & (receivedChars[1] == 'K')  )
            { done = true;  }
            else 
            {newData = false; }            
 
            if (DEBUG) { Serial.print("receivedChars = "); Serial.println( receivedChars );  }
        }
 
  } // while (!done) 
 
 
  // Turn on the built in LED to show the app has received the initialization codes
  digitalWrite(13,HIGH); 
  if (DEBUG)  {  Serial.println("OK received from the app");  } 
 
 
  // refeshRate is the frequency to check the input pins
  refreshRate = 100;
 
} // void setup()
 
 
void loop()  
{
 
  if ( millis()-refreshRate > startTime)
  {
    startTime = millis();
    checkPins();  // read the pin values and if the values have changed send the new values to the Android app
  }
 
  recvWithStartEndMarkers();          // check to see if we have received any new commands
  if (newData) { processCommand(); }  // if we have a new command set the Arduino pin accordingly
 
}
 
 
/*
****************************************
* dumpBTserialBuffer
* removes data from the software serial buffer
* 
* passed:
*  
* global: 
*
* Returns:
*          
* Sets:
*
*/
void dumpBTserialBuffer()
{
     while(BTserial.available() > 0)  { char t = BTserial.read();  }
}  
 
 
/*
****************************************
* Function processCommand
* parses data commands contained in receivedChars[]
* receivedChars[] has not been checked for errors
* 
* passed:
*  
* global: 
*       receivedChars[]
*       newData
*
* Returns:
*          
* Sets:
*
*/
void processCommand()
{
     newData = false;
     byte pin = ((receivedChars[1]-48) *10 ) + receivedChars[2]-48;
 
     // digital pin 
     if ( receivedChars[0] == 'D')
     {
          if ( receivedChars[3] == 'H') { digitalWrite(pin,HIGH); }
          if ( receivedChars[3] == 'L') { digitalWrite(pin,LOW);  }
          if (DEBUG) { Serial.print("Digital pin command = ");  Serial.println(receivedChars); }
     }
 
     // PWM pin
     if ( receivedChars[0] == 'P')
     {
          byte val = ((receivedChars[3]-48) *100 ) + ((receivedChars[4]-48) * 10)  + (receivedChars[5]-48)   ;
          analogWrite(pin, val);
          if (DEBUG) { Serial.print("PWN command = ");  Serial.println(receivedChars); }
     }  
}
 
 
/*
****************************************
* Function checkPins
* Checks the values of the deignated pins and if the value has changed sends ascii codes to software serial
* 
* passed:
*  
* global: 
*         newPotVal
*         oldPotVal
*         potPin
*         newButtonSwitchState
*         oldButtonSwitchState
*         buttonSwitchPin
*         numberString
*
* Returns:
*          
* Sets:
*
*/
void checkPins()
{
        // Check the value on analogue pin A1
        newPotVal = analogRead(A1);
        //The pot I am using jitters +/- 1 so I only using changes of 2 or more.  
        if ( abs(newPotVal-oldPotVal) > 1)
        {
             oldPotVal = newPotVal;
             formatNumber( newPotVal, 4);
             BTserial.print("[A01");
             BTserial.print(numberString);
             BTserial.print("]");      
 
             if (DEBUG) { Serial.print("[A01"); Serial.print(numberString); Serial.println("]"); }
        }   
 
 
 
        // Check the state of pin 6 - the button switch.        
        newButtonSwitchState = digitalRead(6);
        if (newButtonSwitchState != oldButtonSwitchState)
        {
             oldButtonSwitchState = newButtonSwitchState;
             if (oldButtonSwitchState == true)
             {
                if (DEBUG) { Serial.println("[D06H]"); }
                BTserial.print("[D06H]");
             }
             else
             {
                if (DEBUG) { Serial.println("[D06L]"); }
                BTserial.print("[D06L]");
             }
        } 
}
 
 
/*
****************************************
* Function formatNumber
* formats a number in to a string and copies it to the global char array numberString
* pads the start of the string with '0' characters
* 
* passed:
*         number = the integer to convert to a string
*         digits = the number of digits to use         
*  
* global: 
*         numberString
*
* Returns:
*          
* Sets:
*         numberString
*
*/
void formatNumber( unsigned int number, byte digits)
{
    char tempString[10] = "\0"; 
    strcpy(numberString, tempString);
 
    // convert an integer into a acsii string base 10
    itoa (number, tempString, 10);
 
    // create a string of '0' characters to pad the number    
    byte numZeros = digits - strlen(tempString) ;
    if (numZeros > 0)
    {
       for (int i=1; i <= numZeros; i++)    { strcat(numberString,"0");  }
    }
    strcat(numberString,tempString); 
}
 
 
// 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 = '>';
 
     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; }
     }
}

Download ArduinoSketch ArduinoBluetoothControl example003b

 
 

Example 04. Single Analogue Sensor (Potentiometer)

This is a basic example of using a single analogue sensor. For this example I am using a potentiometer but any other analogue sensor can be used. The potentiometer is connected to A1,

ArduinoBluetoothControl_cicuit04

 

Test Sketch 04. Monitoring a a potentiometer

All this sketch does is read analogue pin A1 and send the value to the Android app. We are not receiving any data from the app and so we do not need to check.

 
Initialization commands

Set pin A1 for analogue and rename to “Potentiometer”

 BTserial.print("<START>");                // Start marker
 BTserial.print("<A010000>");              // Initialize analogue pin A01. Start value 0
 BTserial.print("<NA01Potentiometer>");    // set the pin description for A1 to Potentiometer. This will be truncated
 BTserial.print("<C2>");                   // number of commands not including itself.
 BTserial.print("<END>");                  // End marker
/*
* Sketch: ArduinoSketch_ArduinoBluetoothControl_example004b_Single_analogue_sensor
* By Martyn Currey
* 28.11.2015
* Written in Arduino IDE 1.6.3
*
* Requires the Arduino Bluetooth Control Android App.
*
* See https://www.martyncurrey.com/arduino-bluetooth-control/
*
* Read pin states / values and send to an Android app over bluetooth
* The Android app is initialized by commands sent from the Arduino
*
* The example uses the following pins
* A1 - potentiometer
*/
 
// Change DEBUG to true to output debug information to the serial monitor
const boolean DEBUG = true;
 
 
// The Bluetooth module is connected to pin D2 and D3 and uses software serial
#include <SoftwareSerial.h>
SoftwareSerial BTserial(2,3); // RX | TX
 
char numberString[10];
char rc = ' ';
const byte maxDataLength = 20;
char receivedChars[21] ;
boolean newData = false;
 
unsigned long startTime = 0;
unsigned long refreshRate = 2500;
 
unsigned int oldAnalogueVal = 0;
unsigned int newAnalogueVal = 0;
 
 
 
void setup()  
{
  // A1 does not need initializing
  if (DEBUG)
  {
      // open serial communication for debugging
      Serial.begin(9600);
      while (!Serial) {;}
      Serial.println("ArduinoSketch_ArduinoBluetoothControl_example004b_Single_analogue_sensor");
  }
 
 
  //  open software serial connection to the Bluetooth module
  BTserial.begin(9600); 
  if (DEBUG) {  Serial.println("BTserial started at 9600");   }
  newData = false;
  refreshRate = 3000;    // how often to send the init codes
  boolean done = false;
  startTime = millis();
  while (!done)
  {
        if ( millis()-startTime > refreshRate)
        {
            startTime = millis();
            BTserial.print("<START>");                // Start marker
            BTserial.print("<A010000>");              // Initialize analogue pin A01. Start value 0
            BTserial.print("<NA01Potentiometer>");    // set the pin description for A1 to Potentiometer. This may be truncated            
            BTserial.print("<C2>");                   // number of commands not including itself.
            BTserial.print("<END>");                  // End marker
            if (DEBUG) { Serial.println("Sent init commands. Waiting for receipt"); }
        }
 
        recvWithStartEndMarkers(); // check for new data from the Bluetooth module
        if (newData)
        {
            if (  (receivedChars[0] == 'O') & (receivedChars[1] == 'K')  )      { done = true;  }
            else                                                                {newData = false; }            
            if (DEBUG) { Serial.print("receivedChars = "); Serial.println( receivedChars );  }
        }
 
  } // while (!done) 
 
  if (DEBUG)  {  Serial.println("OK received from the app");  } 
 
  // refeshRate is the frequency to check the input pin
  refreshRate = 500;
  startTime = millis();
 
} // void setup()
 
 
void loop()  
{
 
  if ( millis()-refreshRate > startTime)
  {
    startTime = millis();
 
        // Check the value on analogue pin A1
        newAnalogueVal = analogRead(A1);
 
        if ( newAnalogueVal != oldAnalogueVal )
        {
             oldAnalogueVal = newAnalogueVal;
             formatNumber( newAnalogueVal, 4);
             BTserial.print("[A01");  BTserial.print(numberString);  BTserial.print("]");      
             if (DEBUG) { Serial.print("[A01"); Serial.print(numberString); Serial.println("]"); }
        } 
  }
 
} // loop()
 
 
 
 
void formatNumber( unsigned int number, byte digits)
{
    char tempString[10] = "\0"; 
    strcpy(numberString, tempString);
 
    // convert an integer into a acsii string base 10
    itoa (number, tempString, 10);
 
    // create a string of '0' characters to pad the number    
    byte numZeros = digits - strlen(tempString) ;
    if (numZeros > 0)
    {
       for (int i=1; i <= numZeros; i++)    { strcat(numberString,"0");  }
    }
    strcat(numberString,tempString); 
}
 
 
 
// 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) 
     {
          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; }
     }
}

Download ArduinoSketch ArduinoBluetoothControl example004

 
 
 

Example 05. Using RESET

In version 3 of the app I added a <RESET> command. Here is a brief example on how to use it to have the Arduino automatically resend the initiazation commands when it detects the reset.

I am using the same circuit as example 4 – a single analogue sensor (potentiometer)

The main difference in the sketch is that the part that sends the initization commands has been moved to its own function. The means we can call it at anytime.

The varaible initialized is used to show whether or not we have sent the init commands and received a reply. When initialized is TRUE we know the Arduino has connected to the app and we can start to send and/or receive pin data.

We we receive the <RESET> command we simply set initialized to FALSE.

/*
* Sketch: ArduinoSketch_ArduinoBluetoothControl_RESET
* By Martyn Currey
* 13.02.2016
* Written in Arduino IDE 1.6.3
*
* Requires the Arduino Bluetooth Control Android App.
*
* See https://www.martyncurrey.com/arduino-bluetooth-control/
*
* Read pin states / values and sends to an Android app over bluetooth
* Receive control commands from the Android app
* The Android app is initialized by commands sent from the Arduino
*
* The example uses the following pins
* A1 - a potentiometer
* D2 - software serial RX
* D3 - software serial TX
*/
 
// The Bluetooth module is connected to pin D2 and D3 and uses software serial
#include <SoftwareSerial.h>
SoftwareSerial BTserial(2,3); // RX | TX
 
// Change DEBUG to true to output debug information to the serial monitor
const boolean DEBUG = true;
 
char numberString[10];
// used to hold an ascii representation of a number
// [10] allows for 9 digits but in this example I am only using 4 digits
 
char rc = ' ';
const byte maxDataLength = 20;
char receivedChars[21] ;
boolean newData = false;
 
unsigned long startTime = 0;
unsigned long refreshRate = 100;
 
// I only send a value if the value of the sensor has changed.
// This means I need to store the old value so I can compare.
unsigned int oldPotVal = 0;
unsigned int newPotVal = 0;
 
boolean initialized = false;
 
 
 
void setup()  
{
 
  // potPin (A1) does not need initializing
 
  //Pin 13 LED is used to show status 
  // Flashing means sending initialization commands and waiting for a reply
  // On means the Android app has replied correctly
  pinMode(13, OUTPUT); 
  digitalWrite(13,LOW);
 
  if (DEBUG)
  {
      // open serial communication for debugging
      Serial.begin(9600);
      Serial.println(__FILE__);
      Serial.println(__DATE__);
      Serial.println(" ");
  }
 
  BTserial.begin(9600);   //  open software serial connection to the Bluetooth module
  refreshRate = 100;      // refeshRate is the frequency to check the input pins
 
} // void setup()
 
 
 
 
void loop()  
{
 
     if (!initialized)
     {
         sendInitCommands();  // send the init commands and wait for a reply.
 
     }
     else
     {
        if ( millis()-refreshRate > startTime)
        {
          startTime = millis();
          checkPins();  // read the pin values and if the values have changed send the new values to the Android app
        }
 
        recvWithStartEndMarkers();          // check to see if we have received any new commands
        if (newData) { processCommand(); }  // if we have a new command do something about it
 
    }
 
}
 
 
 
 
/*
****************************************
* Function sendInitCommands
* Sends initialization commands and then waits for a "OK" reply.
* 
* passed:
*  
* global: 
*       receivedChars[]
*       newData
*
* Returns:
*          
* Sets:
*
*/
void sendInitCommands()
{
  // Send initialization commands and the wait for an "OK"   
  boolean LEDisON = false;
  boolean done = false;
  byte count = 0;
  boolean sendInitCodes = true;
 
  newData = false;
  long unsigned startTime = millis();
  while (!done)
  {
        // This bit flashes the LED on pin 13. 
        if ( millis()-startTime > 500 )
        {
            startTime = millis();
 
            if (LEDisON) { LEDisON = false;  digitalWrite(13,LOW);   }
            else         { LEDisON = true;   digitalWrite(13,HIGH);  } 
 
            count++; 
            // if reply is not received within 3 seconds resend the commands
            if (count>=6) { count = 0; sendInitCodes = true;         }
        }
 
 
        // Keep sending the initialization commands until the "OK" reply is received.
        if (sendInitCodes == true)   
        { 
 
            dumpBTserialBuffer(); // not really required but it makes me feel better :-)
            BTserial.print("<START>");                // Start marker
            BTserial.print("<A010000>");              // Initialize analogue pin A01. Start value 0000
            BTserial.print("<NA01Potentiometer>");    // set the pin description for A1 to Potentiometer. This will be truncated      
            BTserial.print("<C2>");                   // number of commands not including itself
            BTserial.print("<END>");                  // End marker
            sendInitCodes = false; 
 
            if (DEBUG) { Serial.println("Sent init commands. Waiting for reply"); }
        }
 
 
        recvWithStartEndMarkers(); // check for new data from the Bluetooth module
        if (newData)
        {
            // The Android app receives the commands and sends an "OK" back.
            if (strcmp ("OK",receivedChars) == 0)   { done = true;  }
            else                                    { newData = false; }            
 
            if (DEBUG) { Serial.print("receivedChars = "); Serial.println( receivedChars );  }
        }
 
  } // while (!done)   
 
  initialized = true;
 
  // Turn on the built in LED to show the app has received the initialization codes
  digitalWrite(13,HIGH); 
  if (DEBUG)  {  Serial.println("OK received from the app");  } 
 
 
}
 
 
 
/*
****************************************
* dumpBTserialBuffer
* removes data from the software serial buffer
* 
* passed:
*  
* global: 
*
* Returns:
*          
* Sets:
*
*/
void dumpBTserialBuffer()
{
     while(BTserial.available() > 0)  { char t = BTserial.read();  }
}  
 
 
 
 
/*
****************************************
* Function processCommand
* parses data commands contained in receivedChars[]
* receivedChars[] has not been checked for errors
* 
* passed:
*  
* global: 
*       receivedChars[]
*       newData
*
* Returns:
*          
* Sets:
*
*/
void processCommand()
{
     newData = false;
 
     if (strcmp ("RESET",receivedChars) == 0) 
     {
         initialized = false;
     }
 
     if (strcmp ("DISCONECT",receivedChars) == 0) 
     {
         initialized = false;
     }
 
     if (DEBUG) { Serial.print("Recieved data = ");  Serial.println(receivedChars); }
 
}
 
 
 
 
/*
****************************************
* Function checkPins
* Checks the values of the deignated pins and if the value has changed sends ascii codes to software serial
* 
* passed:
*  
* global: 
*         newPotVal
*         oldPotVal
*         potPin
*         newButtonSwitchState
*         oldButtonSwitchState
*         buttonSwitchPin
*         numberString
*
* Returns:
*          
* Sets:
*
*/
void checkPins()
{
        // Check the value on analogue pin A1
        newPotVal = analogRead(A1);
        //The pot I am using jitters +/- 1 so I only using changes of 2 or more.  
        if ( abs(newPotVal-oldPotVal) > 1)
        {
             oldPotVal = newPotVal;
             formatNumber( newPotVal, 4);
             BTserial.print("[A01");
             BTserial.print(numberString);
             BTserial.print("]");      
 
             if (DEBUG) { Serial.print("[A01"); Serial.print(numberString); Serial.println("]"); }
        }   
 
 
}
 
 
/*
****************************************
* Function formatNumber
* formats a number in to a string and copies it to the global char array numberString
* pads the start of the string with '0' characters
* 
* passed:
*         number = the integer to convert to a string
*         digits = the number of digits to use         
*  
* global: 
*         numberString
*
* Returns:
*          
* Sets:
*         numberString
*
*/
void formatNumber( unsigned int number, byte digits)
{
    char tempString[10] = "\0"; 
    strcpy(numberString, tempString);
 
    // convert an integer into a acsii string base 10
    itoa (number, tempString, 10);
 
    // create a string of '0' characters to pad the number    
    byte numZeros = digits - strlen(tempString) ;
    if (numZeros > 0)
    {
       for (int i=1; i <= numZeros; i++)    { strcat(numberString,"0");  }
    }
    strcat(numberString,tempString); 
}
 
 
// 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 = '>';
 
     if (BTserial.available() > 0) 
     {
          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; }
     }
}

Download ArduinoSketch_ArduinoBluetoothControl_RESET

 
 

Downloads

Download ArduinoSketch_ArduinoBluetoothControl_example001_single_LED_b
Download ArduinoSketch ArduinoBluetoothControl example002b ServoControl
Download ArduinoSketch ArduinoBluetoothControl example003b
Download ArduinoSketch ArduinoBluetoothControl example004
Download ArduinoSketch_ArduinoBluetoothControl_RESET

Download the Android app from Google Play

 
 
 

Source code / aia file

A lot of people have asked for the aia file and I had always intended to release the code but wanted to clean it up before posting. Unfortunately I never got round to doing so and the longer I left the harder it was to get back to. I also feel the graphics could be a lot better.
The code works fine but it is not particularly efficient. There are 2 very similar code blocks handling the initiation commands and the data commands. These could very easily be merged in to one.

aia file for the ABC app

If you use the code to make something more interesting, please let me know.
 
 
 

92 thoughts on “Arduino Bluetooth Control”

  1. First of all: thanks for sharing! Nice.
    When I was working on an app created with MIT App Inventor 2 I came across your post.
    I have created a moodlight with an APA102 LED string with configurable settings in EEPROM on the Arduino.
    What I wanted to do is let the app send a command to retrieve the settings, the Arduino will then return key=value pairs, the same pairs that can be sent by the app.
    So if the Arduino needs to refresh the settings on the app it can send the values.
    Regards,
    Eric
    So, would it be an added feature to let the Arduino set the values on the app?

    Reply
    • This is very possible but beyond the scope of the above.

      My solution would be to implement the processCommand() and recvWithStartEndMarkers() functions in the Android app, use start and end markers, and then process commands in app the same way as in the Arduino sketch.

      Reply
  2. Martyn,

    I am from the MIT2 forum.
    I changed the 003 sample.

    As said I declared ValueOut1 as integer.
    Changed

    void checkPins()
    {
    ValueOut1 = 1023;

    // Check the value on analogue pin A1
    //newPotVal = analogRead(A1); //original code
    newPotVal = ValueOut1;
    //The pot I am using jitters +/- 1 so I only using changes of 2 or more.
    if ( abs(newPotVal – oldPotVal) > 0)
    {
    oldPotVal = newPotVal;
    formatNumber( newPotVal, 4);
    BTserial.print(“[A01”);
    BTserial.print(numberString);
    BTserial.print(“]”);

    if (DEBUG) {
    Serial.print(“[A01”);
    Serial.print(numberString);
    Serial.println(“]”);
    }
    }

    What I in the serial monitor see is:

    ArduinoSketch_ArduinoBluetoothControl_example003

    Sent init commands. Waiting for receipt
    Sent init commands. Waiting for receipt
    Sent init commands. Waiting for receipt
    Sent init commands. Waiting for receipt
    Sent init commands. Waiting for receipt
    Sent init commands. Waiting for receipt
    Sent init commands. Waiting for receipt
    receivedChars = DISCONECT
    Sent init commands. Waiting for receipt
    Sent init commands. Waiting for receipt
    Sent init commands. Waiting for receipt
    receivedChars = OK
    OK received from the app
    [A011023]

    it is only one value in the last line and there is no update but that is correct.
    As the value is not changing as it is a static one the serial monitor does not show them line by line.
    But the ABC app does show 0000 in the datafield and not 1023.

    What goes wrong?
    Your help is appricaited to get things going.

    Paco

    Reply
  3. Hi Paco,

    It looks like the Bluetooth module is disconnecting. See “receivedChars = DISCONECT”. What BT module are you using?

    0000 is the default value. You can change this to something else in the initialization command, try <A011111>.

    I will try to add a sketch later this weekend showing the bare minimum required for an analogue sensor.

    Reply
    • .
      EDIT
      Just added example 04. A basic example for monitoring a single analogue pin.

      I have noticed that sometimes the Arduino is not quite ready when the app sends the acknowledgement signal and the signal gets corrupted and not recognised. When this happens the sketch will keep sending the init codes but the app has already displayed the pin but the pin value will not change. If this happens try using the RESET button on the Bluetooth tab.

      06.12.2015: figured this out. I was checking the elapsed time incorrectly. I was using “if ( millis()-refreshRate > startTime)” instead of “if ( millis()-startTime > refreshRate)”.

      I have updated the above sketches.

      Reply
  4. Hello Martyn,

    Sample 04 works fine.
    When I change the value to 1023 it is nicely mentioned in the ABC app.
    I just blew my Nano so have to wait for new supply to test more then one serial data value. Let you know.

    Paco

    Reply
  5. Hello Martyn,

    Finally I found this great app for controlling arduino :) I think this is the best app. Thank you Martyn you are very talented.

    I am working on a project and I need some help to write the code and using the Bluetooth module for controlling.
    The main idea is simple: Controlling a Dc motor (6-9v geared motor) with Arduino Uno + L298 H bridge + bluetooth module

    It’s a basic controlling of the DC motor, these are the commands what I need:

    – loop start switch: which starts the motor, and the motor continuously running until the stop button is pressed
    – program start switch: which starts a program of running the motor for example 10 sec. and after 10 sec. stops.
    – direction switch: which controls the direction of the motor
    – stop switch: stops the motor
    – Fader: Speed controller of the motor

    Can I do this with bluetooth and your ABC app?
    Can you help me writing the code? Any help is well appreciated. :)

    Thank you!
    Peter

    Reply
    • You can do this by re-purposing the commands and ignoring the pin numbers but it would not be an ideal solution.

      On the Arduino side you can perform any function you like based on the commands received. For example D02H does not have to mean bring pin D2 HIGH. It could mean start a motor on pin 10. It is up to you.

      some examples:
      D2 – set up as a start stop switch (LOW = off. HIGH = on)
      D3 – use for direction (HIGH left, LOW right) ( you could even use a slider (min1 max3. 1=left, 2=stop, 3=right)
      D4 – set program. HIGH = start program (start the motor for 10 seconds). When the program has completed send a commands from the Arduino to change the status to LOW.
      D5 – slider to control the motor speed.

      Another example. I use a slider (min=1 max=4) to determine 1 of 4 actions rather than 4 separate buttons.

      I am now travelling until after the new year so cannot offer more help and all I can suggest is experiment.

      Reply
      • Hello Martyn,

        I couldn’t figured out how to write the code for the above application. I have all the parts, the Bluetooth works very well, and the demo codes too :)

        Can you help me please writing the code for the above application?

        How can I start and, how to send the commands to the H298N bridge for controling the dc motor?

        Thank you for your help!

        Reply
        • Hi Peter,
          assuming you have 2 directions; left and right, I would use a slider. Min value 1, max value 3. Initial value 2.
          Then in the Arduino sketch a 1 would mean left, 3 would mean right and 2 would mean off/stop. This would work for a simply on/off system but would not offer any speed control.
          If you wanted speed control you could use a slider with a larger scale, for example 0-100 and then use 0-49 for left, 51-100 for right and 50 as off. 1 would be fastest left and 100 would be fastest right.

          Using buttons is not the best solution because you can have both buttons HIGH at the same time and of course you cannot have a motor turning left and right at the same time.

          ABC is not really the best solution for your project. It was designed as a simply way to control or monitor Arduino pins. I am now working on a different controller which is based on functions rather than pins but it is likely to be a while before it is ready.
          Your project has inspired me to add motor control and toggle buttons. Something I had not considered before.

          If you fancy having a play with app inventor have a look at https://www.martyncurrey.com/arduinobtcontrol/ which includes a navigation keypad that may be better suited for your project. The aia file is available for download.

          Reply
          • Thank you Martin,

            Now I have a working controller :), finally I’ve figured out. So I have a button for Left turn and for Right turn. If both are LOW the motor is stopped. If I change HIGH or the left or the right button the motor tuns left or right. And I have a slider for speed control.

            One more question. How can I assign a slider to control LOW HIGH parameters and not PWM? Can you help me with a sample code.

            And what do you think what is wrong with the code? when I press the reset in the app, doesn’t make the reinitialization. the app says waiting for initialization commands. I need to press the reset button on arduino to initialize.

            thank you.

            ————————————–

            Hi Peter,

            it is up to you how you handle the data the Arduino receives from the app. For example the slider data <P10000> and <P10001> can be used as a switch. If the value = 000 set a pin to LOW, if it is 001 set a pin HIGH. Or even display a message on an LCD, or flash an LED.

            The reset button restarts the app and so the initialization commands need to be resent.

            Reply
          • Is it possible after pressing the reset button in the app, the initialization codes to be resent automatically?

            —————————————
            Not at this time.

            The reset button was implemented so that when the Arduino is restarted you do not need to restart the app, just use the reset button.

            Martyn

            Reply
  6. First of all your project is nice !

    Can you please add the .aia file for app inventor here, so that we can see how the app work ?

    Thanks.

    Reply
  7. Is it possible to digital read data from a sensor. I have a dht 21 temp and humidity sensor and I can’t figured out how to see data on phone. Data is transmited on a single digital pin, out pin(D20 for example). I will apreciate very much if you can help me.

    Reply
    • I would suggest breaking the problem down in to small tasks. Get the sensors working first with output to the serial monitor. Once you are happy with this then add the app. Use test sketch 4 as a starting point.

      Reply
  8. Hi Martyn,
    First of all thank you very very much for sharing this awesome knowledge with us.
    It helped me to get most of my answers.
    Well i am unable to write a code for my arduino to control my 8-channel relay board without any errors.
    kindly help me with this,i am using your app.
    Thank You!

    Reply
    • To get started simply extend Example 01.

      To add extra pins there are 3 things to extend; 2 inside the setup() function and 1 inside the processCommand() function.

      Inside setup() –
      Define the pins at
      // Set the LED pin to output
      pinMode(12, OUTPUT);
      digitalWrite(12,LOW);
      add extra pins here
      pinMode(11, OUTPUT);
      digitalWrite(11,LOW);

      Initialization commands at
      BTserial.print(“<D12OL>”);
      add extra pins here
      BTserial.print(“<D11OL>”);
      (remember to update the <Cn> command)

      Inside the processCommand() function-
      // does the pin data command start with a “D”
      if ( receivedChars[0] == ‘D’)
      {
      byte pin = ((receivedChars[1]-48) *10 ) + receivedChars[2]-48; // get the pin number
      if (pin == 12)
      {
      if ( receivedChars[3] == ‘H’) { digitalWrite(pin,HIGH); }
      if ( receivedChars[3] == ‘L’) { digitalWrite(pin,LOW); }
      }

      // add extra pins here
      if (pin==11)
      {
      }
      }

      Reply
  9. thank you for sharing! very interesting.
    i did want to have a closer look to your software, but unfortunately i wasn’t able to connect to arduino. i am using hc05 and my smartphone is “nexus s” (pretty old)
    With another android app (blueterm) i can connect without any problems.
    What is going wrong?
    i would appreciate any hint to get things going.
    Klaus

    Reply
  10. Hi Klaus,
    do you get any error message when you select the HC-05 or does it say connected?

    If it connects and then nothing happens you may have an issue with the initialization commands.

    Reply
    • Hi Martyn,
      finally i solved the problem by unrooting (took me a while) my Smartphone. Every thing works now just fine.
      Thank you for your help and good luck.

      Reply
  11. Hi Martyn! You are awesome. I spent like 3 days trying to make my bluetooth work, and after i have found your site, i did it in 15 mins. You are just awesome. Now i have a question. I want to turn on/off a water pump with relay module. The waterpump is simple, you plug it in and it goes on. Could you help me a bit with the code on arduino how it should look. I use your sample ( 3 one). Thanks a lot for everything you did. Sorry for english, its not my native language. Have a nice day!

    Reply
  12. Can i get some help with this error
    Invalid text operation
    Segment: Start(5) + length(1) -1 exceeds text length(4).
    It seems like is some sort of aplication error… halp? :D

    Reply
  13. I just want to add more extra pins thats all. I go into app and i press connect and immediately after that the erroir pops up. In example 3 if i write
    pinMode(9, OUTPUT);
    digitalWrite(9,LOW);
    BTserial.print(“”);
    BTserial.print(“”);
    I get the error. On wednesday i have to present my homework, if you could give me some tips to resolve the problems it would be awesome. I just want to add more Digital Pins thats all. :)

    Reply
    • I hope you understood me. I write on your sketch
      pinMode… etc
      BTserial.print…. etc
      i want to use 7 pins. Then i upload on arduino. I log in the apps. And after i connect to arduino with the phone, after 1 second the error pops up.

      Reply
      • It is going to be a few days before I can look at this.
        In the meantime try removing the BTserial.print(“”); statements.
        These are not required and I think are causing the problem.

        Reply
          • ic, they are actually the init commands. WordPress though they were tags and removed them….

            can you repost the commands replacing the < and > characters with [ and ] so they show up.

            Also, do you have the latest version?

            Reply
  14. Compliments of the good work ,very great I must say.
    would you please help me with the coding .I’m using example 3 and want to extend it by adding 1 more analog sensor(potentio meter) and 1 more button input

    Reply
  15. Hi Martin
    Having the same problem as bluez ,I’m trying to have multiple sensors ,like on the example 3 ,I want 3 analoge sensors and 3 digital sensors . the example works well but when I make extras on the code its none responsive. can you please just write an example of 2 or more digital inputs and two or more analogue inputs on one progam please..

    I love you app ! great stuff

    Reply
    • I’ll try to add an extended example. In the meantime, do not flood the app with data. If you do not need instant updates limit how often you send data, for example once a second or once every 100ms.

      Reply
  16. hi Martin I just want to ask if is it possible to read the inputs from reset ,because what I noticed with example 3 is that ,If reset the arduino and one of the inputs is high(5v) I have to change input to low than High again for software to read . It does not automatically read high at startup. Hope you find this in order

    Reply
    • You would need to change how you initialise the pins. Read the pin status first and then create the appropriate initialisation command.

      For example:
      Read pin D2
      If D2 is HIGH use <D02OH>
      If D2 is LOW use <D02OL>

      Reply
  17. Hi. I tried your app on my Galaxy Note 4 and no matter which version of arduino code I use I cannot get it to initialise. Using the monitor I can see it is sending the initialisation request and it does receive commands from the Galaxy (RESET and DISCONNECT). Any ideas?
    regards
    David

    Reply
      • Hi. It seems the module isnt in AT mode. using the linked code i can send “text” to the arduino via the bletooth and its echoed in the serial monitor but it doesnt respond to AT commands. sending from the arduino to the galaxy shows nothing.
        Regards
        David

        Reply
        • The app requires the Bluetooth module to be in communication mode. It doesn’t use AT mode.

          You do need to match the modules communication baud rate with the BTserial.begin(9600); statement in the sketch though. I use 9600 in all the examples as this is the normal default speed for most BT modules, however, yours maybe be different and you will need AT mode to check.

          Determine which Bluetooth modules you have and then Google the model number. If they are one of the common models I may have a guide on the site. Some start in AT mode, other need to be put in to AT mode.

          Can you see the BT modules when using an Android device? What name do they show?

          Reply
          • hi. it pairs with the android fine and shows up as HC-06. Data sent from the android shows up on the serial window perfectly but data sent from the serial window doesnt show on the android device. i cant find information on the modules but they have 3 solder pads on the rear , P104, 3V3 and P105
            regards
            david

            Reply
            • Most likely you have a problem with the connection between Arduino TX and BT module RX. Check the connections and double check you are using the correct value resistors.

              Reply
  18. Hi, That was my first thought and I did check. I think I will start again and use a logic level converter I have lying around somewhere, I have used these before on the HC-O5 module with success. Thanks for the advise.
    regards
    David

    Reply
  19. Hi, I have a problem running more than one servo. I used your example to run one servo on pin 5 fine, but when I attach another servo to pin 6 and initialize it, it does not move. The PWM controls for pin 6 on my android phone also controls pin 5…
    What am I doing wrong? I can also send you the code if needed

    Reply
      • Hey Martyn, just wanted to thank you for making this app and your prompt response. I used your app to control a pentathlete robot with 2 stepper motors and a servo and it worked out great for a mock ASME competition! (although we didn’t spec out the right motors and the h-bridges couldn’t handle the power output) The tutorials and examples were useful and simple enough for an ME who’s never used an arduino before! thanks again!

        Reply
  20. hi sir
    i’m interest with your project and i have working on similar project to receive status of pin from arduino but i have problem in the mti app blocks. so might you help me with that
    thanks

    Reply
  21. Hello Martyn,
    I am using Arduino pro mini with HC-05 via level convertor.
    I am able to pair & connect the HC-05 with the mobile, rate of LED flashing in HC-05 is reduced.
    Arduino running example004b is able to receive, connect & reset signal, from the App (version3)
    However, the ERRORS section of the “connect” tab reports
    Invalid command type: [START]
    Invalid command type: [A010000]
    .
    .
    Invalid command type: [END]
    Kindly advise where my mistake might be & help me to cross this hurdle.
    Thank you.

    Reply
  22. Sorry, for some reasons, all characters within “greater than” & “smaller than” are all ignored in my reply. I hope the following get across.

    “<NA01………..”

    Reply
  23. No, they are not getting across…..anyway, what I’m saying is: the arduino sends out the correct initialization code but the app thinks its not.

    Reply
    • To get < and > to show use the html code tag & l t ; and & g t ;

      The error messages you posted above:
      Invalid command type: [START]
      Invalid command type: [A010000]

      show that you have used [ and ] for the init commands use < and >.

      Reply
      • Thank you.
        Please allow me to explain my problem again.
        The example004b sketch, for 1 pot, is copied from this website and uploaded to my pro mini without any change.
        Using a BT terminal the following is seen <START><A010000>…………<END>
        However, the error section of your app says Invalid command type:[START}……Invalid command type:[END]

        Reply
          • I have uploaded ArduinoSketch_ArduinoBluetoothControl_example001_single_LED_b, without any change.
            BT terminal shows <START><D120L><C1>………<END>
            The ERROR messages are as follows
            Invalid command type:[START]
            Data commands received but control elements not yet initialized.[D120L]
            Invalid command type:[C1]
            Invalid command type:[END]
            Serial monitor reports receivedChars=RESET when RESET is pressed, same for CONNECT & DISCONNECT. Most time its displaying Initialization commands sent. Waitng for reply. No improvement using another mobile.

            Reply
  24. @Yan Chun Tong

    Little bit stumped. I tried the examples again and all worked fine. At the weekend I will try to review the app source code see if I can spot anything.

    Do you have the latest version of the app?

    Reply
    • The “ABOUT” tab of your app says Bluetooth Control Panel version 3.

      Meanwhile, I have watch the youtube #36 Control your Arduino from your phone – HC06 Bluetooth mo.mp4 by Mr.Ralph S Bacon, downloaded his app & the arduino sketch.
      In that arduino sketch, I have changed the pin alloted to the led, as per your example001, and added A1as analog input for the potentiometer.
      I read the pot, convert result to ascii & sent it thro’ the softwareserial.
      I am able to turn the led on & off via the bluetooth terminal, and the analog input is also received by the terminal, although preceded by 2 <error>. I have yet to find out why 2 errors were returned.
      My hurdle seems to be similar to the problem described by David(31august2016) above.

      Reply
        • One last word here before I move on to post in the Bluetooth Control Panel tab.
          Thank you very much for your help.
          I was unaware that the sketches found in the Arduino Bluetooth Control tab are incompatible with the Bluetooth Control Panel Version3, installed from the play store.
          After your advise, I have successfully used BCP_Example_01a_Single_LED.ino with Bluetooth Control Panel version3.
          Now I’ll have to familiarize on how to control the app via my arduino pro mini. Thank you again.

          Reply
  25. Hello, i was working with sketch number 003 and im having an issues getting it to intailize on the app. I keep getting all kinds of errors most of them are invalid command type. Please help me. Thanks

    Using an Arduino Uno and HC-06

    Reply
  26. Hi Martyn,
    is there a way you can relese ABC aia file now when you already move to BTC?
    I believe this will be very useful for all users of your beautifull and most valuable app I ever seen about bluetooth communication betwen android and arduino.
    thanks,
    Damir

    Reply
  27. Hi Martyn,

    This is a great tutorial.

    You hint at the ability to send a list in the .WriteString procedure. When I have tried it, I find that my full list is available in the .StringsWritten callback, but my embedded device only receives the first list item (“test1″,”test2″,”test3” and only “test1” shows up at my embedded serial port).

    I was wondering if you had any thoughts about this? (A quick search didn’t find any reference on your blog, I’m sorry if you’ve already discussed this)

    Thanks, Al

    Reply
  28. hello sir
    i need your help i am working on my final year project .Actually i am sending the data through arduino via using bluetooth and potential meter but my application do not receive any data .The serial motion show the reading on my pc.

    Reply
  29. Hi Martyn,
    Thanks for your great app and tutorial, the sketches were very help[ul. We, my friend Jan and i made a very nice small hoovercraft. With 4 propellers , 2 for lifting and 2 for propulsion. Sorry we can’t show you the video.

    Reply

Leave a Comment