简易防丢器
更新时间:2017-08-08 阅读:2886
目录
项目概述
项目角色定位
在蓝牙协议中,有着两种角色,一种是中心设备(central),一种是外部设备(peripheral). 在本项目中,手机APP扮演的中心设备,防丢器(单片机)扮演的是外部设备.所以我们需要用到的是下图左边的API.
项目原理
蓝牙防丢器:指的是通过蓝牙将防丢器和手机APP建立连接,当手机和防丢器之间的距离超出某个指定的值时,就会对用户进行提醒.
进行距离计算: 要知道蓝牙通信节点(如手机和蓝牙设备)之间的距离,最容易实现的方法是通过读取接收RSSI(Received Signal Strength Indication)值来计算.无线通讯中功率与距离的关系如下:其中A可以看作是信号传输1米远时接收信号的功率,n是传播因子(它受障碍,温度和湿度等影响),r是节点之间的距离.当确定了常数A与n的值后,距离r就可以根据PR(dBm)计算出来.
实现过程
定义服务与特征
定义好蓝牙通信所需的服务和特征对应的UUID,如:
#define BATTERY_SERVICE_UUID @"180F" #define IMALERT_SERVICE_UUID @"1802" #define INTERACTION_SERVICE_UUID @"CC07" #define BATTERY_CHARACTERISTIC_UUID @"2A19" #define ALERT_CHARACTERISTIC_UUID @"2A06" #define RECEIVE_CHARACTERISTIC_UUID @"CD01" #define SENDCMD_CHARACTERISTIC_UUID @"CD20" #define VERSION_CHARACTERISTIC_UUID @"CD30"
通过蓝牙扫描开启指定服务的设备
CBCentralManager *centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; [centralManager scanForPeripheralsWithServices:[CBUUID UUIDWithString:BATTERY_SERVICE_UUID],[CBUUID UUIDWithString:IMALERT_SERVICE_UUID],[CBUUID UUIDWithString:INTERACTION_SERVICE_UUID]] options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES };
实现两个重要delegate
CBCentralManagerDelegate
在.h文件中:
@interface TCBleCentralManager : NSObject <CBCentralManagerDelegate> @property (strong,nonatomic)TCBlePeripheral *blePeripheral; //这个类会实现第二个代理CBPeripheralDelegate
在.m文件中,实现几个代理方法:
(void)centralManagerDidUpdateState:(CBCentralManager *)central { //在这个方法中会获得到中心设备的蓝牙状态central.state. } //这个方法是扫描设备的回调函数 (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI { //所需的设备 blePeripheral.discoveredPeripheral = peripheral; //对符合要求的设备发出连接请求 [self.centralManager connectPeripheral:peripheral options:nil]; } //设备连接成功会回调这个方法 (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { //实现外设的代理 peripheral.delegate = blePeripheral.self; //获取对应的服务 [peripheral discoverServices:@[[CBUUID UUIDWithString:BATTERY_SERVICE_UUID],[CBUUID UUIDWithString:IMALERT_SERVICE_UUID],[CBUUID UUIDWithString:INTERACTION_SERVICE_UUID]]]; } (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { /**这个方法调用有两种原因: 一是调用方法(void)connectPeripheral:(CBPeripheral *)peripheral options:(NSDictionary *)options失败, 二是调用方法(void)cancelPeripheralConnection:(CBPeripheral *)peripheral. 区别在与如果是第一种方法error不为nil,第二种为nil */ //清除设备信息 [self cleanup: blePeripheral.discoveredPeripheral]; blePeripheral.discoveredPeripheral = nil; } (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { //这个方法是因为调用了(void)connectPeripheral:(CBPeripheral *)peripheral options:(NSDictionary *)options超时 //清除设备信息 [self cleanup: blePeripheral.discoveredPeripheral]; blePeripheral.discoveredPeripheral = nil; } //断开设备并且清除信息 (void)cleanup:(CBPeripheral*)peripheral { // Don't do anything if we're not connected if (!peripheral.isConnected) { return; } // See if we are subscribed to a characteristic on the peripheral if (peripheral.services != nil) { for (CBService *service in peripheral.services) { if (service.characteristics != nil) { for (CBCharacteristic *characteristic in service.characteristics) { if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:BATTERY_CHARACTERISTIC_UUID]]) { if (characteristic.isNotifying) { // It is notifying, so unsubscribe [peripheral setNotifyValue:NO forCharacteristic:characteristic]; // And we're done. return; } } } } } } // If we've got this far, we're connected, but we're not subscribed, so we just disconnect [self.centralManager cancelPeripheralConnection:peripheral]; }
CBPeripheralDelegate
在.h文件中:
@interface TCBlePeripheral : NSObject <CBPeripheralDelegate> @property (strong,nonatomic) CBPeripheral * discoveredPeripheral;
在.m文件中,实现几个代理方法:
//发现设备服务 (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error { //扫描所需服务中所要的特征 for (CBService *service in peripheral.services) { if ([service.UUID isEqual:[CBUUID UUIDWithString:BATTERY_SERVICE_UUID]]) { [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:BATTERY_CHARACTERISTIC_UUID]] forService:service]; } } } //发现服务中的特征(用于通信) (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error { //找到这些特征,并且管理起来,用于后面的通信 for (CBCharacteristic *characteristic in service.characteristics) { if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:BATTERY_CHARACTERISTIC_UUID]]) { [peripheral setNotifyValue:YES forCharacteristic:characteristic];//设置为订阅的模式 batteryCh = characteristic; } } } //更新特征的状态 (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { } //更新特征获取到的信息值,如电量. (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { NSString *stringFromData = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding]; if ([characteristic.UUID.UUIDString compare:batteryCh.UUID.UUIDString] == 0) { char * value = (char*)[characteristic.value bytes]; NSLog(@"电量: %@,,%@,%c", stringFromData,characteristic.value,value[0]); return; } } //通过特征主动读取设备信息 [discoveredPeripheral readValueForCharacteristic:characteristic]; //通过特征写入设备信息 static int data = 0x04; [discoveredPeripheral writeValue:[[NSData alloc] initWithBytes:&data length:1] forCharacteristic:characteristic type:1];
获取RSSI值
[discoveredPeripheral readRSSI];
对discoveredPeripheral.RSSI.intValue直接使用; readRSSI会回调方法(void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error(IOS5.0后使用,IOS8.0弃用)