前一段時間做一個iPhone端通過藍牙與血壓計交互的軟件,類似于天天血壓這款軟件的功能。在此帶來了關于藍牙的一些分享!
1、外設
外設就是一臺向外發(fā)送信息的設備,它以廣播的形勢進行消息的發(fā)送,在手機和血壓計中,血壓計所扮演的角色就是外設。其它的一些例子,又比如智能手環(huán)、打印機、跑步用的計步器等等,這些設備都是屬于外設。在CoreBluetooth 中是通過CBPeripheralManager來進行管理的。
2、中心
中心是我們所說的手機端,用來接收外設所發(fā)送的信息,比如血壓計測量時所測量的值,測量的最終結(jié)果等信息,另外也可以通過中心端向外設寫入一些值來使外設展示一些功能,比如通過手機端發(fā)送的一些指令使得血壓計啟動測量、關閉測量和關機功能。
二、實現(xiàn)手機端(中心)的代碼邏輯
1、建立中心角色
2、掃描外設
3、連接外設
4、掃描外設中的服務和特征
4.1 獲取外設的services
4.2 獲取外設的Characteristics,獲取Characteristics的值,獲取Characteristics的Descriptor和Descriptor的值
5、與外設做數(shù)據(jù)交互
6、 訂閱Characteristic的通知
7、斷開連接
在此解釋一下什么是服務(services),在硬件工程師開發(fā)一款藍牙設備時,會在設備中定義好服務。在每一個服務中都有一個或多個特征,每個特征的屬性有只讀、只寫、通知等等。
創(chuàng)建中心管理者
//導入框架
#import <CoreBluetooth/CoreBluetooth.h>
@interface XYViewController ()<CBCentralManagerDelegate, CBPeripheralDelegate >
//用于保存被發(fā)現(xiàn)設備
@property (strong, nonatomic) NSMutableArray* myPeripherals;
@end
- (void)viewDidLoad {
[super viewDidLoad];
self.myCentralManager = [[CBCentralManager alloc]initWithDelegate:self queue:nil options:nil];
}
設置主設備的委托,CBCentralManagerDelegate
必須實現(xiàn)的代理方法:
- (void)centralManagerDidUpdateState:(CBCentralManager *)central;//主設備狀態(tài)改變的委托,在初始化CBCentralManager的適合會打開設備,只有當設備正確打開后才能使用
其他選擇實現(xiàn)的委托中比較重要的:
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI; //找到外設的委托
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;//連接外設成功的委托
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;//外設連接失敗的委托
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;//斷開外設的委托
掃描到設備進行連接
//掃描到設備會進入方法
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{
//接下連接測試設備,如果沒有設備,可以下載一個叫l(wèi)ightbule的app去模擬一個設備
//找到的設備必須持有它,否則CBCentralManager中也不會保存peripheral,那么CBPeripheralDelegate中的方法也不會被調(diào)用?。? [myPeripherals addObject:peripheral];
//連接設備
[manager connectPeripheral:peripheral options:nil];
}
一個主設備最多能連7個外設,每個外設最多只能給一個主設備連接,連接成功、失敗、斷開都會進入到相應的代理
//連接到Peripherals-成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
NSLog(@">>>連接到名稱為(%@)的設備-成功",peripheral.name);
[peripheral setDelegate:self];
//掃描外設Services,成功后會進入方法:-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
[peripheral discoverServices:nil];
}
//連接到Peripherals-失敗
-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@">>>連接到名稱為(%@)的設備-失敗,原因:%@",[peripheral name],[error localizedDescription]);
}
//Peripherals斷開連接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
NSLog(@">>>外設連接斷開連接 %@: %@\n", [peripheral name], [error localizedDescription]);
}
掃描到Services
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
// NSLog(@">>>掃描到服務:%@",peripheral.services);
if (error){
NSLog(@">>>Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]);
return;
}
for (CBService *service in peripheral.services) {
NSLog(@"%@",service.UUID);
//掃描每個service的Characteristics,掃描到后會進入方法: -(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
[peripheral discoverCharacteristics:nil forService:service];
}
}
獲取外設的Characteristics,獲取Characteristics的值,獲取Characteristics的Descriptor和Descriptor的值
//掃描到Characteristics
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
if (error)
{
NSLog(@"error Discovered characteristics for %@ with error: %@", service.UUID, [error localizedDescription]);
return;
}
for (CBCharacteristic *characteristic in service.characteristics)
{
NSLog(@"service:%@ 的 Characteristic: %@",service.UUID,characteristic.UUID);
}
//獲取Characteristic的值,讀到數(shù)據(jù)會進入方法:-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
for (CBCharacteristic *characteristic in service.characteristics){
{
[peripheral readValueForCharacteristic:characteristic];
}
}
//搜索Characteristic的Descriptors,讀到數(shù)據(jù)會進入方法:-(void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
for (CBCharacteristic *characteristic in service.characteristics){
[peripheral discoverDescriptorsForCharacteristic:characteristic];
}
}
//獲取的charateristic的值
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
//打印出characteristic的UUID和值
//!注意,value的類型是NSData,具體開發(fā)時,會根據(jù)外設協(xié)議制定的方式去解析數(shù)據(jù)
NSLog(@"characteristic uuid:%@ value:%@",characteristic.UUID,characteristic.value);
}
//搜索到Characteristic的Descriptors
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
//打印出Characteristic和他的Descriptors
NSLog(@"characteristic uuid:%@",characteristic.UUID);
for (CBDescriptor *d in characteristic.descriptors) {
NSLog(@"Descriptor uuid:%@",d.UUID);
}
}
//獲取到Descriptors的值
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error{
//打印出DescriptorsUUID 和value
//這個descriptor都是對于characteristic的描述,一般都是字符串,所以這里我們轉(zhuǎn)換成字符串去解析
NSLog(@"characteristic uuid:%@ value:%@",[NSString stringWithFormat:@"%@",descriptor.UUID],descriptor.value);
}
把數(shù)據(jù)寫到Characteristic中,??在寫入的時候,必須要先寫入與外設建立連接的值,只有建立了連接之后寫入其他的值才能有反應(ps:我被坑過)
//寫數(shù)據(jù)
-(void)writeCharacteristic:(CBPeripheral *)peripheral
characteristic:(CBCharacteristic *)characteristic
value:(NSData *)value{
//打印出 characteristic 的權(quán)限,可以看到有很多種,這是一個NS_OPTIONS,就是可以同時用于好幾個值,
//常見的有read,write,notify,indicate,知知道這幾個基本就夠用了,前連個是讀寫權(quán)限,后兩個都是通知,兩種不同的通知方式。
/*
CBCharacteristicPropertyBroadcast
CBCharacteristicPropertyRead
CBCharacteristicPropertyWriteWithoutResponse
CBCharacteristicPropertyWrite
CBCharacteristicPropertyNotify
CBCharacteristicPropertyIndicate
CBCharacteristicPropertyAuthenticatedSignedWrites
CBCharacteristicPropertyExtendedProperties
CBCharacteristicPropertyNotifyEncryptionRequired
CBCharacteristicPropertyIndicateEncryptionRequired
*/
NSLog(@"%lu", (unsigned long)characteristic.properties);
//只有 characteristic.properties 有write的權(quán)限才可以寫
if(characteristic.properties & CBCharacteristicPropertyWrite){
/*
最好一個type參數(shù)可以為CBCharacteristicWriteWithResponse或type:CBCharacteristicWriteWithResponse,區(qū)別是是否會有反饋
*/
[peripheral writeValue:value forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
}else{
NSLog(@"該字段不可寫!");
}
}
訂閱Characteristic的通知
//設置通知
-(void)notifyCharacteristic:(CBPeripheral *)peripheral
characteristic:(CBCharacteristic *)characteristic{
//設置通知,數(shù)據(jù)通知會進入:didUpdateValueForCharacteristic方法
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
//取消通知
-(void)cancelNotifyCharacteristic:(CBPeripheral *)peripheral
characteristic:(CBCharacteristic *)characteristic{
[peripheral setNotifyValue:NO forCharacteristic:characteristic];
}
斷開連接
//停止掃描并斷開連接
-(void)disconnectPeripheral:(CBCentralManager *)centralManager
peripheral:(CBPeripheral *)peripheral{
//停止掃描
[centralManager stopScan];
//斷開連接
[centralManager cancelPeripheralConnection:peripheral];
}
如何計算寫入的值?
一下為模擬數(shù)據(jù),僅供參考,主要講的是計算思路
藍牙文檔如圖所示


按照文檔流程所示可以算出每一項功能所對應的值以及手機端所接收到值對應的功能
在這些值中其中校驗碼的計算是需要自己計算一下的,計算的方法如下圖所示,現(xiàn)將16進制轉(zhuǎn)化為2進制,然后進行異或運算獲得
