bluetooth: arduino controlled from windows

having got the bluesmirf working, now time to start sending and receiving some proper data between a computer and the arduino.

this post is divided into:
Part 1: sending data from within the arduino programme
Part 2: sending data from a windows application (using VB.Net)
Part 3: sending proper data from VB.Net
Part 4: sending data back to a PC from the arduino

Part 1: sending data from within the arduino programme

first up, the excellent arduino software tutorial. this should ensure that a lowercase letter sent (via bluetooth) to the arduino is returned (via bluetooth) in capitals. i wired up the board as suggested (see image on right) – note that the bluesmirf transmit pin (tx) will be wired up to the arduino receive pin (rx) and vice versa. i then cut and paste the tutorial into the arduino software and uploaded it to the chip. having disabled and re-enabled the smirf, and disconnected and reconnected the serial connection in teraterm, it works – sort of. in teraterm, i type in ‘a’ and get back ”β”, “b” gives me “ô”. so something a bit odd going on, but at least there’s communication!

rather than battle too long with trying to resolve what was going on there, i tried to see if i could i could flash an LED on pin 13 according to the number entered into teraterm (not the ‘serial window’ within the arduino programming environment). the following code worked:


/* Hello Software Serial Mode 
* -------------------------- * * 

turns on and off an LED on Pin 13 
according to the number transmitted 
to the arduino via the bluesmirf. 

Created 17 June 2008 by Ben at cape ealing 
*/

// include the SoftwareSerial library so you can use its functions:
#include <SoftwareSerial.h>

// define the pins on the arduino: 7 to rx, 6 to tx, 13 to flash
#define rxPin 7
#define txPin 6
#define flashPin 13

// set up a new serial connection using pins 7 and 6
SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);

// the setup part of the script
void setup()  {

  // define pin modes for tx, rx:  
  pinMode(rxPin, INPUT);  
  pinMode(txPin, OUTPUT);  
  pinMode(flashPin, OUTPUT);

  // set the data rate for the serial port  
  mySerial.begin(9600);}

// the main part of the script
void loop() {

  //get the value from the receive pin  
  int val = mySerial.read();

  //turn that value from ASCII to an integer  
  val = val - '0';

  //print out the value just obtained  
  mySerial.print(val);

  // print a linefeed character  
  mySerial.println();

  // flash the LED the number of times entered  
  for (int i=0; i < val; i++){  
  digitalWrite(flashPin,HIGH);  
  delay(500);  
  digitalWrite(flashPin,LOW);  delay(500);  
  } 
}

Part 2: sending data from a windows application (using VB.Net)

now time to send commands from within a Windows application out via COM port 7 to the Arduino. using the same sketch as above, i then wrote the following script in visual basic (VB.Net) which opens COM7 and sends out through it the single byte “5”, which is then transmitted over bluetooth, to the arduino, which then flashes the LED on pin 13 five times.

the windows app I ran this from was a VB.Net application – the beginnings of the ASCOM driver for the binocular mirror mount (see the capeMirror software section). i wrote the entirety of that driver in the free “visual basic express” programme from microsoft (see link on left). the vb code below could easily be tested (and for free) within that environment too. It’s not adding any functionality, but it’s accessing the COM port / arduino from within a Windows application. In visual basic I created a new Project using the ‘Console Application’ template and then within that i wrote this code as the Sub Main(), click Build, then Debug->Start Debugging:

Module Module1

    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'Connect to Arduino over Bluetooth via the serial port.
    '
    'created by Ben at Cape Ealing
    '17 June 2008
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

    Public Sub Main()

        Dim Arduino_SerialPort As New IO.Ports.SerialPort

        'First see if the serial port is open, if not open it
        If Arduino_SerialPort.IsOpen = False Then
            With Arduino_SerialPort
                .PortName = "COM7"
                .BaudRate = 9600
                .DataBits = 8
                .Parity = IO.Ports.Parity.None
                .StopBits = IO.Ports.StopBits.One
                .Encoding = System.Text.Encoding.ASCII
                .ReadTimeout = 5000
            End With
            Arduino_SerialPort.Open()
        End If

        'send one byte of data: 5
        Arduino_SerialPort.Write("5")

    End Sub

