AndroidBLE开发——Android手机与BLE终端通信初识

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

AndroidBLE开发——Android⼿机与BLE终端通信初识
设备: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设备通信⼀些初步认识,如果有哪⾥说的不正确,还请指正。

相关文档
最新文档