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:

01/* Hello Software Serial Mode
02* -------------------------- * *
03 
04turns on and off an LED on Pin 13
05according to the number transmitted
06to the arduino via the bluesmirf.
07 
08Created 17 June 2008 by Ben at cape ealing
09*/
10 
11// include the SoftwareSerial library so you can use its functions:
12#include <SoftwareSerial.h>
13 
14// define the pins on the arduino: 7 to rx, 6 to tx, 13 to flash
15#define rxPin 7
16#define txPin 6
17#define flashPin 13
18 
19// set up a new serial connection using pins 7 and 6
20SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);
21 
22// the setup part of the script
23void setup()  {
24 
25  // define pin modes for tx, rx: 
26  pinMode(rxPin, INPUT); 
27  pinMode(txPin, OUTPUT); 
28  pinMode(flashPin, OUTPUT);
29 
30  // set the data rate for the serial port 
31  mySerial.begin(9600);}
32 
33// the main part of the script
34void loop() {
35 
36  //get the value from the receive pin 
37  int val = mySerial.read();
38 
39  //turn that value from ASCII to an integer 
40  val = val - '0';
41 
42  //print out the value just obtained 
43  mySerial.print(val);
44 
45  // print a linefeed character 
46  mySerial.println();
47 
48  // flash the LED the number of times entered 
49  for (int i=0; i < val; i++){ 
50  digitalWrite(flashPin,HIGH); 
51  delay(500); 
52  digitalWrite(flashPin,LOW);  delay(500); 
53  }
54}

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:

01Module Module1
02 
03    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
04    'Connect to Arduino over Bluetooth via the serial port.
05    '
06    'created by Ben at Cape Ealing
07    '17 June 2008
08    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
09 
10    Public Sub Main()
11 
12        Dim Arduino_SerialPort As New IO.Ports.SerialPort
13 
14        'First see if the serial port is open, if not open it
15        If Arduino_SerialPort.IsOpen = False Then
16            With Arduino_SerialPort
17                .PortName = "COM7"
18                .BaudRate = 9600
19                .DataBits = 8
20                .Parity = IO.Ports.Parity.None
21                .StopBits = IO.Ports.StopBits.One
22                .Encoding = System.Text.Encoding.ASCII
23                .ReadTimeout = 5000
24            End With
25            Arduino_SerialPort.Open()
26        End If
27 
28        'send one byte of data: 5
29        Arduino_SerialPort.Write("5")
30 
31    End Sub
32 
33End 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.

29'Arduino_SerialPort.Write("5")
30'Comment out the line above and add the line below
31Arduino_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.

