iOS藍牙BLE4.0通信功能


概述

iOS藍牙BLE4.0通信功能,最近剛學的蘋果,為了實現藍牙門鎖的項目,找了一天學習了下藍牙的原理,親手測試了一次藍牙的通信功能,結果成功了,那么就把我學習的東西分享一下。

詳細

一、藍牙常見名稱和縮寫

  • BLE:(Bluetooth low energy)藍牙4.0設備因為低耗電

  • BLE:(Bluetooth low energy)藍牙4.0設備因為低耗電

  • Central:中心設備,發起藍牙連接的設備(一般是指手機)

  • Peripheral:外設,被藍牙連接的設備(一般是運動手環)

  • Service and Characteristic:服務和特征,每個設備會提供服務和特征,類似於服務端的API,但是結構不同,每個設備會有很多服務,每個服務中包含很多特征,這些特征的權限一般分為讀(read),寫(write),通知(notify)幾種,就是我們連接設備后具體需要操作的內容

  • Description:描述,每個Characteristic可以對應一個或者多個Description用於描述Characteristic的信息或屬性

二、藍牙基礎知識

 

1、CoreBluetooth框架的核心其實是倆東西

  • Peripheral

  • Central

image.png

2、這兩組api分別對應不同的業務常見

 

  • 左側叫中心模式,就是以你的app作為中心,連接其他的外設的場景

  • 右側稱為外設模式,使用外設連接其他中心設備操作的場景

3、服務和特征(service and characteristic)

  • 每個設備都會有1個or多個服務

  • 每個服務里都會有1個or多個特征

  • 特征就是具體鍵值對,提供數據的地方

  • 每個特征屬性分為:讀,寫,通知等等

外設,服務,特征的關系

image.png

三、BLE中心模式流程

 

1、建立中心角色

2、掃描外設(Discover Peripheral)

3、連接外設(Connect Peripheral)

4、掃描外設中的服務和特征(Discover Services And Characteristics)

4.1 獲取外設的services

4.2 獲取外設的Characteristics,獲取characteristics的值

4.3 獲取Characteristics的Descriptor和Descriptor的值

5、利用特征與外設做數據交互

6、訂閱Characteristic的通知

7、斷開連接(Disconnect)

四、准備工作

1、一台蘋果設備,進行真機測試

2、一個藍牙模塊或者外設

五、程序實現

項目代碼截圖:

image.png

以下是實現的過程:

1、導入依賴庫、聲明委托、定義變量

#import "ViewController.h"
#import <CoreBluetooth/CoreBluetooth.h>

#define mBLEName @"ZJ2"

@interface ViewController () <CBCentralManagerDelegate, CBPeripheralDelegate>
//手機設備
@property (nonatomic, strong) CBCentralManager *mCentral;
//外設設備
@property (nonatomic, strong) CBPeripheral *mPeripheral;
//特征值
@property (nonatomic, strong) CBCharacteristic *mCharacteristic;
//服務
@property (nonatomic, strong) CBService *mService;
//描述
@property (nonatomic, strong) CBDescriptor *mDescriptor;

@end

2、程序開始時初始化設備

- (CBCentralManager *)mCentral
{
    if (!_mCentral) {
        _mCentral = [[CBCentralManager alloc] initWithDelegate:self
                                                         queue:dispatch_get_main_queue()
                                                       options:nil];
    }
    return _mCentral;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //中心管理者初始化
    [self mCentral];
}

3、當程序退出時,記得斷開連接

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    
    // 停止掃描
    if([self.mCentral isScanning]){
        NSLog(@"stopScan");
        [self.mCentral stopScan];
    }
    //停止連接
    if(nil != self.mPeripheral && self.mPeripheral.state == CBPeripheralStateConnecting){
        NSLog(@"cancelPeripheralConnection");
        [self.mCentral cancelPeripheralConnection:self.mPeripheral];
    }
}

4、掃描外設

//只要中心管理者初始化,就會觸發此代理方法
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
    switch (central.state) {
        case CBManagerStateUnknown:
            NSLog(@"CBManagerStateUnknown");
            break;
        case CBManagerStateResetting:
            NSLog(@"CBManagerStateResetting");
            break;
        case CBManagerStateUnsupported:
            NSLog(@"CBManagerStateUnsupported");
            break;
        case CBManagerStateUnauthorized:
            NSLog(@"CBManagerStateUnauthorized");
            break;
        case CBManagerStatePoweredOff:
            NSLog(@"CBManagerStatePoweredOff");
            break;
        case CBManagerStatePoweredOn:
        {
            NSLog(@"CBManagerStatePoweredOn");
            //搜索外設
            [self.mCentral scanForPeripheralsWithServices:nil // 通過某些服務篩選外設
                                                  options:nil]; // dict,條件
        }
            break;
        default:
            break;
    }
}

5、連接外設

//發現外設后調用的方法
- (void)centralManager:(CBCentralManager *)central // 中心管理者
 didDiscoverPeripheral:(CBPeripheral *)peripheral // 外設
     advertisementData:(NSDictionary *)advertisementData // 外設攜帶的數據
                  RSSI:(NSNumber *)RSSI // 外設發出的藍牙信號強度
{
    NSLog(@"搜索到設備名:%@,設備ID:%@",peripheral.name,peripheral.identifier);
    //(ABS(RSSI.integerValue) > 35)
    //發現完之后就是進行連接
    if([peripheral.name isEqualToString:mBLEName]){
        self.mPeripheral = peripheral;
        self.mPeripheral.delegate = self;
        [self.mCentral connectPeripheral:peripheral options:nil];
    }
}