End Module

Amazingly it worked.

Part 3: sending proper data from VB.Net

Now time to send ‘longer data’ to the arduino. This little example sends 3 numbers (up to six digits long) from within a visual basic .Net application to the arduino. The arduino then flashes 3 different LED pins according to the numbers received by it. The picture on the right shows the wiring.

The following amendment to lines 23 and 24 of the VB.Net script sends an instruction which contains 3 numbers separated by semi-colons. The instruction begins with a hash. So #5;10;15 sends 3 separate variables: 5, 10 and 15.

        'Arduino_SerialPort.Write("5")
        'Comment out the line above and add the line below
        Arduino_SerialPort.Write("#5;10;15;")

On the arduino, the AFSoftwareSerial library is needed. This from ladyada as he (lad yada?) or she (lady ada?) put it “Here is a re-vamped “software serial” library that doesnt suck.”
drop it into hardware/library folder

This next sketch (with thanks to Nition who developed the tricky serial parsing bit) does the job.


/* AFSoft Serial Mode - Multi-Bits
* --------------------------------------- * *
Turns on and off an LED on Pin 13 according to the number
transmitted to the arduino via the bluesmirf. Can now
receive a number larger than 1-bit.
Sending #5;10;15; will: flash Pin 11 x 5, Pin 12 x 10, Pin 13 x 15. 

Acknowledgements
The difficult serial parsing bit was came from Nition
see forum post at:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1203538464/2#2

The AFSoftwareSerial library came from ladyada.
It adds the serial.available functionality.
Download it here: http://www.ladyada.net/make/eshield/download.html 

Created 19 June 2008 * by Ben
*/ 

// include the AFSoftSerial library
#include <AFSoftSerial.h> 

// define the pins on the arduino: 7 to rx, 6 to tx, 13 to flash
#define rxPin 7
#define txPin 6
#define flashxPin 11
#define flashyPin 12
#define flashrPin 13 

//define the variables for parsing serial data
#define tagLength 6 // each tag ID contains 6 bytes
#define hash 0x23 // "#" hash
#define semicolon 0x3b // ";" semicolon
#define dataRate 9600 // 9600kbps
int tagIndex = 0; // counter for number of bytes read
int allComplete = false; // whether all tags have been read
char xVal[tagLength], yVal[tagLength], rVal[tagLength];
char thisChar;
int xComplete = false;
int yComplete = false;
int rComplete = false; 

// set up a new serial connection using pins 7 and 6
AFSoftSerial mySerial = AFSoftSerial(rxPin, txPin); 

// the setup part of the script
void setup() { 

// define pin modes for tx, rx
pinMode(rxPin, INPUT);
pinMode(txPin, OUTPUT);
pinMode(flashxPin, OUTPUT);
pinMode(flashyPin, OUTPUT);
pinMode(flashrPin, OUTPUT); 

// set the data rate for the serial port
mySerial.begin(dataRate);} 

// the main part of the script
void loop() { 

// read in and parse serial data
if (mySerial.available() > 0) {
  delay(1500);  // wait for all data. 1.5s works fine. could be shorter.

readData(); // call the function to read the data that's been received 

// flash the Pin 11 [xVal] number of times
for (int a=0; a<atoi(xVal);a++){
digitalWrite(flashxPin,HIGH);
delay(250);
digitalWrite(flashxPin,LOW);
delay(250);
} 

// flash the Pin 12 [yVal] number of times
for (int a=0; a<atoi(yVal);a++){
digitalWrite(flashyPin,HIGH);
delay(250);
digitalWrite(flashyPin,LOW);
delay(250);
} 

// flash the Pin 13 [rVal] number of times
for (int a=0; a<atoi(rVal);a++){
digitalWrite(flashrPin,HIGH);
delay(250);
digitalWrite(flashrPin,LOW);
delay(250);
} 

} // end if
} // end loop

