1. 程式人生 > >IOS之BLE藍芽讀取資料與寫入資料

IOS之BLE藍芽讀取資料與寫入資料

1.本篇文章歸納了詳細的藍芽讀取,與藍芽寫入的通訊。
2.藉助公司最近一直研發藍芽裝置專案,博主一路走過來,也遇到不少的坑,希望在此能夠給予更多看官的幫助。

  • 藍芽的讀取
  • UUID的主要類檔案,歸納放置在一個檔案:Constants.h
#define APP_NAME    @"DishTemp"

//溫度值功能: 傳送實時溫度資料, 572.0ㄈ(共7個位元組),字串形式.1
#define BOOT_TEMPVALUE_UUID [CBUUID UUIDWithString:@"此處為你們硬體工程師提供的UUID"]

/* OTA Upgrade */
#pragma mark - OTA Upgrade

#define FLASH_ARRAY_ID   @"flashArrayID"
#define FLASH_ROW_NUMBER  @"flashRowNumber"

#define COMMAND_START_BYTE    0x01
#define COMMAND_END_BYTE      0x17
//Bootloader command codes

#define VERIFY_CHECKSUM       0x31
#define GET_FLASH_SIZE        0x32
#define SEND_DATA             0x37
#define ENTER_BOOTLOADER      0x38
#define PROGRAM_ROW           0x39
#define VERIFY_ROW            0x3A
#define EXIT_BOOTLOADER       0x3B


// Bootloader status/Error codes

#define SUCCESS               @"0x00"
#define ERROR_FILE            @"0x01"
#define ERROR_EOF             @"0x02"
#define ERROR_LENGTH          @"0x03"
#define ERROR_DATA            @"0x04"
#define ERROR_COMMAND         @"0x05"
#define ERROR_DEVICE          @"0x06"
#define ERROR_VERSION         @"0x07"
#define ERROR_CHECKSUM        @"0x08"
#define ERROR_ARRAY           @"0x09"
#define ERROR_ROW             @"0x0A"
#define ERROR_BOOTLOADER      @"0x0B"
#define ERROR_APPLICATION     @"0x0C"
#define ERROR_ACTIVE          @"0x0D"
#define ERROR_UNKNOWN         @"0x0F"
#define ERROR_ABORT           @"0xFF"


#define UPGRADE_BTN_TITLE_FOR_SEPERATE_SELECTION    @"NEXT"
#define UPGRADE_BTN_TITLE_DEFAULT                   @"UPGRADE"

#define COMMAND_START_BYTE    0x01
#define COMMAND_END_BYTE      0x17

#define CHECK_SUM   @"checkSum"
#define CRC_16      @"crc_16"
#define ROW_DATA    @"rowData"

/* File parsing alerts */
#define FILE_FORMAT_ERROR           @"FileFormatError"
#define PARSING_ERROR               @"ParsingError"
#define FILE_EMPTY_ERROR            @"FileEmpty"

#define LOCALIZEDSTRING(string) NSLocalizedString(string, nil)

藍芽連結上之後,讀取到服務:BlueHelp.m

//只要掃描到特徵就會呼叫,其中的外設和服務就是特徵所在的外設和服務
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(nonnull CBService *)service error:(nullable NSError *)error{
    if(error){
        NSLog(@"掃描特徵出現錯誤,錯誤原因:%@",error);
    }else{
        //遍歷特徵,拿到需要的特徵進行處理
        for (CBCharacteristic *characteristic in service.characteristics){
            NSLog(@"characteristic is %@",characteristic.UUID);
            //如果是溫度資料處理
            if([characteristic.UUID isEqual:BOOT_TEMPVALUE_UUID]){
                //將全部的特徵資訊打印出來
                _isconnected = true;
                _peripheral = peripheral;
                _sendtempcharateristic = characteristic;
                [peripheral setNotifyValue:YES forCharacteristic:characteristic];
            }
     
            //Tempunit
            else if([characteristic.UUID isEqual:BOOT_TEMPUNIT_UUID]){
                _sendtempunitcharateristic = characteristic;
                [peripheral setNotifyValue:YES forCharacteristic:characteristic];
            }
            else{
                ..........
            }
        }
    }
}

