一、外设

1.在外设的.h文件中定义如下

 
 1 //周边管理者
2
3 @property (nonatomic , strong) CBPeripheralManager *peripheralManager;
4
5 // 中心
6
7 @property (nonatomic,strong) CBCentral *central;
8
9 // 特征
10
11 @property (nonatomic , strong) CBMutableCharacteristic *customCharacteristic;
12
13 // 服务
14
15 @property (nonatomic , strong) CBMutableService *customService;
16
17 // 向中心发送的数据
18
19 @property (strong, nonatomic) NSData *dataToSend;
20
21 @property (nonatomic, readwrite) NSInteger sendDataIndex;
 

2.然后在.m文件中进行如下操作

2.1在viewDidLoad方法中初始化外设和要发送的数据

1 // 初始化外设
2 self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
3 // 初始化数据
4 self.dataToSend = [@"snadjfkhaw加大困难的是咖啡euijferlfmn ksxncjxznvjeajfrnjadnfjasfndsafnjsadkfnjsa" dataUsingEncoding:NSUTF8StringEncoding];

2.2 Peripheral Manager被创建,状态改变时调用

CBPeripheralManagerStatePoweredOff 设备关闭状态

CBPeripheralManagerStateUnauthorized 未授权

CBPeripheralManagerStateUnsupported 您的设备不支持蓝牙4.0

CBPeripheralManagerStateResetting 重置状态

CBPeripheralManagerStateUnknown 未知状态

 
 1 - (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
2
3 {
4
5 switch (peripheral.state) {
6
7 case CBPeripheralManagerStatePoweredOn:
8
9 NSLog(@"蓝牙设备已经打开,可以扫描外设");
10
11 [self setupService];
12
13 break;
14
15 default:
16
17 NSLog(@"外设改变状态");
18
19 break;
20
21 }
22
23 }
24
25 - (void)setupService
26
27 {
28
29 //creates the characteristic UUID
30
31 CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID];
32
33 //create the characteristic
34
35 self.customCharacteristic = [[CBMutableCharacteristic alloc] initWithType:characteristicUUID
36
37 properties:CBCharacteristicPropertyNotify
38
39 value:nil
40
41 permissions:CBAttributePermissionsReadable];
42
43 //create the service UUID
44
45 CBUUID *servieceUUID = [CBUUID UUIDWithString:kServiceUUID];
46
47 //creates the service and adds the charecteristic to it
48
49 self.customService = [[CBMutableService alloc] initWithType:servieceUUID primary:YES];
50
51 //sets the characteristics for this service
52
53 [self.customService setCharacteristics:@[self.customCharacteristic]];
54
55 // And add it to the peripheral manager
56
57 [self.peripheralManager addService:self.customService];
58
59 }
 

2.3 当你执行addService方法后执行如下回调

 
 1 - (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error {
2 if (error != nil) {
3 NSLog(@"%s,error = %@",__PRETTY_FUNCTION__, error.localizedDescription);
4 } else {
5 //starts advertising the service
6 [self.peripheralManager startAdvertising:@{CBAdvertisementDataLocalNameKey:@"服务门店",
7 CBAdvertisementDataServiceUUIDsKey:@[[CBUUID UUIDWithString:kServiceUUID]]}];
8
9 }
10 }
 

2.4 central订阅了characteristic的值,当更新值的时候peripheral会调用

 
 1 - (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic
2 {
3 self.central = central;
4 if (_lastDeviceUUID == central.identifier) {
5 return;
6 }
7 _lastDeviceUUID = central.identifier;
8 self.sendDataIndex = 0;
9 [self sendData];
10 }
11
12
13 #pragma mark - 向客户端发消息
14 - (void)sendData {
15
16 // 标记是否为最后一次发送
17 static BOOL sendingEOM = NO;
18 // 1. 如果是最后一次发送
19 if (sendingEOM) {
20 // 只发送 "EOM" 表示结束
21 BOOL didSend = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.customCharacteristic onSubscribedCentrals:@[self.central]];
22
23 // 1.1. 最后一次发送成功
24 if (didSend) {
25 sendingEOM = NO;
26 NSLog(@"Sent: EOM");
27 }
28 return;
29 }
30 // 2. 不是最后一次发送,且数据为空,则返回
31 if (self.sendDataIndex >= self.dataToSend.length) {
32 return;
33 }
34 // 3. 数据尚未发送完成,继续发送直到完成
35 BOOL didSend = YES;
36 while (didSend) {
37 // 3.1. 计算剩余多大数据量需要发送
38 NSInteger amountToSend = self.dataToSend.length - self.sendDataIndex;
39 // 不能大于20个字节
40 if (amountToSend > NOTIFY_MTU)
41 amountToSend = NOTIFY_MTU;
42 // 3.2. copy出我们想要发送的数据
43 NSData *chunk = [NSData dataWithBytes:self.dataToSend.bytes+self.sendDataIndex length:amountToSend];
44 // 3.3. 发送
45 didSend = [self.peripheralManager updateValue:chunk forCharacteristic:self.customCharacteristic onSubscribedCentrals:@[self.central]];
46 // 3.4. 如果没有发送成功,重新发送
47 // If it didn't work, drop out and wait for the callback
48 if (!didSend) {
49 NSLog(@"SEND ERROR");
50 return;
51 }
52 NSString *stringFromData = [[NSString alloc] initWithData:chunk encoding:NSUTF8StringEncoding];
53 NSLog(@"Sent: %@", stringFromData);
54 // 3.5. 发送成功,修改已经发送成功数据index值
55 self.sendDataIndex += amountToSend;
56 // 3.6. 如果是最后一次需要发送
57 if (self.sendDataIndex >= self.dataToSend.length) {
58 // 3.6.1. 把 标识是否为最后一次发送 改为YES
59 sendingEOM = YES;
60 // 3.6.2. 发送
61 BOOL eomSent = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.customCharacteristic onSubscribedCentrals:@[self.central]];
62 if (eomSent) {
63 // 3.6.3. 发送成功,则我们已经完成这个功能
64 sendingEOM = NO;
65 NSLog(@"Sent: EOM");
66 }
67 return;
68 }
69 }
70 }
 

