藍(lán)牙介紹:使用的是網(wǎng)上購買的一個簡單的藍(lán)牙模塊
藍(lán)牙模塊地址:藍(lán)牙模塊地址
USB轉(zhuǎn)TTL:轉(zhuǎn)接模塊地址
AT-09藍(lán)牙4.0BLE 模塊
該藍(lán)牙模塊相當(dāng)簡單,適合初學(xué)者入門使用
下面是該藍(lán)牙的設(shè)備信息以及傳輸特性:
廣播數(shù)據(jù):
{
是否可連接
kCBAdvDataIsConnectable = 1;
Mac地址
kCBAdvDataManufacturerData = <1a9888a0 3ca30807 b90a>;
兩種服務(wù)
kCBAdvDataServiceUUIDs = (
FFE0,
FEE0
);
}
這里的服務(wù)有FFE0和FEE0兩種董济,F(xiàn)FE0代表攜帶設(shè)備信息的服務(wù)矢赁,F(xiàn)EE0代表傳輸特性
FFE0服務(wù)的特征:
(
攜帶設(shè)備信息
"<CBCharacteristic: 0x13d6ba1d0, UUID = System ID, properties = 0x2, value = (null), notifying = NO>",
"<CBCharacteristic: 0x13d6ba390, UUID = Model Number String, properties = 0x2, value = (null), notifying = NO>",
"<CBCharacteristic: 0x13d6ba3f0, UUID = Serial Number String, properties = 0x2, value = (null), notifying = NO>",
"<CBCharacteristic: 0x13d6ba330, UUID = Firmware Revision String, properties = 0x2, value = (null), notifying = NO>",
"<CBCharacteristic: 0x13d6ba550, UUID = Hardware Revision String, properties = 0x2, value = (null), notifying = NO>",
"<CBCharacteristic: 0x13d6ba480, UUID = Software Revision String, properties = 0x2, value = (null), notifying = NO>",
"<CBCharacteristic: 0x13d6ba750, UUID = Manufacturer Name String, properties = 0x2, value = (null), notifying = NO>",
"<CBCharacteristic: 0x13d6ba800, UUID = IEEE Regulatory Certification, properties = 0x2, value = (null), notifying = NO>",
"<CBCharacteristic: 0x13d6ba860, UUID = PnP ID, properties = 0x2, value = (null), notifying = NO>"
)
FEE0服務(wù)的特征:
"<CBCharacteristic: 0x13d563890, UUID = FFE1, properties = 0x1E, value = (null), notifying = NO>"
此藍(lán)牙模塊只有簡單的傳輸特性,讀寫的特征為同一個基协,并且由于讀寫服務(wù)FEE0
的屬性properties
為0x1E
,按照網(wǎng)上的資料,0x1E
應(yīng)該是CBCharacteristicPropertyRead=0x02
,CBCharacteristicPropertyWriteWithoutResponse=0x04
,CBCharacteristicPropertyWrite=0x08
信峻,CBCharacteristicPropertyNotify=0x10
的組合,可是實(shí)際上當(dāng)發(fā)送數(shù)據(jù)后去讀數(shù)據(jù)時只能采取手動調(diào)用的方式讀取并且返回固定值;
藍(lán)牙相關(guān)對象需要被控制器對象持有
創(chuàng)建NSObject
類BLEManager
導(dǎo)入<CoreBluetooth/CoreBluetooth.h>
框架,在.h
文件接口遵守CBCentralManagerDelegate,CBPeripheralDelegate
協(xié)議,在控制器文件BLEManager
下創(chuàng)建以下屬性:
@property (retain, nonatomic) CBCentralManager *centralManager; //中心設(shè)備
@property (retain, nonatomic) CBPeripheral *discoveredPeripheral; //外圍設(shè)備
@property (retain, nonatomic) CBCharacteristic *discoveredCharacteristic; //服務(wù)特征
用于持有相關(guān)對象瓮床。
- 1.實(shí)例化一個中心設(shè)備對象
if (!self.centralManager){
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
設(shè)置代理盹舞,默認(rèn)主線程操作。
- 2.設(shè)備對象實(shí)例化代理
#pragma mark - CentralManager Delegate
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
if (central.state==CBCentralManagerStateUnsupported)
{
//手機(jī)不支持低功耗藍(lán)牙
return;
}
if (central.state==CBCentralManagerStatePoweredOff) {
//手機(jī)藍(lán)牙未開啟
return;
}
if (central.state == CBCentralManagerStateUnauthorized)
{
//系統(tǒng)設(shè)置不允許
return;
}
if (central.state == CBCentralManagerStatePoweredOn) {
在這里開始掃描外圍設(shè)備的服務(wù)
這里的Services表示UUID隘庄,傳參代表值掃描帶有該UUID的設(shè)備踢步,也可以傳nil
CBCentralManagerScanOptionAllowDuplicatesKey設(shè)置為NO表示不會重復(fù)掃描已經(jīng)發(fā)現(xiàn)的設(shè)備
[self.centralManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey : @NO }];
}
}
這個代理返回中心設(shè)備能否進(jìn)行藍(lán)牙操作的信息,這里列出了不支持丑掺,未開啟获印,支持三種狀態(tài)。
- 3.掃描周圍設(shè)備
在這里可以得到掃描到廣播的設(shè)備信息街州,包括設(shè)備對象兼丰,信號,廣播信息等唆缴,
這個方法不斷刷新鳍征,一直尋找周圍的設(shè)備,篩選設(shè)備連接成功之后面徽,可以手動停止掃描艳丛。
/**
掃描周圍設(shè)備的回調(diào)
@param central 中心設(shè)備對象
@param peripheral 周圍設(shè)備對象
@param advertisementData 廣播數(shù)據(jù)
@param RSSI 信號
*/
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
可以在這里設(shè)置連接名字以MLT開頭的設(shè)備
if ([peripheral.name hasPrefix:@"MLT"]) {
self.discoveredPeripheral = peripheral;
[self.centralManager connectPeripheral:peripheral options:nil];
}
}
- 4連接結(jié)果回調(diào)
//成功鏈接外圍設(shè)備
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
//停止掃描
[self.centralManager stopScan];
//設(shè)置外圍設(shè)備代理
peripheral.delegate = self;
//查找連接設(shè)備的所有服務(wù)
[peripheral discoverServices:nil];
}
//連接外圍設(shè)備失敗
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
//與外圍設(shè)備連接斷開
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
可以在這里向外部發(fā)送連接斷開的通知
可以這里可以設(shè)置自動重新掃描連接
}
- 5外圍設(shè)備的代理方法
#pragma mark - Peripheral Delegate
//找到對應(yīng)的服務(wù)代理方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
if (error) {
NSLog(@"Error is %@", [error localizedDescription]);
return;
}
//查找連接設(shè)備的服務(wù)的所有特征
for (CBService *service in peripheral.services) {
[peripheral discoverCharacteristics:nil forService:service];
}
}
- 6.查找特征的代理方法
//找到特性代理方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
if (error) {
NSLog(@"Error is %@", [error localizedDescription]);
return;
}
for (CBCharacteristic *characteristic in service.characteristics)
{
//設(shè)置特性2的通知為YES,以收取外圍設(shè)備發(fā)過來的數(shù)據(jù) - 讀數(shù)據(jù)
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"FFE1"]])
{
開啟讀服務(wù)通知
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
self.discoveredCharacteristic=characteristic; //保持服務(wù)特征
}
}
}
特征值的通知設(shè)置發(fā)生改變時觸發(fā)的方法斗忌,在代碼中設(shè)置允許讀寫通知時都會進(jìn)入此方法
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (error){
NSLog(@"改變特征通知錯誤: %@", error.localizedDescription);
}
當(dāng)不是傳輸特征時质礼,不做處理
if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:@"FFE1"]]){
return;
}
當(dāng)傳輸特征通知開啟時,連接成功(到這一步才可以正常進(jìn)行數(shù)據(jù)交互)
if (characteristic.isNotifying){
在這里可以向外發(fā)送連接成功通知
}else{
否則取消連接
[self.centralManager cancelPeripheralConnection:peripheral];
}
}
- 7.寫數(shù)據(jù)
//自定義寫數(shù)據(jù)的動態(tài)方法
-(void)writeDataToBle:(NSString *)instruction{
if (self.discoveredPeripheral&&self.discoveredCharacteristic)
{
[self.discoveredPeripheral writeValue:[[NSData alloc] initWithBytes:[self hexStringToBytes:instruction] length:[instruction length]/2.0] forCharacteristic:self.discoveredCharacteristic type:CBCharacteristicWriteWithResponse];
}
}
其中CBCharacteristicWriteType
有兩個選擇:
1 . CBCharacteristicWriteWithResponse
接收寫操作回調(diào)
2 . CBCharacteristicWriteWithoutResponse
不接受寫操作回調(diào)
前者表示寫數(shù)據(jù)成功或者失敗都會得到回調(diào)织阳,后者則沒有。
當(dāng)選擇2的模式時候砰粹,藍(lán)牙的讀數(shù)據(jù)必須允許通知唧躲,不然讀數(shù)據(jù)的回調(diào)將沒有反應(yīng)造挽。在藍(lán)牙讀數(shù)據(jù)通知開啟,特征的屬性值包含CBCharacteristicWriteWithoutResponse
,并且選擇2的方式發(fā)送數(shù)據(jù)的情況下弄痹,一旦發(fā)送數(shù)據(jù)到藍(lán)牙饭入,藍(lán)牙將通過讀數(shù)據(jù)回調(diào)返回?cái)?shù)據(jù)。
當(dāng)選擇1的模式的時候肛真,發(fā)送數(shù)據(jù)操作將進(jìn)入下面的回調(diào)方法里面谐丢,我們可以判斷發(fā)送數(shù)據(jù)的操作是否成功,如果成功可以手動調(diào)用蚓让,讀取藍(lán)牙返回?cái)?shù)據(jù)的方法來得到藍(lán)牙返回的數(shù)據(jù)
寫數(shù)據(jù)的回調(diào)
-(void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
//當(dāng)錯誤為空的時候可以在這里手動調(diào)用讀數(shù)據(jù)的方法乾忱,調(diào)用該方法,程序也會在讀數(shù)據(jù)的代理里面得到藍(lán)牙返回的數(shù)據(jù)历极。
[self.discoveredPeripheral readValueForCharacteristic: self.discoveredCharacteristic];
}
- 8.讀數(shù)據(jù)的回調(diào)
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
if (error) {
NSLog(@"Error: %@", [error localizedDescription]);
return;
}
NSString *stringFromData = [characteristic.value description];
//刪除字符串中的空格
stringFromData=[stringFromData stringByReplacingOccurrencesOfString:@" " withString:@""];
//刪除字符串中的尖括號
stringFromData=[stringFromData stringByReplacingOccurrencesOfString:@"<" withString:@""];
stringFromData=[stringFromData stringByReplacingOccurrencesOfString:@">" withString:@""];
NSLog(@"Received: %@", stringFromData);
}
附錄:
下面文章作為借鑒