zoukankan      html  css  js  c++  java
  • iOS BLE(蓝牙4.0) 读取埃微i5智能手环步数的简单实现

    • 开发前:

      • 1、profile
        profile可以理解为一种规范,一个标准的通信协议,它存在于从机中。蓝牙组织规定了一些标准的profile,例如 HID OVER GATT ,防丢器 ,心率计等。每个profile中会包含多个service,每个service代表从机的一种能力。
      • 2、service
        service可以理解为一个服务,在ble从机中,通过有多个服务,例如电量信息服务、系统信息服务等,每个service中又包含多个characteristic特征值。每个具体的characteristic特征值才是ble通信的主题。比如当前的电量是80%,所以会通过电量的characteristic特征值存在从机的profile里,这样主机就可以通过这个characteristic来读取80%这个数据
      • 3、characteristic
        characteristic特征值,ble主从机的通信均是通过characteristic来实现,可以理解为一个标签,通过这个标签可以获取或者写入想要的内容。
      • 4、UUID
        UUID,统一识别码,我们刚才提到的service和characteristic,都需要一个唯一的uuid来标识

      • 整理一下,每个从机都会有一个叫做profile的东西存在,不管是上面的自定义的simpleprofile,还是标准的防丢器profile,他们都是由一些列service组成,然后每个service又包含了多个characteristic,主机和从机之间的通信,均是通过characteristic来实现。

    • 1 懒加载创建中心设备 (中心设备一般是手机本身))
    /**
     *  懒加载 初始化中心设备 CBCentralManager
     *
     *  @return 中心设备
     */
    - (CBCentralManager *)centralManager {
        if (!_centralManager) {
            _centralManager = [[CBCentralManager alloc]initWithDelegate:self queue:nil options:nil];
        }
        return _centralManager;
    }
    • 2 扫描外设并判断蓝牙开启状态及设备是否支持BLE(在需要扫描的地方调用该方法, 比如点击扫描按钮)
    - (void)scanPeripheral {
        // 2.扫描外设
        if(self.centralManager.state == CBCentralManagerStatePoweredOff) {           // 蓝牙关闭状态
    
            [[[UIAlertView alloc] initWithTitle:@"蓝牙是关闭状态"
                                        message:@"请打开蓝牙"
                                       delegate:self
                              cancelButtonTitle:@"dismiss"
                              otherButtonTitles: nil] show];
    
        } else if(self.centralManager.state == CBCentralManagerStateUnsupported) {   // 设备蓝牙不支持
    
            [[[UIAlertView alloc] initWithTitle:@"设备蓝牙不支持"
                                        message:@"必须 iPhone4S 以上的设备才支持蓝牙4.0"
                                       delegate:self
                              cancelButtonTitle:@"dismiss"
                              otherButtonTitles: nil] show];
    
        } else if(self.centralManager.state == CBCentralManagerStatePoweredOn) {    // 蓝牙打开状态
            if (self.peripherals.count) {
                // 连接外设
                [self.centralManager connectPeripheral:[self.peripherals firstObject] options:nil];
                return;
            }
            NSLog(@"蓝牙已经打开, 正在搜索中...");
            self.connectStateLabel.text = @"正在搜索外设中...";
            // 如果第一个参数为nil, 那么将会扫描所有可用的外围设备, 不过这样会很慢
            [self.centralManager scanForPeripheralsWithServices:nil
                                                        options:nil];
        }
    }
    • 3 必须实现CBCentralManager的一个代理方法, 在里边调用步骤2的方法
    /**
     *  如果蓝牙状态改变, 会在这个方法回调
     *
     *  @param central 中心设备(一般为你的iPhone)
     */
    - (void)centralManagerDidUpdateState:(CBCentralManager *)central {
    
        [self scanPeripheral];
    }
    • 4 实现CBCentralManager一个代理方法, 如果扫描到外设会在这个方法中获取外设的信息, 并且连接外设
    /**
     *  这个代理方法中可以获取外设的信息
     *  4. 可以这里连接外设
     *  @param central           中心设备
     *  @param peripheral        外设
     *  @param advertisementData
     *  @param RSSI
     */
    -(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
    
        NSLog(@"已经搜索到设备, 正在连接中...");
    
        self.connectStateLabel.text = @"正在连接设备...";
    
        // 这里可以停止扫描外围设备
        [self.centralManager stopScan];
    
        if (![self.peripherals containsObject:peripheral]) {
    
            NSLog(@"外设名称: %@", peripheral.name);
    
            // 显示设备名称
            [self setUpName:peripheral.name];
    
            peripheral.delegate = self;
    
            // 应该保留外设, 否则会被释放
            [self.peripherals addObject:peripheral];
    
        }
    
        // 连接外设
        [self.centralManager connectPeripheral:peripheral options:nil];
    
    }
    • 5 实现CBCentralManager的一个代理方法, 如果连接外设成功会回调这个方法, 在这个方法中扫描外设中的服务
    /**
     *  如果连接成功的话会回调这个方法
     *  5. 扫描外设中的服务
     *  @param central 中心设备
     *  @param peripheral 外设
     */
    - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
    
        self.connectStateLabel.text = @"连接成功, 同步数据中...";
    
        // 查找服务
        [peripheral discoverServices:nil];
    
    }
    • 6 实现CBCentralManager的一个代理方法, 如果连接失败会回调这个方法
    /**
     *  连接失败
     *
     */
    - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    
        self.connectStateLabel.text = @"连接失败...";
    
        self.deviceNameKeyLabel.hidden = YES;
        self.deviceNameValueLabel.hidden = YES;
    
        [self scanPeripheral];
    }
    • 7 实现CBPeripheral的一个代理方法, 从外设的services属性中获取服务列表, 从而获取到想要的服务, 并从中调用查找特征的方法
    /**
     *  7. 从外设的services属性中获取服务列表
     *
     *  @param peripheral 外设
     *  @param error      错误信息
     */
    - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
    
        NSLog(@"已经获取到服务列表, 正在匹配服务中...");
    
        if (error) {
            NSLog(@"Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]);
    
    //        if ([self.delegate respondsToSelector:@selector(DidNotifyFailConnectService:withPeripheral:error:)])
    //            [self.delegate DidNotifyFailConnectService:nil withPeripheral:nil error:nil];
            return;
        }
    
        // 遍历服务
        for (CBService *service in peripheral.services) {
            NSLog(@"%@", service.UUID);
    
    //        [peripheral discoverCharacteristics:nil forService:service];
            // 找到对应的服务
            if ([service.UUID isEqual:[CBUUID UUIDWithString:@"FF20"]]) {
    //            NSLog(@"Service found with UUID: %@", service.UUID);
                // 查找特征
                [peripheral discoverCharacteristics:nil forService:service];
                break;
            }
    
        }
    
    }
    • 8 实现CBPeripheral的一个代理方法, 如果找到服务中的特征则会回调这个方法
    /**
     *  返回已经发现的特性的代理方法
     *  8. 发现服务中的特征
     *  @param peripheral 外设
     *  @param service    服务
     *  @param error      错误信息
     */
    - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
    
        if (error) {
            NSLog(@"Discovered characteristics for %@ with error: %@", service.UUID, [error localizedDescription]);
            return;
        }
    
    //    NSLog(@"
    服务: %@", service.UUID);
        // 从服务中遍历特征
        for (CBCharacteristic *characteristic in service.characteristics) {
    //        [peripheral setNotifyValue:YES forCharacteristic:characteristic];
            if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"FF22"]]) {
                // 这里要注意有些特征可读, 有些特征可写, 有些可以发通知, 而不是随便调用读写或者发通知的方法的
                // [peripheral readValueForCharacteristic:characteristic];
                // [peripheral discoverDescriptorsForCharacteristic:characteristic];
                // 发送通知
                [peripheral setNotifyValue:YES forCharacteristic:characteristic];
            }
    
        }
    }
    • 9 与外设进行数据交互(对于埃微智能手环, 这个特征中返回的字节数肯可能小于20, 那些情况没有分析, 所以暂且过滤掉, 如果返回20个字节的话, 那么第8, 9位存储步数; 注意, 这里仅仅针对埃微智能手环进行的数据分析)
    /**
     *  9.与外设进行数据交互
     *
     *  @param peripheral     外设
     *  @param characteristic 特征
     *  @param error          错误信息
     */
    - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    
        if (error) {
            NSLog(@"Error updating value for characteristic %@ error: %@", characteristic.UUID, [error localizedDescription]);
            return;
        }
    
        NSData *data = characteristic.value;
        char scartchVal[data.length];
        int16_t dataTemp;
        [data getBytes:&scartchVal length:data.length];
    
        long len = sizeof(scartchVal) / sizeof(scartchVal[0]);
    
        // 可能返回的字节数小于20, 那些情况没有分析, 所以暂且过滤掉
        if ((sizeof(scartchVal) / sizeof(scartchVal[0])) == 20) {
            // 对于埃微智能手环, 如果返回20个字节的话, 那么第8, 9位存储步数
            dataTemp = ((scartchVal[8] & 0xff) + ((scartchVal[9] << 8) & 0xff00));
            self.connectStateLabel.text = @"数据同步成功";
            self.stepLabel.text = [NSString stringWithFormat:@"%d", dataTemp];
        }
  • 相关阅读:
    HTML 与 HTML 页面之间动态传值的问题
    maven 导入本地项目(JQuery中的绝杀 $("表单").serialize() 可以自动提交表格数据)+邮件发送+通用的Servlet写法
    linux服务器nginx的卸载
    http协议
    所谓的批量删除
    查看本机ssh公钥,生成公钥
    centos7 redis5编译安装
    linux没有ll等命令的解决办法
    Linux 安装python3.7.0
    CentOS7 安装mysql
  • 原文地址:https://www.cnblogs.com/liaolijun/p/6689943.html
Copyright © 2011-2022 走看看