猪小花1号

个人签名

283篇博客

BLE低功耗蓝牙及其在iOS上的应用

猪小花1号2018-09-05 16:04

作者:刘国建


BLE简介

 BLE是蓝牙低能耗的简称(Bluetooh Low Energy)。蓝牙低能耗(BLE)技术是低成本、短距离、可互操作的鲁棒性无线技术,工作在免许可的2.4GHz ISM射频频段。它从一开始就设计为超低功耗(ULP)无线技术。它利用许多智能手段最大限度地降低功耗。
 蓝牙低能耗架构共有两种芯片构成:单模芯片和双模芯片。蓝牙单模芯片可以和其它单模芯片及双模芯片通信,此时后者需要使用自身架构中的蓝牙低能耗技术部分进行收发数据。双模芯片也能与标准蓝牙技术及使用传统蓝牙架构的其它双模芯片通信。
双模芯片可以在目前使用标准蓝牙芯片的任何场合使用。这样安装有双模芯片的手机、PC、个人导航设备(PND)或其它应用就可以和市场上已经在用的所有传统标准蓝牙设备以及所有未来的蓝牙低能耗设备通信。然而,由于这些设备要求执行标准蓝牙和蓝牙低能耗任务,因此双模芯片针对ULP操作的优化程度没有像单模芯片那么高。
  单模芯片可以用单节钮扣电池(如3V、220mAh的CR2032)工作很长时间(几个月甚至几年)。相反,标准蓝牙技术(和蓝牙低能耗双模器件)通常要求使用至少两节AAA电池(电量是钮扣电池的10至12倍,可以容忍高得多的峰值电流),并且更多情况下最多只能工作几天或几周的时间(取决于具体应用)。注意,也有一些高度专业化的标准蓝牙设备,它们可以使用容量比AAA电池低的电池工作。

版本:4.0,4.1,4.2 目前三个
SIG在2010年发布了4.0的specification,2013年发布了4.1的specification,一年以后,在2014年又发布了4.2的specification,specification的调整很快。从4.0版本起,革命性的加入了BLE协议部分,同时将2.1+EDR和3.0+HS全都包含在内,4.1和4.2在4.0的基础上做了改进,主要包括连接速度,传输效率等等,可以看出是向着适用于物联网的方向做的改进(蓝牙也在布局智能家居,笔者认为如果蓝牙能改善联网特性的话,蓝牙比zigbee和WiFi协议更加适合智能家居的互联需求)。
首先,比较蓝牙4.0、4.1、4.2 specification的可以看出最明显的特点是,4.1和4.2增加了一个volume 7:Wireless Coexistence volume。主要介绍手机的无线共存测试。移动通讯采用4G-LTE标准后会占用2.4GHz频段,4.1和4.2的specification对此做出了测试。
4.1和4.2在4.0的基础上添加了IPv6和6LowPAN,搭载蓝牙芯片的设备可以取得在互联网上的唯一标记,与其他的联网设备进行通讯。
4.1和4.2提高了4.0的传输速率,4.0的协议栈规定了每包承载有效数据不大于20字节,4.2把这个数值扩大了10倍,最终将BLE的传输速率提高了2.5倍,不过需要对等的支持4.2的设备才能看出来效果。
4.1和4.2实现了主从一体,比如你的智能手环作为主和防丢器连接的时候,智能手环同时也可以作为从和智能手机相连。
4.1和4.2再有一个很重要的方面是改进了蓝牙连接的安全性。
物联网构成无线连接一定是组网灵活,低功耗,带宽适用,安全的,蓝牙在向着这样的方向发展,与WiFi和zigbee相比,无疑是最有竞争力成为物联网协议的无线连接规范。

