編輯:關於android開發
藍牙BLE官方Demo下載地址: http://download.csdn.net/detail/lqw770737185/8116019
參考博客地址: http://www.eoeandroid.com/thread-563868-1-1.html?_dsign=843d16d6
設備:MX5手機一台,農藥殘留檢測儀一台(BLE終端設備)
目的:實現手機控制儀器,如發送打印指令,儀器能進行打印操作等
關於如何打開藍牙,配置相關權限,搜索BLE設備等步驟網上有很多資料,這裡就不多做作解釋了,本文主要講通信方面的內容。需要注意的是搜索BLE設備的結果是異步返回的,在BluetoothAdapter.LeScanCallback這個回調中返回,並且搜索過程是一個非常耗電的過程,所以我們應該做好相應處理,例如可以讓它搜索10s就停止搜索等。
在我們理解Android設備與BLE終端設備通信過程之前,我們需要來先了解幾個類:
BluetoothGatt:BluetoothGatt 是我們用的最多,也是我們最重要的一個類,為了盡可能通俗的理解,這裡我們可以把它看成Android手機與BLE終端設備建立通信的一個管道,只有有了這個管道,我們才有了通信的前提。
BluetoothGattService:藍牙設備的服務,在這裡我們把BluetoothGattService比喻成班級。而Bluetoothdevice我們把它比喻成學校,一個學校裡面可以有很多班級,也就是說我們每台BLE終端設備擁有多個服務,班級(各個服務)之間通過UUID(唯一標識符)區別。
BluetoothGattCharacteristic: 藍牙設備所擁有的特征,它是手機與BLE終端設備交換數據的關鍵,我們做的所有事情,目的就是為了得到它。在這裡我們把它比喻成學生,一個班級裡面有很多個學生,也就是說我們每個服務下擁有多個特征,學生(各個特征)之間通過UUID(唯一標識符)區別。
總結:當我們想要用手機與BLE設備進行通信時,實際上也就相當於我們要去找一個學生交流,首先我們需要搭建一個管道,也就是我們需要先獲取得到一個BluetoothGatt,其次我們需要知道這個學生在哪一個班級,學號是什麼,這也就是我們所說的serviceUUID,和charUUID。這裡我們還需要注意一下,找到這個學生後並不是直接和他交流,他就好像一個中介一樣,在手機和BLE終端設備之間幫助這兩者傳遞著信息,我們手機所發數據要先經過他,在由他傳遞到BLE設備上,而BLE設備上的返回信息,也是先傳遞到他那邊,然後手機再從他那邊進行讀取。
Android手機與BLE終端設備通信結果都是以回調的形式返回,如下是幾個常見的返回回調(可見於官方Demo的BluetoothLeservice類):
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { //連接狀態改變的回調 @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (newState == BluetoothProfile.STATE_CONNECTED) { // 連接成功後啟動服務發現 Log.e("AAAAAAAA", "啟動服務發現:" + mBluetoothGatt.discoverServices()); } }; //發現服務的回調 public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { Log.e(TAG, "成功發現服務"); }else{ Log.e(TAG, "服務發現失敗,錯誤碼為:" + status); } }; //寫操作的回調 public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { Log.e(TAG, "寫入成功" +characteristic.getValue()); } }; //讀操作的回調 public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { Log.e(TAG, "讀取成功" +characteristic.getValue()); } } //數據返回的回調(此處接收BLE設備返回數據) public void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic) { }; }; }
一、連接藍牙BLE終端設備
在我們打開藍牙,掃描發現想要連接的設備後,接下來要做的,當然就是去連接它了,連接方法很簡單,我們一句代碼就可以實現了(如下)。可以發現,當我們開始連接BLE終端設備的時候,連接方法就自動就幫我們返回了一個BluetoothGatt對象了,前面我們說到BluetoothGatt是我們最重要的一個類,它相當於一個管道,是我們建立通信的前提:(這裡面有三個參數,第一個參數是上下文對象,第二個參數是是否自動連接,這裡設置為false,第三個參數就是上面的回調方法)
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
連接成功與否都會通過下面這個回調來告訴我們:
// 連接狀態改變的回調 @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { //代表連接成功,此處我們可以發送一個廣播回去告訴activity已成功連接 if (newState == BluetoothProfile.STATE_CONNECTED) { //連接成功後啟動服務發現 Log.e("AAAAAAAA", "啟動服務發現:" + mBluetoothGatt.discoverServices()); } }
二、啟動服務發現
連接成功後,我們就要去尋找我們所需要的服務,這裡需要先啟動服務發現,使用一句代碼即可:
mBluetoothGatt.discoverServices() ;
啟動服務發現,它的結果也是通過回調函數返回:
// 發現服務的回調 public void onServicesDiscovered(BluetoothGatt gatt, int status) { //成功發現服務後可以調用相應方法得到該BLE設備的所有服務,並且打印每一個服務的UUID和每個服務下各個特征的UUID if (status == BluetoothGatt.GATT_SUCCESS) { List<BluetoothGattService> supportedGattServices =mBluetoothGatt.getServices(); for(int i=0;i<supportedGattServices.size();i++){ Log.e("AAAAA","1:BluetoothGattService UUID=:"+supportedGattServices.get(i).getUuid()); List<BluetoothGattCharacteristic> listGattCharacteristic=supportedGattServices.get(i).getCharacteristics(); for(int j=0;j<listGattCharacteristic.size();j++){ Log.e("a","2: BluetoothGattCharacteristic UUID=:"+listGattCharacteristic.get(j).getUuid()); } } } else { Log.e("AAAAA", "onservicesdiscovered收到: " + status); } }
我們也可以通過調用下面方法得知每個特征所具有的屬性:可讀或者可寫或者具備通知功能或者都具備等
// 循環遍歷服務以及每個服務下面的各個特征,判斷讀寫,通知屬性 for (BluetoothGattService gattService :supportedGattServices) { List<BluetoothGattCharacteristic> gattCharacteristics =supportedGattServices.getCharacteristics(); for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) { int charaProp = gattCharacteristic.getProperties(); if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) { // Log.e("nihao","gattCharacteristic的UUID為:"+gattCharacteristic.getUuid()); // Log.e("nihao","gattCharacteristic的屬性為: 可讀"); } if ((charaProp | BluetoothGattCharacteristic.PROPERTY_WRITE) > 0) { // Log.e("nihao","gattCharacteristic的UUID為:"+gattCharacteristic.getUuid()); // Log.e("nihao","gattCharacteristic的屬性為: 可寫"); } if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) { // Log.e("nihao","gattCharacteristic的UUID為:"+gattCharacteristic.getUuid()+gattCharacteristic); // Log.e("nihao","gattCharacteristic的屬性為: 具備通知屬性"); } } }
三、獲取Characteristic
之前我們說過,我們的最終目的就是獲取Characteristic來進行通信,正常情況下,我們可以從硬件工程師那邊得到serviceUUID和characteristicUUID,也就是我們所比喻的班級號和學號,以此來獲得我們的characteristic,但如果我們無法得知這兩個所需的UUID時,我們也可以通過上一步的方法來獲取(打印所有特征UUID,取出自己想要的特征)。這次試驗我就是通過此方法獲得,但是通過打印日志發現,雖然我這邊的BLE終端它每個服務下的所有特征都具有可讀可寫可通知屬性,但是只有characteristicUUID="0000ffe1-0000-1000-8000-00805f9b34fb"這個特征UUID能進行通信,它對應的serviceUUID="0000ffe0-0000-1000-8000-00805f9b34fb",暫且就先用這個,反正一個能用就行。假設我們在知道serviceUUID和characteristicUUID的前提下,我們就可以通過下面代碼獲取相應特征值:
BluetoothGattService service = mBluetoothGatt.getService(UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb")); BluetoothGattCharacteristic characteristic= service.getCharacteristic(UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));
四、開始通信
我們在得到一個相應的特征以後,接下來就可以開始讀寫操作進行通信了。
a.讀操作,讀操作比較簡單,只需將相應的特征值傳入即可得到該特征值下的數據,如下代碼:
mBluetoothGatt.readCharacteristic(characteristic);
讀取的結果通過onCharacteristicRead回調返回:(通過characteristic.getValue()就可以得到讀取到的值了)
// 讀操作的回調 public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { Log.e(TAG, "讀取成功" +characteristic.getValue()); } }
b.寫操作,寫操作是我們的重點,我們可以通過向characteristic寫入指令(發送指令)以此來達到控制BLE終端設備的目的:
//將指令放置進特征中 characteristic.setValue(new byte[] {0x7e, 0x14, 0x00, 0x00,0x00,(byte) 0xaa}); //設置回復形式 characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE); //開始寫數據 mBluetoothGatt.writeCharacteristic(chharacteristic);
注:與儀器通信,我們這裡發送的是16進制的數據,發送的時候需要先將其裝載到byte[]數組中,例如我發送 7e 14 00 00 00 aa這個指令,我需要把它轉化為ew byte[] {0x7e, 0x14, 0x00, 0x00,0x00,(byte) 0xaa }這樣去發送,因為BLE傳輸過程每次最大只能傳輸20個字節,所以如果發送的指令大於20字節的話要分包發送,例如現在要發送28個字節的,可以先write(前20個字節),開啟線程sleep(幾十毫秒)後在write(後面8個字節)。
五、BLE終端設備返回數據
當我們向BLE終端設備寫入指令時,如果寫入成功並且指令也正確,我們就會獲得相應的響應指令,在下面這個回調中我們可以得到BLE設備返回回來的響應指令(通過characteristic.getValue()取出返回數據):
// 數據返回的回調(此處接收機器返回數據並作處理) public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { Log.e("AAAAAAAA",characteristic.getValue()); };
接收到返回數據的前提是我們設置了該特征具有Notification功能,所以完整的寫操作代碼應該是這樣的(注意設置特征Notification的代碼要放在最前):
mBluetoothGatt.setCharacteristicNotification(characteristic,true) //將指令放置進來 characteristic.setValue(new byte[] {0x7e, 0x14, 0x00, 0x00,0x00,(byte) 0xaa}); //設置回復形式 characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE); //開始寫數據 mBluetoothGatt.writeCharacteristic(chharacteristic);
以上就是自己對Android手機與BLE設備通信一些初步認識,如果有哪裡說的不正確,還請指正。
mvp+retrofit+rxjava,retrofitrxjava引用 retrofit : com.squareup.retrofit2:r
從編程的角度理解gradle腳本??Android Studio腳本構建和編程 隨著Android 開發環境從Eclipse轉向Android Studio,我們每個
android:常用的AlertDialog對話框及自定義對話框 常用的Dialog有確認對話框,單選按鈕對話框,多選按鈕對話框,復選按鈕對話框另外還有自定義的對話框
Android基礎入門教程——10.11 傳感器專題(2)——方向傳感器 Android基礎入門教程——10.11 傳感器專題(2)—