001/* AFSoft Serial Mode - Multi-Bits
002* --------------------------------------- * *
003Turns on and off an LED on Pin 13 according to the number
004transmitted to the arduino via the bluesmirf. Can now
005receive a number larger than 1-bit.
006Sending #5;10;15; will: flash Pin 11 x 5, Pin 12 x 10, Pin 13 x 15.
007 
008Acknowledgements
009The difficult serial parsing bit was came from Nition
010see forum post at:
012 
013The AFSoftwareSerial library came from ladyada.
014It adds the serial.available functionality.
016 
017Created 19 June 2008 * by Ben
018*/
019 
020// include the AFSoftSerial library
021#include <AFSoftSerial.h>
022 
023// define the pins on the arduino: 7 to rx, 6 to tx, 13 to flash
024#define rxPin 7
025#define txPin 6
026#define flashxPin 11
027#define flashyPin 12
028#define flashrPin 13
029 
030//define the variables for parsing serial data
031#define tagLength 6 // each tag ID contains 6 bytes
032#define hash 0x23 // "#" hash
033#define semicolon 0x3b // ";" semicolon
034#define dataRate 9600 // 9600kbps
035int tagIndex = 0; // counter for number of bytes read
036int allComplete = false; // whether all tags have been read
037char xVal[tagLength], yVal[tagLength], rVal[tagLength];
038char thisChar;
039int xComplete = false;
040int yComplete = false;
041int rComplete = false;
042 
043// set up a new serial connection using pins 7 and 6
044AFSoftSerial mySerial = AFSoftSerial(rxPin, txPin);
045 
046// the setup part of the script
047void setup() {
048 
049// define pin modes for tx, rx
050pinMode(rxPin, INPUT);
051pinMode(txPin, OUTPUT);
052pinMode(flashxPin, OUTPUT);
053pinMode(flashyPin, OUTPUT);
054pinMode(flashrPin, OUTPUT);
055 
056// set the data rate for the serial port
057mySerial.begin(dataRate);}
058 
059// the main part of the script
060void loop() {
061 
062// read in and parse serial data
063if (mySerial.available() > 0) {
064  delay(1500);  // wait for all data. 1.5s works fine. could be shorter.
065 
066readData(); // call the function to read the data that's been received
067 
068// flash the Pin 11 [xVal] number of times
069for (int a=0; a<atoi(xVal);a++){
070digitalWrite(flashxPin,HIGH);
071delay(250);
072digitalWrite(flashxPin,LOW);
073delay(250);
074}
075 
076// flash the Pin 12 [yVal] number of times
077for (int a=0; a<atoi(yVal);a++){
078digitalWrite(flashyPin,HIGH);
079delay(250);
080digitalWrite(flashyPin,LOW);
081delay(250);
082}
083 
084// flash the Pin 13 [rVal] number of times
085for (int a=0; a<atoi(rVal);a++){
086digitalWrite(flashrPin,HIGH);
087delay(250);
088digitalWrite(flashrPin,LOW);
089delay(250);
090}
091 
092} // end if
093} // end loop
094 
095void readData() {
096 
097// Reset all the variables
098xComplete = false;
099yComplete = false;
100rComplete = false;
101 
102for (int i=0;i<5;i++){
103digitalWrite(5, HIGH);
104xVal[i] = 0x00;
105yVal[i] = 0x00;
106rVal[i] = 0x00;
107}
108 
109// Read the serial datachar
110thisChar = mySerial.read();
111if (thisChar == hash)
112{ // read all x
113while (xComplete == false && mySerial.available() > 0){
114char thisChar = mySerial.read();
115// Serial.println("x-loop");
116if (thisChar == semicolon){
117xComplete = true;
118break;
119}
120else {
121xVal[tagIndex] = thisChar;
122tagIndex++;
123}
124}
125tagIndex = 0;
126 
127// read all y
128while (yComplete == false && mySerial.available() > 0){
129char thisChar = mySerial.read();
130// Serial.println("y-loop");
131if (thisChar == semicolon){
132yComplete = true;
133break; }
134else {
135yVal[tagIndex] = thisChar;
136tagIndex++;
137}
138}
139tagIndex = 0;
140 
141// read all r
142while (rComplete == false && mySerial.available() > 0){
143char thisChar = mySerial.read();
144// Serial.println("r-loop");
145if (thisChar == semicolon){
146rComplete = true;
147break;
148}
149else {
150rVal[tagIndex] = thisChar;
151tagIndex++;
152}
153}
154tagIndex = 0;
155 
156if (xComplete == true && yComplete == true && rComplete == true){
157// Can put in debugging here
158}
159}
160}

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:

01Module Module1
02    Public WithEvents Arduino_SerialPort As IO.Ports.SerialPort
03    Public ReceivedDataYet As Boolean
04 
05    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
06    'Connect to Arduino over Bluetooth via the serial port.
07    '
08    'created by Ben at Cape Ealing
09    '17 June 2008
10    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
11 
12    Public Sub Main()
13 
14        Dim Arduino_SerialPort As New IO.Ports.SerialPort
15        Dim RxChar As Char
16        Dim RxMessage As String
17 
18        'Empty the variables       
19        RxChar = ""
20        RxMessage = ""
21 
22        'First see if the serial port is open, if not open it
23        If Arduino_SerialPort.IsOpen = False Then
24            With Arduino_SerialPort
25                .PortName = "COM7"
26                .BaudRate = 9600
27                .DataBits = 8
28                .Parity = IO.Ports.Parity.None
29                .StopBits = IO.Ports.StopBits.One
30                .Encoding = System.Text.Encoding.ASCII
31                .ReadTimeout = 5000
32            End With
33            Arduino_SerialPort.Open()
34        End If
35 
36        'send the portions of data
37        Arduino_SerialPort.Write("#5;10;15;#")
38 
39        'Wait until the Arduino sends back it's message
40        Do Until Arduino_SerialPort.BytesToRead > 0
41        Loop
42 
43        'Collect the message one byte at a time
44        Do
45            RxChar = ChrW(Arduino_SerialPort.ReadByte)
46            RxMessage = RxMessage & RxChar
47        Loop Until RxChar = "]"
48 
49        'Display the message
50        MsgBox(RxMessage)
51 
52    End Sub
53End Module

The arduino sketch looks like this:

