蓝牙BLE官方Demo下载地址: http://download.csdn.net/detail/lqw770737185/8116019
参考博客地址: http://www.eoeandroid.com/thread-563868-1-1.html?_dsign=843d16d6html
设备:MX5手机一台,农药残留检测仪一台(BLE终端设备)android
目的:实现手机控制仪器,如发送打印指令,仪器能进行打印操做等数组
关于如何打开蓝牙,配置相关权限,搜索BLE设备等步骤网上有不少资料,这里就很少作做解释了,本文主要讲通讯方面的内容。须要注意的是搜索BLE设备的结果是异步返回的,在BluetoothAdapter.LeScanCallback这个回调中返回,而且搜索过程是一个很是耗电的过程,因此咱们应该作好相应处理,例如可让它搜索10s就中止搜索等。异步
在咱们理解Android设备与BLE终端设备通讯过程以前,咱们须要来先了解几个类:ide
BluetoothGatt:BluetoothGatt 是咱们用的最多,也是咱们最重要的一个类,为了尽量通俗的理解,这里咱们能够把它当作Android手机与BLE终端设备创建通讯的一个管道,只有有了这个管道,咱们才有了通讯的前提。函数
BluetoothGattService:蓝牙设备的服务,在这里咱们把BluetoothGattService比喻成班级。而Bluetoothdevice咱们把它比喻成学校,一个学校里面能够有不少班级,也就是说咱们每台BLE终端设备拥有多个服务,班级(各个服务)之间经过UUID(惟一标识符)区别。ui
BluetoothGattCharacteristic: 蓝牙设备所拥有的特征,它是手机与BLE终端设备交换数据的关键,咱们作的全部事情,目的就是为了获得它。在这里咱们把它比喻成学生,一个班级里面有不少个学生,也就是说咱们每一个服务下拥有多个特征,学生(各个特征)之间经过UUID(惟一标识符)区别。this
总结:当咱们想要用手机与BLE设备进行通讯时,实际上也就至关于咱们要去找一个学生交流,首先咱们须要搭建一个管道,也就是咱们须要先获取获得一个BluetoothGatt,其次咱们须要知道这个学生在哪个班级,学号是什么,这也就是咱们所说的serviceUUID,和charUUID。这里咱们还须要注意一下,找到这个学生后并非直接和他交流,他就好像一个中介同样,在手机和BLE终端设备之间帮助这二者传递着信息,咱们手机所发数据要先通过他,在由他传递到BLE设备上,而BLE设备上的返回信息,也是先传递到他那边,而后手机再从他那边进行读取。spa
Android手机与BLE终端设备通讯结果都是以回调的形式返回,以下是几个常见的返回回调(可见于官方Demo的BluetoothLeservice类):.net
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) { }; }; }
1、链接蓝牙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()); } }
2、启动服务发现
链接成功后,咱们就要去寻找咱们所须要的服务,这里须要先启动服务发现,使用一句代码便可:
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的属性为: 具有通知属性"); } } }
3、获取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"));
4、开始通讯
咱们在获得一个相应的特征之后,接下来就能够开始读写操做进行通讯了。
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个字节)。
5、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设备通讯一些初步认识,若是有哪里说的不正确,还请指正。