得到藍芽溫度,現在就需要解析溫度資料

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
    BOOL ota = [_userDefaults getOta];
    NSLog(@"ISOTA is %d",ota);
    //不是OTA的情況 也不是傳送資料的情況
    //順序依次為 溫度是否正常->溫度值->溫度符號->溫度地址->溫度報警值->溫度報警靜音->溫度報警開關->電壓提示
    if(!ota&&!_isSendData){
        NSString *temp=[self getTempTMWData:characteristic];
        NSArray *tmp = [temp componentsSeparatedByString:@","];
        
        NSString *nomal = tmp[0];
        NSString *temptemp = tmp[1];
        NSString *tempunit = tmp[2];
        int tempaddre = [tmp[3] intValue];
        
       // NSLog(@"DSADASFDSGFG%@sss%@www%@",nomal,temptemp,tempunit);
        
        self.currentDate = [NSDate date];
        NSString *dateString = [_dateformatter stringFromDate:self.currentDate];
        NSDate *logDate = [_dateformatter dateFromString:dateString];
        long logTime= (long)[logDate timeIntervalSince1970];
        
        //如果要等於F的時候
        if(_currentTime!=logTime){
            if([tempunit isEqualToString:@"F"]){
                //float floatString = [temptemp floatValue];
                //float aa = [_commonUtil convertFahrenheitToCelcius:floatString];
                //正常的時候
                if(tempaddre==0){
                    //NSString *ftempWendu =  [NSString stringWithFormat:@"%f",aa];
                    //NSString *ftempSymbol = @"C";
                    //[_tempDB saveTempname:_deviceName saveTempaddre:tempaddre saveTempTemp:ftempWendu saveTempSymbol:ftempSymbol saveTemptime:logTime];
                }else if(tempaddre==1){
                    //NSString *ftempSymbol = @"C";
                    //[_tempDB saveTempname:_deviceName saveTempaddre:tempaddre saveTempTemp:@"999" saveTempSymbol:ftempSymbol saveTemptime:logTime];
                }
            }else{
                if(tempaddre==0){
                    //[_tempDB saveTempname:_deviceName saveTempaddre:tempaddre saveTempTemp:temptemp saveTempSymbol:tempunit saveTemptime:logTime];
                }else if(tempaddre==1){
                    //[_tempDB saveTempname:_deviceName saveTempaddre:tempaddre saveTempTemp:@"999" saveTempSymbol:tempunit saveTemptime:logTime];
                }
            }
            _currentTime = logTime;
        }
        
        //傳送所有資料
        NSDictionary *tempDict = [NSDictionary dictionaryWithObject:temp forKey:@"tempData"];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"tempNofiction" object:nil userInfo:tempDict];
        
    }

引入BlueHelp.h檔案

#import <Foundation/Foundation.h>
//匯入藍芽框架
#import <CoreBluetooth/CoreBluetooth.h>
#import "DeviceModel.h"
#import "Constants.h"
#import "CommonUserDefaults.h"
#import "CommonUtil.h"
#import "TempDB.h"

#define COMMAND_PACKET_MIN_SIZE  7

@interface BlueHelp : NSObject

//藍芽的裝置搜尋顯示在列表中
@property (nonatomic, strong) NSMutableArray <CBPeripheral*>*periperals;

//連線peripheral
@property(nonatomic,strong) CBPeripheral *peripheral;

//連線peripheral
@property(nonatomic,strong) CBPeripheral *selectperipheral;

//中心管理者
@property (nonatomic, strong) CBCentralManager *centerManager;

@property (nonatomic,strong) DeviceModel *deviceModel;

//裝置列表
@property (nonatomic,strong) NSMutableArray *deviceList;

@property (nonatomic,strong) NSMutableArray *commandArray;
//是否進行ota升級
@property (nonatomic) BOOL isOta;

@property (nonatomic) BOOL isWritePacketDataSuccess;

@property (strong,nonatomic) NSString * checkSumType;

/*!
 *  @property isApplicationValid
 *
 *  @discussion flag used to check whether the application writing is success
 *
 */
@property (nonatomic) BOOL isApplicationValid;
/*!
 *  @property checkSum
 *
 *  @discussion checkSum received from the device for writing a single row
 *
 */
@property (assign) uint8_t checkSum;

/*!
 *  @property startRowNumber
 *
 *  @discussion Device flash start row number
 *
 */
@property (nonatomic) int startRowNumber;

/*!
 *  @property endRowNumber
 *
 *  @discussion Device flash end row number
 *
 */
@property (nonatomic) int endRowNumber;

/*!
 *  @property siliconIDString
 *
 *  @discussion siliconID from the device response
 *
 */