001/* AFSoft Serial Mode - Multi-Bits
002* --------------------------------------- * *
003Turns on and off an LED on Pin 13 according to the number
004transmitted to the arduino via the bluesmirf. Can now
005receive a number larger than 1-bit.
006Sending #5;10;15; will: flash Pin 11 x 5, Pin 12 x 10, Pin 13 x 15.
007 
008Acknowledgements
009The difficult serial parsing bit was came from Nition
010see forum post at:
012 
013The AFSoftwareSerial library came from ladyada.
014It adds the serial.available functionality.
016 
017Created 19 June 2008 * by Ben
018*/
019 
020// include the AFSoftSerial library
021#include <AFSoftSerial.h>
022 
023// define the pins on the arduino: 7 to rx, 6 to tx, 13 to flash
024#define rxPin 7
025#define txPin 6
026#define flashxPin 11
027#define flashyPin 12
028#define flashrPin 13
029 
030//define the variables for parsing serial data
031#define tagLength 6 // each tag ID contains 6 bytes
032#define hash 0x23 // "#" hash
033#define semicolon 0x3b // ";" semicolon
034#define dataRate 9600 // 9600kbps
035int tagIndex = 0; // counter for number of bytes read
036int allComplete = false; // whether all tags have been read
037char xVal[tagLength], yVal[tagLength], rVal[tagLength];
038char thisChar;
039int xComplete = false;
040int yComplete = false;
041int rComplete = false;
042 
043// set up a new serial connection using pins 7 and 6
044AFSoftSerial mySerial = AFSoftSerial(rxPin, txPin);
045 
046// the setup part of the script
047void setup() {
048 
049// define pin modes for tx, rx
050pinMode(rxPin, INPUT);
051pinMode(txPin, OUTPUT);
052pinMode(flashxPin, OUTPUT);
053pinMode(flashyPin, OUTPUT);
054pinMode(flashrPin, OUTPUT);
055 
056// set the data rate for the serial port
057mySerial.begin(dataRate);}
058 
059// the main part of the script
060void loop() {
061 
062// read in and parse serial data
063if (mySerial.available() > 0) {
064  delay(1500);  // wait for all data to be in. 1500 works fine. could try shorter
065 
066readData(); // call the function to read the data that's been received
067 
068// flash the Pin 11 [xVal] number of times
069for (int a=0; a<atoi(xVal);a++){
070digitalWrite(flashxPin,HIGH);
071delay(250);
072digitalWrite(flashxPin,LOW);
073delay(250);
074}
075 
076// flash the Pin 12 [yVal] number of times
077for (int a=0; a<atoi(yVal);a++){
078digitalWrite(flashyPin,HIGH);
079delay(250);
080digitalWrite(flashyPin,LOW);
081delay(250);
082}
083 
084// flash the Pin 13 [rVal] number of times
085for (int a=0; a<atoi(rVal);a++){
086digitalWrite(flashrPin,HIGH);
087delay(250);
088digitalWrite(flashrPin,LOW);
089delay(250);
090}
091 
092// run the DataComplete procedure
093DataComplete();
094 
095} // end if
096} // end loop
097 
098void readData() {
099 
100// Reset all the variables
101xComplete = false;
102yComplete = false;
103rComplete = false;
104 
105for (int i=0;i<5;i++){
106digitalWrite(5, HIGH);
107xVal[i] = 0x00;
108yVal[i] = 0x00;
109rVal[i] = 0x00;
110}
111 
112// Read the serial datachar
113thisChar = mySerial.read();
114if (thisChar == hash)
115{ // read all x
116while (xComplete == false && mySerial.available() > 0){
117char thisChar = mySerial.read();
118// Serial.println("x-loop");
119if (thisChar == semicolon){
120xComplete = true;
121break;
122}
123else {
124xVal[tagIndex] = thisChar;
125tagIndex++;
126}
127}
128tagIndex = 0;
129 
130// read all y
131while (yComplete == false && mySerial.available() > 0){
132char thisChar = mySerial.read();
133// Serial.println("y-loop");
134if (thisChar == semicolon){
135yComplete = true;
136break; }
137else {
138yVal[tagIndex] = thisChar;
139tagIndex++;
140}
141}
142tagIndex = 0;
143 
144// read all r
145while (rComplete == false && mySerial.available() > 0){
146char thisChar = mySerial.read();
147// Serial.println("r-loop");
148if (thisChar == semicolon){
149rComplete = true;
150break;
151}
152else {
153rVal[tagIndex] = thisChar;
154tagIndex++;
155}
156}
157tagIndex = 0;
158 
159if (xComplete == true && yComplete == true && rComplete == true){
160// Can put in debugging here
161}
162}
163}
164 
165void DataComplete(){ 
166// after all the data has been received and the LEDs flashed... 
167mySerial.print("[Arduino;Bluetooth;capeMirror]"); 
168}

Ben

post a comment...

you must be logged in to post a comment.