IOS之BLE藍芽讀取資料與寫入資料
阿新 • • 發佈:2018-12-25
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.寫入藍芽的功能
- 首先根據自己的專案需求
- 然後跟硬體工程師協商好
- 傳送的字元規格,節數等等
如下:傳送“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];
}
最後,經過測試完畢,藍芽的讀取和寫入就闡述到此,如有不懂的可以留言。若有幫助,麻煩點個贊,謝謝您的閱讀!~