Android基於藍芽串列埠程式設計實現HC-05通訊
Android基於藍芽串列埠程式設計實現HC-05通訊
最近接了個工程自動化的專案,需求是實時接收從微控制器傳過來的資料,並進行資料分析處理再進行顯示,在查閱大量的相關部落格和自己踩了不少的坑後,想說把自己的一些經驗分享出來給後來人做個參考www
先介紹下藍芽串列埠的定義
藍芽串列埠是基於SPP協議(Serial Port Profile),能在藍芽裝置之間建立串列埠進行資料傳輸的一種裝置。藍芽串列埠的目的是針對如何在兩個不同裝置(通訊的兩端)上的應用之間保證一條完整的通訊路徑。
目前應用商店可以下載到的藍芽串列埠app就是基於SPP協議,而有一些藍芽搜尋app搜尋不到HC-05就是由於沒有實現藍芽串列埠服務。要想要在自己的app內實現SPP協議需要服務對應的UUID,藍芽串列埠服務的UUID為:
SerialPortServiceClass_UUID = '{00001101-0000-1000-8000-00805F9B34FB}'
更多的手機藍芽各類服務對應的UUID,可以通過下面這個網站進行查詢:
https://www.douban.com/group/topic/20009323/
順便講下藍芽串列埠app的使用,首先需要在系統設定裡,連線上HC-05的藍芽,預設配對密碼為1234,預設波特率為9600,預設名為HC-05。最好在連線後再看一下對應的MAC地址,因為我做的是單一連線,微控制器同一時間只能接入一個藍芽裝置,所以需求對更改連線藍芽模組需求要求不大,如果使用者不在建立專案時更改裝置MAC地址,則使用的就是預設的MAC地址,所以也沒有做選擇藍芽裝置的模組。
部落格附本專案截圖以及專案原始碼地址。
需要的許可權
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- 6.0以上需要加的額外許可權 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
獲取藍芽介面卡
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
不支援藍芽時
// If the adapter is null, then Bluetooth is not supported
if (mBluetoothAdapter == null) {
Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
finish();
}
繫結藍芽裝置
// String MACAddr = "xx:xx:xx:xx:xx:xx";
BluetoothDevice bluetoothDevice = mBluetoothAdapter.getRemoteDevice(MACAddr);
*如果檢測到藍芽沒開啟,呼叫系統藍芽設定(可選)
Intent intent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
startActivity(intent);
連線裝置,開啟藍芽連線執行緒
public void connect(BluetoothDevice device) {
printLog("connect to: " + device);
// Start the thread to connect with the given device
mConnectThread = new ConnectThread(device);
mConnectThread.start();
}
連線執行緒
/**
* This thread runs while attempting to make an outgoing connection with a
* device. It runs straight through; the connection either succeeds or
* fails.
*/
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try {
tmp = device.createRfcommSocketToServiceRecord(UUID.fromString(App.SPP_UUID));
} catch (IOException e) {
printLog("create() failed" + e);
}
mmSocket = tmp;
}
public void run() {
if (Thread.interrupted())
return;
setName("ConnectThread");
// Always cancel discovery because it will slow down a connection
mBluetoothAdapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
isBlueToothConnected = true;
mmSocket.connect();
} catch (IOException e) {
printLog("unable to connect() socket " + e);
handler.sendEmptyMessage(NOT_CONNECT);
isBlueToothConnected = false;
// Close the socket
try {
mmSocket.close();
} catch (IOException e2) {
printLog("unable to close() socket during connection failure" + e2);
}
return;
}
mConnectThread = null;
isBlueToothConnected = true;
// Start the connected thread
// Start the thread to manage the connection and perform
// transmissions
handler.sendEmptyMessage(CONNECT_SUCCESS);
mConnectedThread = new ConnectedThread(mmSocket);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
printLog("close() of connect socket failed" + e);
}
}
}
資料傳輸執行緒(可讀可寫,需求只用讀取)
**
* This thread runs during a connection with a remote device. It handles all
* incoming and outgoing transmissions.
*/
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
printLog("create ConnectedThread");
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
printLog("temp sockets not created" + e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
if (Thread.interrupted()) {
printLog("return");
return;
}
printLog("BEGIN mConnectedThread");
byte[] buffer = new byte[256];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
synchronized (this) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
Message msg = new Message();
msg.what = GET_DATA;
Bundle bundle = new Bundle();
bundle.putInt("data", buffer[0]);
msg.setData(bundle);
handler.sendMessage(msg);
} catch (IOException e) {
printLog("disconnected " + e);
// handler.sendEmptyMessage(OUT_OF_CONNECTED);
break;
}
}
}
}
/**
* Write to the connected OutStream.
*
* @param buffer The bytes to write
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
停止藍芽連線
private void stopBlutoothThread() {
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
}
專案截圖
原始碼可以在我的Github上看到
專案地址:https://github.com/WithLei/DistanceMeasure