2.5 peripheral再次准备好发送Characteristic值的更新时候调用

1 - (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral
2 {
3 [self sendData];
4 }

2.6 当central取消订阅characteristic这个特征的值后调用方法

1 - (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic
2 {
3 NSLog(@"central=%@设备拒绝请求,%s,",central,__PRETTY_FUNCTION__);
4 }

二、中心

1.在中心的.h文件中定义如下

 
1 /**
2 * 中心角色
3 */
4 @property (nonatomic , strong) CBCentralManager *centralManager;
5 @property (nonatomic , strong) CBPeripheral *peripheral;
6 @property (nonatomic, strong) CBCharacteristic *character;
7 @property (nonatomic , strong) NSMutableData *data;
 

2.然后在.m文件中进行如下操作

2.1在viewDidLoad方法中初始化中心和要发送的数据

1     //    1.建立中心角色,queue为执行队列,默认为主线程
2 self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
3 // 2.初始化显示控件
4 [self setupUI];
5 // 3.初始化data
6 _data = [[NSMutableData alloc] init];

2.2 CBCentralManagerDelegate代理方法

回调,返回当前设备蓝牙状态

 
 1 #pragma mark - CBCentralManagerDelegate
2 #pragma mark 回调,返回当前设备蓝牙状态
3 - (void)centralManagerDidUpdateState:(CBCentralManager *)central {
4
5 switch (central.state) {
6 case CBCentralManagerStatePoweredOn:{
7 // 扫描外设(discover)
8 _messageLabel.text = @"蓝牙设备已经打开,可以扫描外设";
9 [self scan];
10 }
11 break;
12 default:
13 break;
14 }
15 }
16
17 #pragma mark - 扫描外设(discover) 超时停止扫描
18 - (void)scan{
19 /**
20 * 第一个参数指定了要搜寻的服务,如果传nil,表示搜寻搜所有的服务
21 * 第二个参数指定了CBCentralManagerScanOptionAllowDuplicatesKey为已发现的设备是否重复扫描,
22 * 如果是同一设备不会多次回调。
23 */
24 [self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:kServiceUUID]] options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}];
25
26 }
27
 

发现外设,回调

 
 1 - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
2
3 NSLog(@"找到了服务:%@,信号质量:%@",advertisementData,RSSI);
4 self.serviceName = [advertisementData objectForKey:@"kCBAdvDataLocalName"];
5
6 if (self.peripheral != peripheral) {
7 self.peripheral = peripheral;
8 NSLog(@"开始连接blueServer:%@",peripheral);
9 [self.centralManager connectPeripheral:self.peripheral options:nil];
10 }
11 }
 

连接失败,回调

1 - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
2 NSLog(@"Failed to connect to %@. (%@)", peripheral, [error localizedDescription]);
3 [self cleanup];
4 }

连接成功,回调

 
 1 - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
2 //因为一个peripheral可能不止提供一个service
3 NSLog(@"连接成功,进一步获取peripheral的service");
4 [self.centralManager stopScan];
5
6 // 每过 0.1 秒钟执行一次 readBLEServiceRSSI 方法
7 self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(readBLEServiceRSSI) userInfo:nil repeats:YES];
8
9 [self.data setLength:0];
10
11 // 设置代理
12 self.peripheral.delegate = self;
13
14 //查询符合条件的外设
15 [self.peripheral discoverServices:@[[CBUUID UUIDWithString:kServiceUUID]]];
16 }
17
18
 