6、獲取服務

//中心管理者連接外設成功
- (void)centralManager:(CBCentralManager *)central // 中心管理者
  didConnectPeripheral:(CBPeripheral *)peripheral // 外設
{
    NSLog(@"設備連接成功,設備名:%@", peripheral.name);
    //7、外設發現服務,傳nil代表不過濾
    [self.mPeripheral discoverServices:nil];
}

// 外設連接失敗
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    NSLog(@"設備連接失敗,設備名:%@", peripheral.name);
}

// 丟失連接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    NSLog(@"設備丟失連接,設備名:%@", peripheral.name);
}

7、獲取服務中的特征

//發現外設的服務后調用的方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
    // 是否獲取失敗
    if (error) {
        NSLog(@"設備獲取服務失敗,設備名:%@", peripheral.name);
        return;
    }
    for (CBService *service in peripheral.services) {
        self.mService = service;
        NSLog(@"設備獲取服務成功,服務名:%@,服務UUID:%@,服務數量:%lu",service,service.UUID,peripheral.services.count);
        //外設發現特征
        [peripheral discoverCharacteristics:nil forService:service];
    }
}

8、獲取特征中的值和描述

//從服務中發現外設特征的時候調用的代理方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
    if(error){
        NSLog(@"設備獲取特征失敗,設備名:%@", peripheral.name);
        return;
    }
    /**
    CBCharacteristicPropertyRead													= 0x02,
    CBCharacteristicPropertyWriteWithoutResponse									= 0x04,
    CBCharacteristicPropertyWrite													= 0x08,
    CBCharacteristicPropertyNotify													= 0x10,
     */
    for (CBCharacteristic *cha in service.characteristics) {
        if(cha.properties & CBCharacteristicPropertyWrite){
            NSLog(@"CBCharacteristicPropertyWrite");
            NSLog(@"%lu",cha.properties & CBCharacteristicPropertyWrite);
            self.mCharacteristic = cha;
        }else if(cha.properties & CBCharacteristicPropertyWriteWithoutResponse){
            NSLog(@"CBCharacteristicPropertyWriteWithoutResponse");
        }else if(cha.properties & CBCharacteristicPropertyRead){
            NSLog(@"CBCharacteristicPropertyRead");
        }else if(cha.properties & CBCharacteristicPropertyNotify){
            NSLog(@"CBCharacteristicPropertyNotify");
        }else if(cha.properties & CBCharacteristicPropertyIndicate){
            NSLog(@"CBCharacteristicPropertyIndicate");
        }
        NSLog(@"設備獲取特征成功,服務名:%@,特征值名:%@,特征UUID:%@,特征數量:%lu",service,cha,cha.UUID,service.characteristics.count);
        //獲取特征對應的描述 會回調didDiscoverDescriptorsForCharacteristic
        [peripheral discoverDescriptorsForCharacteristic:cha];
        //獲取特征的值 會回調didUpdateValueForCharacteristic
        [peripheral readValueForCharacteristic:cha];
    }
    if(nil != self.mCharacteristic){
        //打開外設的通知,否則無法接受數據
        [peripheral setNotifyValue:YES forCharacteristic:self.mCharacteristic];
    }
}

9、讀取特征中的值和描述

//更新特征值的時候調用,可以理解為獲取藍牙發回的數據
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
    NSString *value = [[NSString alloc] initWithData:characteristic.value encoding:NSASCIIStringEncoding];
    NSLog(@"特征名:%@,特征值:%@",characteristic,value);
    
    if([value isEqualToString:@"open"]){
        
    }else if([value isEqualToString:@"close"]){
        
    }
}

10、狀態改變和發現描述

//通知狀態改變時調用
-(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    if(error){
        NSLog(@"特征名:%@,改變通知狀態失敗",characteristic);
    }
    NSLog(@"特征名:%@,改變了通知狀態",characteristic);
}

//發現外設的特征的描述數組
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error
{
    if(error){
        NSLog(@"設備獲取描述失敗,設備名:%@", peripheral.name);
        return;
    }
    for (CBDescriptor *descriptor in characteristic.descriptors) {
        self.mDescriptor = descriptor;
        [peripheral readValueForDescriptor:descriptor];
        NSLog(@"設備獲取描述成功,描述名:%@",descriptor);
    }
}

11、發送數據

//發送數據
-(void)sendDataToBLE:(NSString *)data{
    NSData* myData = [data dataUsingEncoding:NSUTF8StringEncoding];
    [self.mPeripheral writeValue:myData // 寫入的數據
               forCharacteristic:self.mCharacteristic // 寫給哪個特征
                            type:CBCharacteristicWriteWithResponse];// 通過此響應記錄是否成功寫入
}

-(void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    NSLog(@"數據發送成功");
}

六、運行效果

從電腦串口助手可以看到,發送了兩次的D3數據,手機也收到了兩次11的數據

image.png

這里使用的是藍牙模塊Risym cc2541和蘋果手機實現兩者的通信功能,根據BLE中心模式流程走就可以了

下面是手機設備NSLog打印輸出的結果,從連接到發送數據和接收數據的過程。

image.png

查看大圖

可以發現連接成功后,設備有兩個服務,第一個服務對應有九個特征值,第二個服務對應有一個特征值,驗證了上面的原理是正確的

image.png

查看大圖

七、其他補充

CSDN博客地址:http://blog.csdn.net/qq_30379689/article/details/61413950

CSDN課程地址:http://edu.csdn.net/course/detail/4534

 

注:本文著作權歸作者,由demo大師發表,拒絕轉載,轉載需要作者授權

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM