美文网首页读书Android核心技术
低功耗蓝牙原理与实现

低功耗蓝牙原理与实现

作者: 安卓技术砖家 | 来源:发表于2021-07-22 00:05 被阅读0次

    最近公司提出一个需求:如果当前安卓手机支持BLE(Bluetooth Low Energy 低功耗蓝牙),则需要将当前的手机和车机通过蓝牙进行互联,并实现通信。由于之前没有接触过BLE相关的内容,实现的过程中遇到了许多困难,但也因此学到了不少的知识,因此想写下这篇文章与大家分享。文章主要包括以下几个内容:

    1. BLE原理详解
    2. BLE相关的几个概念详解
    3. BLE相关的几个类详解
    4. BLE实现的前提条件
    5. BLE使用的一般流程
    6. BLE使用过程中遇到的一些坑
    7. 参考资料

    原理详解

    1. 蓝牙通信的主从关系

    蓝牙技术规定每一对设备之间进行蓝牙通讯时,必须一个为主角色,另一为从角色,才能进行通信,通信时,必须由主端进行查找,发起配对,建链成功后,双方即可收发数据。理论上,一个蓝牙主端设备,可同时与7个蓝牙从端设备进行通讯。一个具备蓝牙通讯功能的设备,可以在两个角色间切换,平时工作在从模式,等待其它主设备来连接,需要时,转换为主模式,向其它设备发起呼叫。一个蓝牙设备以主模式发起呼叫时,需要知道对方的蓝牙地址,配对密码等信息,配对完成后,可直接发起呼叫。这可以解释为什么有时无法连接蓝牙,有可能是连接的蓝牙设备过多。

    1. 蓝牙的呼叫过程

    蓝牙主端设备发起呼叫,首先是查找,找出周围处于可被查找的蓝牙设备。主端设备找到从端蓝牙设备后,与从端蓝牙设备进行配对,此时需要输入从端设备的PIN码,也有设备不需要输入PIN码。配对完成后,从端蓝牙设备会记录主端设备的信任信息,此时主端即可向从端设备发起呼叫,已配对的设备在下次呼叫时,不再需要重新配对。已配对的设备,做为从端的蓝牙耳机也可以发起建链请求,但做数据通讯的蓝牙模块一般不发起呼叫。链路建立成功后,主从两端之间即可进行双向的数据或语音通讯。在通信状态下,主端和从端设备都可以发起断链,断开蓝牙链路。

    1. 蓝牙一对一的串口数据传输应用

    蓝牙数据传输应用中,一对一串口数据通讯是最常见的应用之一,蓝牙设备在出厂前即提前设好两个蓝牙设备之间的配对信息,主端预存有从端设备的PIN码、地址等,两端设备加电即自动建链,透明串口传输,无需外围电路干预。一对一应用中从端设备可以设为两种类型,一是静默状态,即只能与指定的主端通信,不被别的蓝牙设备查找;二是开发状态,既可被指定主端查找,也可以被别的蓝牙设备查找建链。


    低功耗蓝牙相关的几个概念详解

    1. BLE 全称为Bluetooth Low Energy,即低功耗蓝牙
    2. GATT 全称为Generic Attribute Profile,即通用属性协议
      通过BLE连接,读写属性类小数据的Profile通用规范。现在所有的BLE应用Profile都是基于GATT的。GATT包含若干个Profile,一个Profile包含若干个Services,一个Service包含若干个Characteristics,一个Characteristic包含Properties字段和若干个Descriptor(可选)。
      GATT调用下层的ATT,ATT的attirbute在GATT中表现为Characteristic。有关GATT相关的东西,这篇博客写的很清楚,有兴趣的朋友可以看看。Generic Attribute Profile (GATT) 通用属性协议
    3. ATT 全称Attribute Protocol
      GATT是基于ATT Protocol的。ATT针对BLE设备做了专门的优化,具体就是在传输过程中使用尽量少的数据。每个属性都有一个唯一的UUID,属性将以characteristics and services的形式传输。
    4. UUID 全称Universally Unique Identifier,即通用唯一识别码
      在BLE中,所有的Service,Service包含的Characteristic,以及Characteristic包含的Descriptor都是通过UUID进行标识的。
    5. Service
      Characteristic的集合。例如一个service叫做“Heart Rate Monitor”,它可能包含多个Characteristics,其中可能包含一个叫做“heart ratemeasurement”的Characteristic。一个手环可能。
    6. Characteristic
      Characteristic可以理解为一个数据类型,它包括一个value和0至多个对次value的描述(Descriptor)。
    7. Descriptor
      对Characteristic的描述,例如范围、计量单位等。

    低功耗蓝牙相关的几个类详解

    1. BluetoothManager。通过Context.getSystemService(Context.BLUETOOTH_SERVICE)获得,主要是用于获取BluetoothAdapter实例。
    2. BluetoothAdapter。BLE的主要操作都是通过BluetoothAdapter来实现的,比如判断当前设备的BLE是否可用,是否打开,以及扫描,停止扫描,获取远程设备等。
    3. BluetoothDevice。代表设备上发现的BLE设备,相当于一个Bean,里面包含BLE设备的许多信息,比如蓝牙的名称,蓝牙的地址,同时也是通过它进行连接操作的,同时返回一个BluetoothGatt对象等等。
    4. BluetoothGatt。包含一些 Bluetooth GATT Profile公用的API,比如发现服务,读数据,写数据,判断设备是否在连接状态,断开连接等等。
    5. BluetoothGattService。代表一个Bluetooth GATT Service
    6. BluetoothGattCharacteristic。Represents a Bluetooth GATT Characteristic
    7. BluetoothGattDescriptor。代表一个Bluetooth GATT Descriptor

    实现的前提条件

    首先当前的设备必须要支持BLE,且Android系统必须在4.3或以上。和经典蓝牙一样,应用使用蓝牙,需要声明BLUETOOTH权限,如果需要扫描设备或者操作蓝牙设置,则还需要BLUETOOTH_ADMIN权限:

    除了蓝牙权限外,如果需要BLE feature则还需要声明uses-feature:按时required为true时,则应用只能在支持BLE的Android设备上安装运行;required为false时,Android设备均可正常安装运行,需要在代码运行时判断设备是否支持BLE feature:

    if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)){
        Toast.makeText(this, R.string.ble_not_supported,Toast.LENGTH_SHORT).show();
        finish();
    }
    

    低功耗蓝牙使用的一般流程

    1. 在AndroidManifest文件中添加相关的权限和相关的特征;
    2. 检查当前设备是否支持BLE,并且蓝牙是否打开;
    3. 扫描设备;
    4. 连接指定设备;
    5. 对指定设备进行读写等操作;
    6. 断开连接;
    7. 关闭蓝牙

    使用过程中遇到的一些坑

    1. 扫描到蓝牙后,除了BluetoothDevice里面发现的名称和地址之外,没有获取设备里包含的更多信息:在BluetoothAdapter.LeScanCallback中的onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord)回调函数,第三个参数scanRecord中包含了更多远程设备的信息。
    2. 写数据收不到反馈信息(onCharacteristicChanged()函数就是不回调):首先要确保打开了对应的通知,其次要确保相应的Descriptor执行了类似以下的操作:
    if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
            UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
        descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
        mBluetoothGatt.writeDescriptor(descriptor);
    }
    
    1. 写数据写两次才能收到反馈信息:这个问题真的是非常奇怪,就是明明用正确的方式打开了通知,可是就是收不到数据,但是写两次就可以收到数据。后来的解决方案是:在打开通知以后,延迟1秒进行写操作,就成功了。想必应该是打开通知也是需要时间的,必须在通知打开完成之后,进行写操作才能收到对象的信息。
    2. 发现服务后,在ExpandableListView中无法显示数据:解决方案也是通过Handler延迟0.5S左右就可以正常显示了。

    参考资料

    1. BLE简介和Android BLE编程
    2. Generic Attribute Profile (GATT) 通用属性协议
    3. android ble 的各种坑
    4. Android 蓝牙4.0 ble 官方 demo

    相关文章

      网友评论

        本文标题:低功耗蓝牙原理与实现

        本文链接:https://www.haomeiwen.com/subject/jofjmltx.html