@property (strong,nonatomic) NSString *siliconIDString;
/*!
 *  @property siliconRevString
 *
 *  @discussion silicon rev from the device response
 *
 */
@property (strong,nonatomic) NSString *siliconRevString;


//是否傳送資料
@property (nonatomic) BOOL isSendData;

@property (strong,nonatomic) CommonUtil *commonUtil;

@property (strong,nonatomic) TempDB *tempDB;

@property (strong,nonatomic) NSDate *currentDate;

//時間格式化
@property(strong,nonatomic) NSDateFormatter  *dateformatter;

@property(strong,nonatomic) NSString *deviceName;

//@property (nonatomic,strong) NSUserDefaults *userDefaults;

@property (nonatomic,strong) CommonUserDefaults *userDefaults;
//傳送溫度資料
@property (nonatomic,strong) CBCharacteristic *sendtempcharateristic;
//傳送OTA資料
@property (nonatomic,strong) CBCharacteristic *sendotacharateristic;
//高/低溫度資料
//@property (nonatomic,strong) CBCharacteristic *sendhighalarmcharateristic;
//
//@property (nonatomic,strong) CBCharacteristic *sendlowalarmcharateristic;
//ota
@property (nonatomic,strong) CBCharacteristic *senddfucharateristic;
//傳送字串'CR'清除機子上的最大值(3個位元組)
@property (nonatomic,strong) CBCharacteristic *senddcrstrateristic;
//傳送字串'PD'機子關機(3個位元組)
@property (nonatomic,strong) CBCharacteristic *senddoutstrateristic;
//靜音
@property (strong,nonatomic) CBCharacteristic *sendmutealarmcharateristic;
//calset
@property(strong,nonatomic) CBCharacteristic *sendcalsetcharateristic;
//intervaltime
@property(strong,nonatomic) CBCharacteristic *sendintervaltimecharateristic;
//alarmswitch
@property(strong,nonatomic) CBCharacteristic *sendalarmswitchcharateristic;
//tempunit
@property(strong,nonatomic) CBCharacteristic *sendtempunitcharateristic;

@property(strong,nonatomic) CBCharacteristic *sendlowalarmswitchcharateristic;

///<===============方法區塊=======================>
+ (id)sharedManager;

-(NSMutableArray *)getDeviceList;

-(NSMutableArray *)getPeriperalList;

-(void)startScan;
//連線藍芽
-(void)contentBlue:(int) row;
//斷開藍芽
-(void)disContentBle;

//斷開ota的藍芽連線
-(void)disContentOtaBle;

-(void) discoverCharacteristicsWithCompletionHandler:(void (^) (BOOL success, NSError *error)) handler;

-(void)updateValueForCharacteristicWithCompletionHandler:(void (^) (BOOL success,id command,NSError *error)) handler;

-(void) stopUpdate;

-(void) setCheckSumType:(NSString *) type;

-(NSData *) createCommandPacketWithCommand:(uint8_t)commandCode dataLength:(unsigned short)dataLength data:(NSDictionary *)packetDataDictionary;

-(void) writeValueToCharacteristicWithData:(NSData *)data bootLoaderCommandCode:(unsigned short)commandCode;

/*
 * 停止掃描
 */
-(void)stopScan;

//是否是第一次連線裝置
@property(assign,nonatomic) BOOL isconnected;

@end

此時就是顯示的介面,接收藍芽的廣播

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tempCompletion:) name:@"tempNofiction" object:nil];

接收到廣播,把資訊展示出來

