Receiving sampled analog data on our phones from a sensor attached to an Arduino is illustrative of many tasks that we might want to accomplish using so let's go through a full example.
As you probably know better than I do, the Arduino has pins dedicated to sampling analog voltages as delivered from a sensor or a potentiometer. The Arduino site has a basic tutorial for reading those values periodically and sending them serially. This is precisely what we'll need to do but instead of sending via the normal serial connection we'll send via bluetooth.
By modifying Arduino's Analog Read Serial Tutorial: http://arduino.cc/en/Tutorial/AnalogReadSerial and combining it with our Bluetooth Serial Arduino code from last week we come up with something like the following:
#include <SoftwareSerial.h> int bluetoothTx = 2; // TX-O pin of bluetooth mate, Arduino D2 int bluetoothRx = 3; // RX-I pin of bluetooth mate, Arduino D3 // PIN that the sensor or potentiometer is connected to int analogPin = A0; // Setup the SoftwareSerial connection for our bluemate SoftwareSerial bluetooth(bluetoothTx, bluetoothRx); void setup() { Serial.begin(9600); // Begin the serial monitor at 9600bps - Just so we can see on the serial monitor bluetooth.begin(115200); // The Bluetooth Mate defaults to 115200bps bluetooth.print("$$$"); // Enter command mode delay(100); // Short delay, wait for the Mate to send back CMD bluetooth.println("U,9600,N"); // Temporarily Change the baudrate to 9600, no parity // 115200 can be too fast at times for NewSoftSerial to relay the data reliably bluetooth.begin(9600); // Start bluetooth serial at 9600 } void loop() { if(bluetooth.available()) // If the bluetooth sent any characters { // Send any characters the bluetooth prints to the serial monitor // Just informational Serial.print((char)bluetooth.read()); } // Simply read the value and print it out via println. This will send the value as ASCII int analogValue = analogRead(analogPin); bluetooth.println(analogValue); // Also prints it to the serial monitor, just informational Serial.println(analogValue); }
As we looked at last week once we pair with bluetooth device, we can connect to it at will and receive data serially. This is using a modified version of the BtSerial library from the Arduino folks that is included in the GitHub repo below.
In this example there is a button with the ID of "connectButton" that we are using to do the connection to the Arduino via bluetooth.
package com.example.bluetoothanalog; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.app.Activity; import cc.arduino.btserial.BtSerial; public class MainActivity extends Activity implements OnClickListener { public static final String LOGTAG = "BlueToothAnalog"; // I know the MAC address of the bluetooth address already public static final String BLUETOOTH_MAC_ADDRESS = "00:06:66:42:1F:DF"; // The println function on the Arduino will send a newline or ASCII code 10 after each sensor reading public static final int DELIMITER = 10; // Newline in ASCII // The modified version of the Arduino BtSerial library for Processing/Android BtSerial btserial; // The connect button Button connectButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Setup the connect button connectButton = (Button) this.findViewById(R.id.connectButton); connectButton.setOnClickListener(this); // Setup BtSerial btserial = new BtSerial(this); } @Override protected void onResume() { super.onResume(); } @Override protected void onPause() { super.onPause(); // Disconnect if our application goes to the background btserial.disconnect(); } // btSerialEvent will be triggered whenever there is new data public void btSerialEvent(BtSerial btserialObject) { // Use the "readStringUntil" function to read until we get the newline String serialValue = btserialObject.readStringUntil(DELIMITER); if (serialValue != null) { // Assuming it isn't null, log it Log.v(LOGTAG,"Data: " + serialValue); } } // Handle the button click to connect @Override public void onClick(View clickedView) { if (clickedView == connectButton) { if (btserial.isConnected()) { Log.v(LOGTAG, "Already Connected, Disconnecting"); btserial.disconnect(); } btserial.connect(BLUETOOTH_MAC_ADDRESS); if (btserial.isConnected()) { Log.v(LOGTAG,"Connected"); } else { Log.v(LOGTAG,"Not Connected"); } } } }
If we want to do something with that data, we have to do a bit more work. Here is the above code with the addition of sending the data to a custom view that we can draw on MyDrawingView
package com.example.bluetoothanalog; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.app.Activity; import cc.arduino.btserial.BtSerial; public class MainActivity extends Activity implements OnClickListener { public static final String LOGTAG = "BlueToothAnalog"; public static final String BLUETOOTH_MAC_ADDRESS = "00:06:66:42:1F:DF"; public static final int DELIMITER = 10; // Newline in ASCII BtSerial btserial; // Declare the custom view MyDrawingView myDrawingView; Button connectButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); connectButton = (Button) this.findViewById(R.id.connectButton); connectButton.setOnClickListener(this); // Setup the custom view myDrawingView = (MyDrawingView) this.findViewById(R.id.myDrawingView); btserial = new BtSerial(this); } @Override protected void onResume() { super.onResume(); } @Override protected void onPause() { super.onPause(); btserial.disconnect(); } // Handlers let us interact with threads on the UI thread // The handleMessage method receives messages from other threads and will act upon it on the UI thread Handler handler = new Handler() { @Override public void handleMessage(Message msg) { // Pull out the data that was packed into the message with the key "serialvalue" int messageData = msg.getData().getInt("serialvalue"); // Send it over to the custom view myDrawingView.setYoverTime(messageData); } }; public void btSerialEvent(BtSerial btserialObject) { String serialValue = btserialObject.readStringUntil(DELIMITER); if (serialValue != null) { Log.v(LOGTAG,"Data: " + serialValue); try { // The data is coming to us as an ASCII string so we have to turn it into an int // First we have to trim it to remove the newline int intSerialValue = Integer.parseInt(serialValue.trim()); // Since btSerialEvent is happening in a separate thread, // we need to use a handler to send a message in order to interact with the UI thread // First we obtain a message object Message msg = handler.obtainMessage(); // Create a bundle to hold data Bundle bundle = new Bundle(); // Put our value with the key "serialvalue" bundle.putInt("serialvalue", intSerialValue); // Set the message data to our bundle msg.setData(bundle); // and finally send the message via the handler handler.sendMessage(msg); } catch (NumberFormatException nfe) { // Not a number Log.v(LOGTAG,"" + serialValue + " is not a number"); } } } @Override public void onClick(View clickedView) { if (clickedView == connectButton) { if (btserial.isConnected()) { Log.v(LOGTAG, "Already Connected, Disconnecting"); btserial.disconnect(); } btserial.connect(BLUETOOTH_MAC_ADDRESS); if (btserial.isConnected()) { Log.v(LOGTAG,"Connected"); } else { Log.v(LOGTAG,"Not Connected"); } } } }
Here is a full example: https://github.com/vanevery/BlueToothAnalog (note: I made some significant changes to the BtSerial library and have included it in the project on GitHub as I haven't had a chance to clean it up and send it to the Arduino folks yet.)
Don't forget permissions:
android.permission.BLUETOOTH