iOS CoreBluetooth框架使用
    1、首先是导入框架#import<CoreBluetooth/CoreBluetooth.h>,
              然后创建中心设备并设置代理(不要忘记签订协议):
       CBCentralManager *manager = [[CBCentralManageralloc]init];
       self.manager = manager;
      一旦设置代理在运行程序的时候,就会调用协议里一个必须要完成的方法:
       - (void)centralManagerDidUpdateState:(CBCentralManager *)central;
      这个方法是查看中心设备是否打开蓝牙。
    2、利用中心设备扫描外部设备:
        [manager scanForPeripheralsWithServices:niloptions:nil];
      第一个参数那里表示扫描带有相关服务的外部设备,例如填写@[[CBUUIDUUIDWithString:@"需要连接的外部设备的服务的UUID"]],即表示带有需要连接的外部设备的服务的UUID的外部设备,nil表示扫描全部设备;
      options处以后细讲,暂时可以写一个@{CBCentralManagerScanOptionAllowDuplicatesKey :@YES}这样的参数,YES表示会让中心设备不断地监听外部设备的消息,NO就是不能。
      一旦扫描到外部设备,就会进入协议中的
       - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI;
      在这个方法里,我们可以根据我们获取到的硬件的某些条件进行筛选,然后连接我们需要连接的外部设备,例如连接名字带有A的外部设备:
       if ([peripheral.namehasPrefix:@"A"] ) {
           //连接设备
           [manager connectPeripheral:peripheraloptions:nil];
       }
    3、刚刚的if判断中的语句就是在进行中心设备和外部设备的连接。连接成功或者失败会分别进入
        - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;(连接成功)
        - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(nullableNSError *)error;(连接失败)
    4、我们在连接成功的方法中开始扫描外部设备的服务:
        [peripheral discoverServices:nil];
       接着就会跳入发现服务的代理方法中去:
        - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error;
       我们在这个方法里面开始扫描服务中的特征:
        [peripheral discoverCharacteristics:nilforService:service];
       当我们扫描到特征的时候,就会跳入发现特征的协议方法里去:
         - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error;
    5、扫描到特征之后,我们就可以拿到相应的特征进行读写操作。
       例如进行读取数据的操作:
        if ([characteristics.UUID.UUIDStringisEqualToString:@"你需要的特征的UUID"]){
             //读取特征数据
             [peripheral readValueForCharacteristic:characteristics];
        }
       这就读取了特征包含的相关信息,只要读取就会进入另外一个方法:
        - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;
       在这个方法里,我们就可以拿到我们需要的数据了。
       进行写的操作是
        [peripheralwriteValue:data类型的数据 forCharacteristic:使用到的特征 type:CBCharacteristicWriteWithResponse];
       最后的type类型有两个,分别是CBCharacteristicWriteWithResponse和                                                  CBCharacteristicWriteWithoutResponse;
       选择第一个,每往硬件写入一次数据都会进入
        - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;
       这个方法会告诉我们这次的写入是否成功,但是如果我们不用考虑往硬件写入的数据成功与否的话,选择第二个类型就ok。


BLE速度提升

蓝牙4.1和4.2主要是对MTU的容量进行了提示,4.2 MTU范围[23-512],
注意:core spec里面定义了ATT的默认MTU为23个bytes, 除去ATT的opcode一个字节以及ATT的handle 2个字节之后,剩下的20个字节便是留给GATT的了。
对于不同的平台,设置MTU的方式也不一样,下面举例说明cypress的BLE4.2的设置:
在BLE的设置选项GAP settings里将MTU改成512
以及在L2CAP settings中,把L2CAP MTU也改成512,而实际的发送大小为512-3=509个字节。
并对MTU的req进行监控,将MTU消息发送给手机,如下
case CYBLE_EVT_GATTS_XCNHG_MTU_REQ:
            {
                uint16 cyBle_mtuSize;
                if(CYBLE_GATT_MTU > ((CYBLE_GATT_XCHG_MTU_PARAM_T *)eventParam)->mtu)
                {
                    cyBle_mtuSize = ((CYBLE_GATT_XCHG_MTU_PARAM_T *)eventParam)->mtu;
                }
                else
                {
                    cyBle_mtuSize = CYBLE_GATT_MTU;
                }
                (void)CyBle_GattsExchangeMtuRsp(((CYBLE_GATT_XCHG_MTU_PARAM_T *)eventParam)->connHandle, cyBle_mtuSize);
            }
            break;
对于不同的手机,测试如下:连接间隔20-30ms,由于是with response,所以一般一包数据需要两个连接间隔。
注:这个是MTU对应的不同速率,设备向手机发送数据,一包数据按MTU大小,with response,没有上层交互,纯数据循环发送的结果
对于不同的手机,MTU的大小是不一样的,目前从测试的结果看,只有iPhone7的MTU可以达到512字节,iPhone6s及以下的手机,MTU只能到185个字节,虽然apple官网都标称蓝牙4.2,但是从实测的结果看,只有iPhone7的MTU达到了最大的512字节。


网易云大礼包:https://www.163yun.com/gift

本文来自网易实践者社区,经作者刘国建授权发布