-(void)tempCompletion:(NSNotification*)notification{
    //第一次載入的時候需要這麼執行
    if(_onceLoad){
        [_progress closeLoadingView];
        _tempView.leftView.hidden = FALSE;
        _tempView.rightView.hidden = FALSE;
        _onceLoad = FALSE;
    }
    
    //順序依次為 溫度是否正常->溫度值->溫度符號->溫度地址->溫度報警值->溫度報警靜音->溫度報警開關->電壓提示-靜音報警開關
    // 0-1-2-3-4-5-6-7-8
    NSDictionary *temp = [notification userInfo];
    NSString *tempData = [temp objectForKey:@"tempData"];
    //測試列印
    //NSLog(@"傳過來的溫度是:%@",tempData);
    NSArray *tp = [tempData componentsSeparatedByString:@","];
    
    
    _temptemp = tp[0];//時實溫度
    _TmaxTemp = tp[1];//最大溫度
    _tempunit = tp[2];//溫度符號
    _mutesound = [tp[3] intValue];//低電壓判斷

    //save temp... unit.
    //儲存地址
    [_userDefaults saveMacAddre:self.maclistdata];
    [_userDefaults saveTempUnit:_tempunit macAddre:self.maclistdata];
    [_userDefaults saveCorF:_tempunit macAddre:self.maclistdata];
    //save high alarm.
    
    //當為第一次執行的時候 都統一預設為5秒
    if(_onceRun&&!_onceRunApp){
     
        _tempView.txtaddre.text = self.maclistdata;
        //存入藍芽地址
        if(self.maclistdata!=nil){
            [_userDefaults saveMacAddre:self.maclistdata];
        }
        //存入溫度符號
        if(_tempunit!=nil){
            [_userDefaults saveTempUnit:_tempunit macAddre:self.maclistdata];
        }
        
        //獲取當前的時間
        NSString *time = [_userDefaults getUpdateTime:self.maclistdata];
        if(time!=nil){
            [_blueHelp writeIntervalTime:time];
        }else{
            [_blueHelp writeIntervalTime:@"5"];
        }

        //調式程式
        //[_blueHelp writeHighAlarm:@"-10"];
        
        //傳送cal值
        NSString *cal = [_userDefaults getCal:self.maclistdata currentSymbol:_tempunit];
        if([cal isEqualToString:@""]||cal==nil){
            cal = @"0";
        }
        NSString *calSymbol = [_userDefaults getCalSymbol:self.maclistdata];
        if([_tempunit isEqualToString:calSymbol]){
            [self sendCalSet:cal];
        }else{
            if([_tempunit isEqualToString:@"°C"]){
                if([calSymbol isEqualToString:@"°F"]){
                    float a = [cal floatValue];
                    float b = [_commonUtil convertFahrenheitCalCelcius:a];
                    NSString *bb = [NSString stringWithFormat:@"%0.1f",b];
                    [self sendCalSet:bb];
                }
            }else{
                if([calSymbol isEqualToString:@"°C"]){
                    float a = [cal floatValue];
                    float b = [_commonUtil convertCelciusCalFahren:a];
                    NSString *bb = [NSString stringWithFormat:@"%0.1f",b];
                    [self sendCalSet:bb];
                }
            }
        }
        _onceRun = FALSE;
    }
    
    /*
     * 更新於 2017/11/16 14:44
     */
    //為1的時候顯示 低電量 當為低電量的時候所有的事件也要執行
    [self displayFont:_voltage];
    [self showData];
}

2.寫入藍芽的功能

  1. 首先根據自己的專案需求
  2. 然後跟硬體工程師協商好
  3. 傳送的字元規格,節數等等

如下:傳送“pd”,給底層,為裝置的關機

		NSString *otapd = @"PD";
        [_blueHelp writeBluePD:otapd];//呼叫寫入的類,傳送pd
//PD裝置關機
-(void)writeBluePD:(NSString *)value{
    _isSendData = TRUE;
    [self writeClearPD:value forCharacteristic:_senddoutstrateristic];
    
}
//寫入PD的區塊
-(void)writeClearPD:(NSString *)value forCharacteristic:(CBCharacteristic *)characteristic
{
    NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding];
    NSLog(@"send data pd and is:%@",data);
    //is no write bluetooth data
    if(_senddoutstrateristic.properties & CBCharacteristicPropertyWriteWithoutResponse)
    {
        //send phone on bluetooth data
        [_selectperipheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
    }else
    {
        [_selectperipheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
    }
    //NSLog(@"已經向外設%@的特徵值%@寫入資料",_peripheral.name,characteristic.description);
    _isSendData = FALSE;
}

BlueHelp.h檔案

//傳送字串'PD'機子關機(3個位元組)
@property (nonatomic,strong) CBCharacteristic *senddoutstrateristic;

//寫入裝置的開關按鈕
-(void)writeBluePD:(NSString *)value;

BuleHelp.m檔案

讀取到藍芽UUID服務的時候,加上這個
//傳送字串'PD'機子關機(3個位元組)
            else if([characteristic.UUID isEqual:BOOT_OUTSTRING_UUID]){
                _senddoutstrateristic = characteristic;
                [peripheral setNotifyValue:YES forCharacteristic:characteristic];
            }

最後,經過測試完畢,藍芽的讀取和寫入就闡述到此,如有不懂的可以留言。若有幫助,麻煩點個贊,謝謝您的閱讀!~