https://www.jianshu.com/p/e7df216f9e5e
被连接的设备叫外设Peripheral;发起连接的叫cental;
BLE蓝牙的角色有以下几种:广播者(Advertise)、扫描者(Scanner)、从设备(Slave)、主设备(Master)、发起者(Initiator),其中主设备是由发起者、扫描者转化而来,从设备则是由广播者转化而来;蓝牙模块通信是指两个蓝牙模块或蓝牙设备之间进行通信,进行数据通信的双方一个是主机,一个是从机。
主设备模式:工作在主设备模式,可以与一个从设备进行连接。在此模式下可以对周围设备进行搜索并选择需要连接的从设备进行连接。理论上,一个蓝牙主端设备,可同时与7个蓝牙从端设备进行通讯。一个具备蓝牙通讯功能的设备, 可以在两个角色间切换,平时工作在从模式,等待其它主设备来连接,需要时,转换为主模式,向其它设备发起呼叫。一个蓝牙设备以主模式发起呼叫时,需要知道对方的蓝牙地址,配对密码等信息,配对完成后,可直接发起呼叫。
从设备模式:工作在从机模式下的蓝牙模块只能被主机搜索,不能主动搜索。从设备跟主机连接以后,也可以和主机设备进行发送和接收数据。
主模式与从模式的区别:主机是指能够搜索别人并主动建立连接的一方,从机则不能主动建立连接,只能等别人连接自己。
目前市场上影响力最大的三种无线技术,蓝牙,WIFI和Zigbee。从上图可以看出,蓝牙的传输距离是最短的,功耗是高于Zigbee,低于WIFI。传输距离最短,只有2-10米,当然这是传统蓝牙,传输速度能达到3Mbps。全新的蓝牙4.0技术并不是一种技术,而是由传统蓝牙,高速蓝牙和低功耗蓝牙合而为一。并且这三种蓝牙可以组合使用,也可以单独使用。其中,低功耗蓝牙即BLE是蓝牙4.0的核心规范。
服务和特征都有UUID属性;
#import "ViewController.h"
#import <CoreBluetooth/CoreBluetooth.h>
@interface ViewController ()<CBCentralManagerDelegate,CBPeripheralDelegate>
/** 中央管理者*/
@property (nonatomic,strong) CBCentralManager *manager;
/** 发现的外围设备数据*/
@property (nonatomic,strong) NSMutableArray *peripheralData;
@end
@implementation ViewController
- (void)viewDidLoad {
[superviewDidLoad];
/**
1. 创建中央管理者
2. 扫描外围设备
3. 连接外围设备
4. 扫描服务和特性
5. 利用特性做数据的读写操作
6. 断开连接
*/
//0. 初始化数组
self.peripheralData = [NSMutableArrayarray];
//1. 创建中央管理者
//Delegate: 代理
//queue : 队列如果传nil,就是主队列
self.manager = [[CBCentralManageralloc] initWithDelegate:selfqueue:nil];
//2. 扫描外围设备
//scan: 扫描
//Peripheral: 外设
//Services: 服务的UUID如果传nil,代表扫描所有的服务
[self.managerscanForPeripheralsWithServices:niloptions:nil];
}
/**
3. 当发现外围设备的时候会调用方法
peripheral: 外设
advertisementData: 数据
RSSI : 信号强度
*/
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI
{
//当扫描到的时候,我们需要数组保存,然后创建tableView给用户显示,让用户来选择连接哪一个设备
// 又可能扫描到重复的设备,需要去重
if (![self.peripheralDatacontainsObject:peripheral]) {
[self.peripheralDataaddObject:peripheral];
}
}
/**
4. 将来需要选中tableViewCell的某一行,来连接外设
用下面的方法connectPeripheral模拟tableViewCell选中的方法
*/
- (void)connectPeripheral:(CBPeripheral *)peripheral
{
// 连接外围设备
[self.managerconnectPeripheral:peripheraloptions:nil];
}
/**
5. 当连接到外围设备时调用的代理方法
*/
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
//5.1 设置外设的代理
peripheral.delegate =self;
//5.2 用外设来扫描服务(传如UUID数组NSArray<CBUUID *> *)serviceUUIDs)如果不传,代表扫描所有服务
[peripheral discoverServices:nil];
}
/**
6. 当扫描到服务的时候,此代理方法会调用
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
//找到指定服务UUID,然后去扫描此服务的特性
//services: 当扫描到服务时,所有的服务会存在在外设的services属性中
for (CBService *servicein peripheral.services) {
//将来服务和特征的UUID,都在蓝牙厂商提供的文档中
// 假设服务的UUID为 123456
if ([service.UUID.UUIDStringisEqualToString:@"123456"]) {
//扫描此服务的特性
//Characteristics: 特征
//如果特征传nil,代表扫描所有特征
[peripheral discoverCharacteristics:nilforService:service];
}
}
}
/**
7. 扫描到某个服务的某个特征时,会调用的代理方法
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
//找到指定特征的UUID,然后就可以做数据交互了
//characteristics: 当扫描到特征时,所有的特征会存在在服务的characteristics属性中
for (CBCharacteristic *characteristicin service.characteristics) {
// 假设特征的UUID为 654321
if ([characteristic.UUID.UUIDStringisEqualToString:@"654321"]) {
NSData *data=[NSDatadataWithContentsOfFile:@""];
// 在这里进行写操作,写数据到特征中
[peripheral writeValue:dataforCharacteristic:characteristictype:CBCharacteristicWriteWithResponse];
//从特征中读取数据
[peripheral readValueForCharacteristic:characteristic];
//处理蓝牙发过来的数据
//不过更好的办法是设置事件通知实时获取读取到的数据。设置了这个方法,会调用代理方法- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{}
[peripheral setNotifyValue:YESforCharacteristic:characteristic];
}
}
}
///获取外设发来的数据,不论是read和notify,获取数据都是从这个方法中读取。
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
}
//向特征中写入数据后调用
-(void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
}
//管理中心读取外设发来的实时数据(在前面设置了setNotifyValue:forCharacteristic:这个方法发送通知。会调用下面这个方法)
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
}
/**
8. 断开连接
*/
- (void)viewWillDisappear:(BOOL)animated
{
[superviewWillDisappear:animated];
// 停止扫描
[self.managerstopScan];
}
#pragma mark 必须实现的代理方法
//中央管理器的状态改变时调用(也就是蓝牙开或者关的状态发生改变);
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
NSLog(@"state: %zd", central.state);
switch (central.state) {
caseCBCentralManagerStatePoweredOn:
{
//蓝牙开启状态
//扫描外设
[_managerscanForPeripheralsWithServices:@[[CBUUIDUUIDWithString:@"FF15"]] options:@{CBCentralManagerScanOptionAllowDuplicatesKey :@YES }];//@[[CBUUID UUIDWithString:@"FF15"]]是为了过滤掉其他设备,可以搜索特定标示的设备
}
break;
caseCBCentralManagerStatePoweredOff:
//蓝牙关闭状态
break;
default:
break;
}
}
//蓝牙链接失败时调用
-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
}
//蓝牙断开链接时调用
-(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
}
//在和硬件之间的数据发送和接受,用的都是byte数组。
Byte byte[] = {7};
[_peripheral writeValue:[NSData dataWithBytes:byte length:1] forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithoutResponse];//向特征中写入数据
NSData dataWithBytes:byte length:1] forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithoutResponse];//向特征中写入数据
NSData * data = characteristic.value;
Byte * resultByte = (Byte *)[data bytes];
end