void readData() { 

// Reset all the variables
xComplete = false;
yComplete = false;
rComplete = false; 

for (int i=0;i<5;i++){
digitalWrite(5, HIGH);
xVal[i] = 0x00;
yVal[i] = 0x00;
rVal[i] = 0x00;
} 

// Read the serial datachar
thisChar = mySerial.read();
if (thisChar == hash)
{ // read all x
while (xComplete == false && mySerial.available() > 0){
char thisChar = mySerial.read();
// Serial.println("x-loop");
if (thisChar == semicolon){
xComplete = true;
break;
}
else {
xVal[tagIndex] = thisChar;
tagIndex++;
}
}
tagIndex = 0; 

// read all y
while (yComplete == false && mySerial.available() > 0){
char thisChar = mySerial.read();
// Serial.println("y-loop");
if (thisChar == semicolon){
yComplete = true;
break; }
else {
yVal[tagIndex] = thisChar;
tagIndex++;
}
}
tagIndex = 0; 

// read all r
while (rComplete == false && mySerial.available() > 0){
char thisChar = mySerial.read();
// Serial.println("r-loop");
if (thisChar == semicolon){
rComplete = true;
break;
}
else {
rVal[tagIndex] = thisChar;
tagIndex++;
}
}
tagIndex = 0; 

if (xComplete == true && yComplete == true && rComplete == true){
// Can put in debugging here
}
}
}

Works fine.

Part 4: sending data back to a PC from the arduino

finally with a couple of amendments to the sketch and vb code the arduino can send a message back to the windows application to say that it’s finished. Here the message is: “[Arduino;Bluetooth;capeMirror]”. This is then read by the windows .Net application.

In short, the windows application is ‘waiting’ for any data received via the serial port. So here when it gets the left bracket “[“, it is programmed to collect each of the characters that follow until it gets the right bracket “]” – which tells the .Net programme that the message stream has finished. This will allow the arduino to communicate with the windows app and tell that programme when the arduino has completed the commands. The wiring is as before (on the right for quick reference).

The sketch above needs amending as follows:
1. remove the ‘//’ at line N – this will call the datacomplete function
2. add the following lines into the ‘datacomplete function’.

The vb .net code is as follows:


Module Module1
    Public WithEvents Arduino_SerialPort As IO.Ports.SerialPort
    Public ReceivedDataYet As Boolean

    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'Connect to Arduino over Bluetooth via the serial port.
    '
    'created by Ben at Cape Ealing
    '17 June 2008
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

    Public Sub Main()

        Dim Arduino_SerialPort As New IO.Ports.SerialPort
        Dim RxChar As Char
        Dim RxMessage As String

        'Empty the variables        
        RxChar = ""
        RxMessage = ""

        'First see if the serial port is open, if not open it
        If Arduino_SerialPort.IsOpen = False Then
            With Arduino_SerialPort
                .PortName = "COM7"
                .BaudRate = 9600
                .DataBits = 8
                .Parity = IO.Ports.Parity.None
                .StopBits = IO.Ports.StopBits.One
                .Encoding = System.Text.Encoding.ASCII
                .ReadTimeout = 5000
            End With
            Arduino_SerialPort.Open()
        End If

        'send the portions of data
        Arduino_SerialPort.Write("#5;10;15;#")

        'Wait until the Arduino sends back it's message
        Do Until Arduino_SerialPort.BytesToRead > 0
        Loop

        'Collect the message one byte at a time
        Do
            RxChar = ChrW(Arduino_SerialPort.ReadByte)
            RxMessage = RxMessage & RxChar
        Loop Until RxChar = "]"

        'Display the message
        MsgBox(RxMessage)

    End Sub
End Module

The arduino sketch looks like this:


/* AFSoft Serial Mode - Multi-Bits
* --------------------------------------- * *
Turns on and off an LED on Pin 13 according to the number
transmitted to the arduino via the bluesmirf. Can now
receive a number larger than 1-bit.
Sending #5;10;15; will: flash Pin 11 x 5, Pin 12 x 10, Pin 13 x 15. 

Acknowledgements
The difficult serial parsing bit was came from Nition
see forum post at:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1203538464/2#2

The AFSoftwareSerial library came from ladyada.
It adds the serial.available functionality.
Download it here: http://www.ladyada.net/make/eshield/download.html 

Created 19 June 2008 * by Ben
*/ 

