本文介紹了藍(lán)牙的概念以及具體的使用步驟.
一.藍(lán)牙概念
藍(lán)牙2.0為傳統(tǒng)藍(lán)牙,傳統(tǒng)藍(lán)牙也稱為經(jīng)典藍(lán)牙.
藍(lán)牙4.0因?yàn)榈秃碾?所以也叫做低功耗藍(lán)(BLE).它將三種規(guī)格集一體届谈,包括傳統(tǒng)藍(lán)牙技術(shù)、高速技術(shù)和低耗能技術(shù).
二.BLE支持兩種部署方式
- 雙模式
低功耗藍(lán)牙功能集成在現(xiàn)有的經(jīng)典藍(lán)牙控制器中弯汰,或在現(xiàn)有經(jīng)典藍(lán)牙技術(shù)芯片上增加低功耗堆棧
艰山,整體架構(gòu)基本不變,因此成本增加有限. - 單模式
面向高度集成咏闪、緊湊的設(shè)備曙搬,使用一個(gè)輕量級(jí)連接層(Link Layer)提供超低功耗的待機(jī)模式操作、簡(jiǎn)單設(shè)備恢復(fù)和可靠的點(diǎn)對(duì)多點(diǎn)數(shù)據(jù)傳輸鸽嫂,還能讓聯(lián)網(wǎng)傳感器在藍(lán)牙傳輸中安排好低功耗藍(lán)牙流量的次序纵装,同時(shí)還有高級(jí)節(jié)能和安全加密連接.
三.藍(lán)牙各版本使用選擇
- 藍(lán)牙2.0,不上架
使用私有API,手機(jī)需要越獄. - 藍(lán)牙2.0,要上架
進(jìn)行MFI認(rèn)證,使用ExternalAccessory框架.手機(jī)不需要越獄. - 藍(lán)牙4.0,要上架
使用CoreBluetooth框架,手機(jī)不需要越獄.(CoreBluetooth是基于BLE來開發(fā)的) - 說明
對(duì)于小的硬件廠商來說,MFI認(rèn)證通過幾率不大,不僅耗錢還耗時(shí),所以,還是推薦使用藍(lán)牙4.0.
(MFI:Make for ipad ,iphone, itouch 專們?yōu)樘O果設(shè)備制作的設(shè)備)
四.問題描述
公司要求iOS端需要和鋼琴進(jìn)行藍(lán)牙連接并進(jìn)行數(shù)據(jù)通信,我以為鋼琴是藍(lán)牙4.0,然后快速集成CoreBluetooth框架寫了一個(gè)demo,掃描外設(shè)時(shí),沒有發(fā)現(xiàn)鋼琴的藍(lán)牙名稱,可是用iphone打開系統(tǒng)設(shè)置,可以發(fā)現(xiàn)鋼琴對(duì)應(yīng)的藍(lán)牙.問了安卓的同事,得知鋼琴的藍(lán)牙只有2.0的模塊,所以,安卓端是用2.0藍(lán)牙進(jìn)行交互的.公司決定不做MFI認(rèn)證,改用藍(lán)牙4.0.在與硬件廠商交涉的過程中,得知鋼琴中的藍(lán)牙是4.0的,但是,他們?cè)谠O(shè)計(jì)藍(lán)牙板子的時(shí)候,沒有集成低功耗技術(shù).之后,板子寄回硬件廠商,添加BLE模塊.這才踏上藍(lán)牙4.0的正軌.
五.藍(lán)牙4.0使用解析
1.基本知識(shí)
central:中心,連接硬件的設(shè)備.
peripheral:外設(shè),被連接的硬件.
說明:外設(shè)在一直廣播,當(dāng)你創(chuàng)建的中心對(duì)象在掃描外設(shè)時(shí),就能夠發(fā)現(xiàn)外設(shè).
如圖所示:
[圖片上傳失敗...(image-53233a-1527600504149)]
service:服務(wù).
characteristic:特征.
說明:一個(gè)外設(shè)包含多個(gè)服務(wù),而每一個(gè)服務(wù)中又包含多個(gè)特征,特征包括特征的值和特征的描述.每個(gè)服務(wù)包含多個(gè)字段,字段的權(quán)限有read(讀)、write(寫)据某、notify(通知).
[圖片上傳失敗...(image-107c5e-1527600504149)]
2.藍(lán)牙4.0分為兩種模式
- 中心模式流程
- 建立中心角色
[[CBCentralManager alloc] initWithDelegate:self queue:nil]
- 掃描外設(shè)
cancelPeripheralConnection
- 發(fā)現(xiàn)外設(shè)
didDiscoverPeripheral
- 連接外設(shè)
connectPeripheral
4.1 連接失敗didFailToConnectPeripheral
4.2 連接斷開didDisconnectPeripheral
4.3 連接成功didConnectPeripheral
- 掃描外設(shè)中的服務(wù)
discoverServices
5.1 發(fā)現(xiàn)并獲取外設(shè)中的服務(wù)didDiscoverServices
- 掃描外設(shè)對(duì)應(yīng)服務(wù)的特征
discoverCharacteristics
6.1 發(fā)現(xiàn)并獲取外設(shè)對(duì)應(yīng)服務(wù)的特征didDiscoverCharacteristicsForService
6.2 給對(duì)應(yīng)特征寫數(shù)據(jù)writeValue:forCharacteristic:type:
- 訂閱特征的通知
setNotifyValue:forCharacteristic:
7.1 根據(jù)特征讀取數(shù)據(jù)didUpdateValueForCharacteristic
- 建立中心角色
- 外設(shè)模式流程
- 建立外設(shè)角色
- 設(shè)置本地外設(shè)的服務(wù)和特征
- 發(fā)布外設(shè)和特征
- 廣播服務(wù)
- 響應(yīng)中心的讀寫請(qǐng)求
- 發(fā)送更新的特征值搂擦,訂閱中心
六.藍(lán)牙4.0開發(fā)步驟
1.本文采用中心模式
導(dǎo)入CoreBluetooth框架,#import <CoreBluetooth/CoreBluetooth.h>
2.遵守CBCentralManagerDelegate,CBPeripheralDelegate
協(xié)議
3.添加屬性
// 中心管理者(管理設(shè)備的掃描和連接)
@property (nonatomic, strong) CBCentralManager *centralManager;
// 存儲(chǔ)的設(shè)備
@property (nonatomic, strong) NSMutableArray *peripherals;
// 掃描到的設(shè)備
@property (nonatomic, strong) CBPeripheral *cbPeripheral;
// 文本
@property (weak, nonatomic) IBOutlet UITextView *peripheralText;
// 外設(shè)狀態(tài)
@property (nonatomic, assign) CBManagerState peripheralState;
常量,具體服務(wù)和特征是讀還是寫的類型,問公司硬件廠商,或者問同事.
// 藍(lán)牙4.0設(shè)備名
static NSString * const kBlePeripheralName = @"公司硬件藍(lán)牙名稱";
// 通知服務(wù)
static NSString * const kNotifyServerUUID = @"FFE0";
// 寫服務(wù)
static NSString * const kWriteServerUUID = @"FFE1";
// 通知特征值
static NSString * const kNotifyCharacteristicUUID = @"FFE2";
// 寫特征值
static NSString * const kWriteCharacteristicUUID = @"FFE3";
4.創(chuàng)建中心管理者
- (CBCentralManager *)centralManager
{
if (!_centralManager)
{
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
return _centralManager;
}
創(chuàng)建存儲(chǔ)設(shè)備數(shù)組
- (NSMutableArray *)peripherals
{
if (!_peripherals) {
_peripherals = [NSMutableArray array];
}
return _peripherals;
}
5.掃描設(shè)備之前會(huì)調(diào)用中心管理者狀態(tài)改變的方法
// 當(dāng)狀態(tài)更新時(shí)調(diào)用(如果不實(shí)現(xiàn)會(huì)崩潰)
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
switch (central.state) {
case CBManagerStateUnknown:{
NSLog(@"未知狀態(tài)");
self.peripheralState = central.state;
}
break;
case CBManagerStateResetting:
{
NSLog(@"重置狀態(tài)");
self.peripheralState = central.state;
}
break;
case CBManagerStateUnsupported:
{
NSLog(@"不支持的狀態(tài)");
self.peripheralState = central.state;
}
break;
case CBManagerStateUnauthorized:
{
NSLog(@"未授權(quán)的狀態(tài)");
self.peripheralState = central.state;
}
break;
case CBManagerStatePoweredOff:
{
NSLog(@"關(guān)閉狀態(tài)");
self.peripheralState = central.state;
}
break;
case CBManagerStatePoweredOn:
{
NSLog(@"開啟狀態(tài)-可用狀態(tài)");
self.peripheralState = central.state;
}
break;
default:
break;
}
}
掃描設(shè)備
// 掃描設(shè)備
- (IBAction)scanForPeripherals
{
[self.centralManager stopScan];
NSLog(@"掃描設(shè)備");
[self showMessage:@"掃描設(shè)備"];
if (self.peripheralState == CBManagerStatePoweredOn)
{
// 掃描所有設(shè)備,傳入nil,代表所有設(shè)備.
[self.centralManager scanForPeripheralsWithServices:nil options:nil];
}
}
6.掃描到設(shè)備并開始連接
/**
掃描到設(shè)備
@param central 中心管理者
@param peripheral 掃描到的設(shè)備
@param advertisementData 廣告信息
@param RSSI 信號(hào)強(qiáng)度
*/
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral
advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI
{
[self showMessage:[NSString stringWithFormat:@"發(fā)現(xiàn)設(shè)備,設(shè)備名:%@",peripheral.name]];
if (![self.peripherals containsObject:peripheral])
{
[self.peripherals addObject:peripheral];
NSLog(@"%@",peripheral);
if ([peripheral.name isEqualToString:kBlePeripheralName])
{
[self showMessage:[NSString stringWithFormat:@"設(shè)備名:%@",peripheral.name]];
self.cbPeripheral = peripheral;
[self showMessage:@"開始連接"];
[self.centralManager connectPeripheral:peripheral options:nil];
}
}
}
7.連接的三種狀態(tài),如果連接成功,則掃描所有服務(wù)(也可以掃描指定服務(wù))
連接失敗重連
/**
連接失敗
@param central 中心管理者
@param peripheral 連接失敗的設(shè)備
@param error 錯(cuò)誤信息
*/
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
[self showMessage:@"連接失敗"];
if ([peripheral.name isEqualToString:kBlePeripheralName])
{
[self.centralManager connectPeripheral:peripheral options:nil];
}
}
連接斷開重連
/**
連接斷開
@param central 中心管理者
@param peripheral 連接斷開的設(shè)備
@param error 錯(cuò)誤信息
*/
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
[self showMessage:@"斷開連接"];
if ([peripheral.name isEqualToString:kBlePeripheralName])
{
[self.centralManager connectPeripheral:peripheral options:nil];
}
}
連接成功并掃描服務(wù)
/**
連接成功
@param central 中心管理者
@param peripheral 連接成功的設(shè)備
*/
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
NSLog(@"連接設(shè)備:%@成功",peripheral.name);
[self showMessage:[NSString stringWithFormat:@"連接設(shè)備:%@成功",peripheral.name]];
// 設(shè)置設(shè)備的代理
peripheral.delegate = self;
// services:傳入nil代表掃描所有服務(wù)
[peripheral discoverServices:nil];
}
8.發(fā)現(xiàn)服務(wù)并掃描服務(wù)對(duì)應(yīng)的特征
/**
掃描到服務(wù)
@param peripheral 服務(wù)對(duì)應(yīng)的設(shè)備
@param error 掃描錯(cuò)誤信息
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
// 遍歷所有的服務(wù)
for (CBService *service in peripheral.services)
{
NSLog(@"服務(wù):%@",service.UUID.UUIDString);
// 獲取對(duì)應(yīng)的服務(wù)
if ([service.UUID.UUIDString isEqualToString:kWriteServerUUID] || [service.UUID.UUIDString isEqualToString:kNotifyServerUUID])
{
// 根據(jù)服務(wù)去掃描特征
[peripheral discoverCharacteristics:nil forService:service];
}
}
}
9.掃描到對(duì)應(yīng)的特征,寫入特征的值,并訂閱指定的特征通知.
/**
掃描到對(duì)應(yīng)的特征
@param peripheral 設(shè)備
@param service 特征對(duì)應(yīng)的服務(wù)
@param error 錯(cuò)誤信息
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
// 遍歷所有的特征
for (CBCharacteristic *characteristic in service.characteristics)
{
NSLog(@"特征值:%@",characteristic.UUID.UUIDString);
// 獲取對(duì)應(yīng)的特征
if ([characteristic.UUID.UUIDString isEqualToString:kWriteCharacteristicUUID])
{
// 寫入數(shù)據(jù)
[self showMessage:@"寫入特征值"];
for (Byte i = 0x0; i < 0x73; i++)
{
// 讓鋼琴的每顆燈都亮一次
Byte byte[] = {0xf0, 0x3d, 0x3d, i,
0x02,0xf7};
NSData *data = [NSData dataWithBytes:byte length:6];
[peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
}
}
if ([characteristic.UUID.UUIDString isEqualToString:kNotifyCharacteristicUUID])
{
// 訂閱特征通知
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
}
10.根據(jù)特征讀取到數(shù)據(jù)
/**
根據(jù)特征讀到數(shù)據(jù)
@param peripheral 讀取到數(shù)據(jù)對(duì)應(yīng)的設(shè)備
@param characteristic 特征
@param error 錯(cuò)誤信息
*/
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error
{
if ([characteristic.UUID.UUIDString isEqualToString:kNotifyCharacteristicUUID])
{
NSData *data = characteristic.value;
NSLog(@"%@",data);
}
}
讀取值打印結(jié)果:
2017-04-25 12:34:41.876974+0800 藍(lán)牙4.0Demo[1745:346611] <9f5436>
2017-04-25 12:34:41.983016+0800 藍(lán)牙4.0Demo[1745:346611] <8f5440>
2017-04-25 12:34:42.154821+0800 藍(lán)牙4.0Demo[1745:346611] <9f5649>
2017-04-25 12:34:42.239481+0800 藍(lán)牙4.0Demo[1745:346611] <8f5640>
提示:上Appstore下載LightBlue,進(jìn)行藍(lán)牙通信測(cè)試.
作者:o惜樂o
鏈接:http://www.reibang.com/p/b62081c427a4