失去连接,回调

1 - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
2 NSLog(@"Failed to connect to %@. (%@)", peripheral, [error localizedDescription]);
3 [self cleanup];
4 }

2.3 CBPeripheralDelegate代理方法

读取到RSSI值后的操作

 
1 - (void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error {
2 NSLog(@"%s,%@",__PRETTY_FUNCTION__,peripheral);
3 int rssi = abs([peripheral.RSSI intValue]);
4 CGFloat ci = (rssi - 49) / (10 * 4.);
5
6 self.messageLabel.text = [NSString stringWithFormat:@"发现BLT4.0热点:%@,距离:%.1fm",self.serviceName,pow(10,ci)];
7 }
 

找到我们刚刚指定的服务

 
 1 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
2 if (error) {
3 NSLog(@"%s,error=%@", __PRETTY_FUNCTION__, error.localizedDescription);
4 [self cleanup];
5 return;
6 } else {
7 for (CBService *service in peripheral.services) {
8 NSLog(@"发现UUID=%@的服务",service.UUID);
9 NSLog(@"开始检测这个服务的特征码...");
10 if ([service.UUID isEqual:[CBUUID UUIDWithString:kServiceUUID]]) {
11 [self.peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:kCharacteristicUUID]] forService:service];
12 }
13 }
14 }
15 }
 

如果一个特征被检测到,回调

 
 1 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
2 if (error) {
3 NSLog(@"%s,%@",__PRETTY_FUNCTION__,error);
4 [self cleanup];
5 return;
6 } else {
7 if ([service.UUID isEqual:[CBUUID UUIDWithString:kServiceUUID]]) {
8 for (CBCharacteristic *characteristic in service.characteristics) {
9 if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kCharacteristicUUID]]) {
10 [peripheral setNotifyValue:YES
11 forCharacteristic:characteristic];
12 self.character=characteristic;
13 }
14 }
15 }
16 }
17 }
 

处理蓝牙发过来的数据

 
 1 - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
2 if (error) {
3 NSLog(@"didUpdateValueForCharacteristic - Error discovering characteristics: %@", [error localizedDescription]);
4 return;
5 }
6 NSString *stringFromData = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
7 // 如果我们获得了所有的数据
8 if ([stringFromData isEqualToString:@"EOM"]) {
9 // 显示数据
10 [self alarm:self.data];
11 // 取消订阅
12 [peripheral setNotifyValue:NO forCharacteristic:characteristic];
13 // 让中心失去和设备的连接
14 [self.centralManager cancelPeripheralConnection:peripheral];
15 }
16 // 否则,拼接数据
17 [self.data appendData:characteristic.value];
18 // Log it
19 NSLog(@"Received: %@", stringFromData);
20 }
 

外围设备是否被注销

 
 1 - (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
2 if (error) {
3 NSLog(@"%s,%@",__PRETTY_FUNCTION__,error.localizedDescription);
4 }
5 if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:kCharacteristicUUID]]) {
6 return;
7 }
8 //已经发送通知
9 if (characteristic.isNotifying) {
10 NSLog(@"Notification began on %@",characteristic);
11 } else {
12 //Notification has stopped
13 //so disconnect from the peripheral
14 NSLog(@"Notification stopped on %@ Disconnecting",characteristic);
15 [self.centralManager cancelPeripheralConnection:self.peripheral];
16 }
17 }
 

2.4 出现错误或者结束连接时调用(私有方法)

 
 1 #pragma mark - Call this when things either go wrong, or you're done with the connection.
2 - (void)cleanup {
3 // Don't do anything if we're not connected
4 if (!self.peripheral.isConnected) {
5 return;
6 }
7 // See if we are subscribed to a characteristic on the peripheral
8 if (self.peripheral.services != nil) {
9 for (CBService *service in self.peripheral.services) {
10 if (service.characteristics != nil) {
11 for (CBCharacteristic *characteristic in service.characteristics) {
12 if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kCharacteristicUUID]]) {
13 if (characteristic.isNotifying) {
14 // It is notifying, so unsubscribe
15 [self.peripheral setNotifyValue:NO forCharacteristic:characteristic];
16 // And we're done.
17 return;
18 }
19 }
20 }
21 }
22 }
23 }
24 // If we've got this far, we're connected, but we're not subscribed, so we just disconnect
25 [self.centralManager cancelPeripheralConnection:self.peripheral];
26 }