// include the AFSoftSerial library
#include <AFSoftSerial.h> 

// define the pins on the arduino: 7 to rx, 6 to tx, 13 to flash
#define rxPin 7
#define txPin 6
#define flashxPin 11
#define flashyPin 12
#define flashrPin 13 

//define the variables for parsing serial data
#define tagLength 6 // each tag ID contains 6 bytes
#define hash 0x23 // "#" hash
#define semicolon 0x3b // ";" semicolon
#define dataRate 9600 // 9600kbps
int tagIndex = 0; // counter for number of bytes read
int allComplete = false; // whether all tags have been read
char xVal[tagLength], yVal[tagLength], rVal[tagLength];
char thisChar;
int xComplete = false;
int yComplete = false;
int rComplete = false; 

// set up a new serial connection using pins 7 and 6
AFSoftSerial mySerial = AFSoftSerial(rxPin, txPin); 

// the setup part of the script
void setup() { 

// define pin modes for tx, rx
pinMode(rxPin, INPUT);
pinMode(txPin, OUTPUT);
pinMode(flashxPin, OUTPUT);
pinMode(flashyPin, OUTPUT);
pinMode(flashrPin, OUTPUT); 

// set the data rate for the serial port
mySerial.begin(dataRate);} 

// the main part of the script
void loop() { 

// read in and parse serial data
if (mySerial.available() > 0) {
  delay(1500);  // wait for all data to be in. 1500 works fine. could try shorter 

readData(); // call the function to read the data that's been received 

// flash the Pin 11 [xVal] number of times
for (int a=0; a<atoi(xVal);a++){
digitalWrite(flashxPin,HIGH);
delay(250);
digitalWrite(flashxPin,LOW);
delay(250);
} 

// flash the Pin 12 [yVal] number of times
for (int a=0; a<atoi(yVal);a++){
digitalWrite(flashyPin,HIGH);
delay(250);
digitalWrite(flashyPin,LOW);
delay(250);
} 

// flash the Pin 13 [rVal] number of times
for (int a=0; a<atoi(rVal);a++){
digitalWrite(flashrPin,HIGH);
delay(250);
digitalWrite(flashrPin,LOW);
delay(250);
} 

// run the DataComplete procedure
DataComplete();

} // end if
} // end loop

void readData() { 

// Reset all the variables
xComplete = false;
yComplete = false;
rComplete = false; 

for (int i=0;i<5;i++){
digitalWrite(5, HIGH);
xVal[i] = 0x00;
yVal[i] = 0x00;
rVal[i] = 0x00;
} 

// Read the serial datachar
thisChar = mySerial.read();
if (thisChar == hash)
{ // read all x
while (xComplete == false && mySerial.available() > 0){
char thisChar = mySerial.read();
// Serial.println("x-loop");
if (thisChar == semicolon){
xComplete = true;
break;
}
else {
xVal[tagIndex] = thisChar;
tagIndex++;
}
}
tagIndex = 0; 

// read all y
while (yComplete == false && mySerial.available() > 0){
char thisChar = mySerial.read();
// Serial.println("y-loop");
if (thisChar == semicolon){
yComplete = true;
break; }
else {
yVal[tagIndex] = thisChar;
tagIndex++;
}
}
tagIndex = 0; 

// read all r
while (rComplete == false && mySerial.available() > 0){
char thisChar = mySerial.read();
// Serial.println("r-loop");
if (thisChar == semicolon){
rComplete = true;
break;
}
else {
rVal[tagIndex] = thisChar;
tagIndex++;
}
}
tagIndex = 0; 

if (xComplete == true && yComplete == true && rComplete == true){
// Can put in debugging here
}
}
}

void DataComplete(){  
// after all the data has been received and the LEDs flashed...  
mySerial.print("[Arduino;Bluetooth;capeMirror]");  
}

Ben

post a comment...

you must be logged in to post a comment.