ble编程-外设发送数据到中心的更多相关文章

  1. Java基础知识强化之网络编程笔记06:TCP之TCP协议发送数据 和 接收数据

    1. TCP协议发送数据 和 接收数据 TCP协议接收数据:• 创建接收端的Socket对象• 监听客户端连接.返回一个对应的Socket对象• 获取输入流,读取数据显示在控制台• 释放资源 TCP协 ...

  2. Java基础知识强化之网络编程笔记03:UDP之UDP协议发送数据 和 接收数据

    1. UDP协议发送数据 和 接收数据 UDP协议发送数据: • 创建发送端的Socket对象 • 创建数据,并把数据打包 • 调用Socket对象的发送方法,发送数据包 • 释放资源  UDP协议接 ...

  3. {网络编程}和{多线程}应用:基于UDP协议【实现多发送方发送数据到同一个接收者】--练习

    要求: 使用多线程实现多发送方发送数据到同一个接收者 代码: 发送端:可以在多台电脑上启动发送端,同时向接收端发送数据 注意:匹配地址和端口号 package com.qf.demo; import ...

  4. python网络编程-socket发送大数据包问题

    一:什么是socket大数据包发送问题 socket服务器端或者客户端在向对方发送的数据大于对方接受的缓存时,会出现第二次接受还接到上次命令发送的结果.这就出现象第一次接受结果不全,第二次接果出现第一 ...

  5. STM32 使用 printf 发送数据配置方法 -- 串口 UART, JTAG SWO, JLINK RTT

    STM32串口通信中使用printf发送数据配置方法(开发环境 Keil RVMDK) http://home.eeworld.com.cn/my/space-uid-338727-blogid-47 ...

  6. php以post方式向接口发送数据

    工作需要,我负责收集服务器数据,然后定时向中心服务器发送.我看到了接口信息,需要设置heads头信息,需要发送数据,且是post方式. 这里就用到了curl //发送post请求 function r ...

  7. C#带cookie Post和Get方式发送数据,保持cookie

    在实际编程中,可能需要读取特定网页的信息,但很多网站需要用户登录后,才能够获取相关的页面内容,这就需要编程者先临时存储当前的cookie,在C#中可以使用CookieContainer 对象来保存登录 ...

  8. HTTP 笔记与总结(3 )socket 编程:发送 GET 请求

    使用 PHP + socket 模拟发送 HTTP GET 请求,过程是: ① 打开连接 ② 构造 GET 请求的数据:写入请求行.请求头信息.请求主体信息(GET 请求没有主体信息) ③ 发送 GE ...

  9. Android(java)学习笔记80:UDP协议发送数据

    UDP协议发送数据:我们总是先运行接收端,再运行发送端发送端: 1 package cn.itcast_02; import java.io.IOException; import java.net. ...

随机推荐

  1. SeetaFaceEngine2 实例

    LOG: Creating layer(6):LOG: Creating layer(0):LOG: Creating layer(9):LOG: Creating layer(0):LOG: Cre ...

  2. Web.Config中配置字符串含引号的处理

    配置文件中往往要用到一些特殊的字符, Web.Config默认编码格式为UTF-8,对于XML文件,要用到实体转义码来替换.对应关系如下: 字符 转义码 & 符号 & & 单引 ...

  3. 浏览器显示 req Provisional headers are shown

    现象: 原因: 请求被插件什么的拦截导致. 修复: 换浏览器也可以. ​

  4. 123457123456#0#-----com.ppGame.huaHua65--前拼后广--儿童填色-pp

    com.ppGame.huaHua65--前拼后广--儿童填色-pp

  5. PHP5.2\5.3 Xdebug 调试器配置及应用

    PHP5.2添加的扩展方式:zend_extension_ts=D:\www\Server\php5\ext\php_xdebug-2.1.0-5.2-vc6.dll PHP5.3添加的扩展方式:ze ...

  6. iOS-UIPasteboard的使用

    剪贴板的使用以及自定义剪贴板. 系统剪贴板的直接调用 其实整个过程非常的简单,我就用我写的一个自定义UILable来说明调用系统剪贴板. 首先,因为苹果只放出来了 UITextView,UITextF ...

  7. Qt563x86vs2015.编译错误(TypeError: Property 'asciify' of object Core::Internal::UtilsJsExtension(0x????????) is not a function)

    1.在 编译或打开 pro时 有时会有这个错误 1.1.参考网址:Qt 编译错误 提示TypeError_ Property 'asciify' of object Core__Internal__U ...

  8. windows强大的快捷键

    1 电脑锁屏 有些时候,需要暂时离开座位去处理其他事,可是电脑还有数据再跑. 关掉的话,数据就白跑了,不关的话,又不想让别人看到我电脑的资料. 那么就按住windows键后,再按L键. 这样电脑就直接 ...

  9. Java program to find the largest element in array

    Java program to find the largest element in array Given an array of numbers, write a java program to ...

  10. [.Net] 一句话Linq(递归查询)

    功能查询起止日期范围内连续的月份列表. /* Period */ cbxPeriod.DataSource = Enumerable.Range(, ).Select(t => DateTime ...