背景知識(shí)
藍(lán)牙技術(shù)最初由愛立信(也就是多年前手機(jī)做得最丑最奇葩的公司的烁,最終被用戶以腳投票踢出市場(chǎng))創(chuàng)制。技術(shù)始于愛立信公司的1994方案螺男,它是研究在移動(dòng)電話和其他配件間進(jìn)行低功耗、低成本無線通信連接的方法。發(fā)明者希望為設(shè)備間的通訊創(chuàng)造一組統(tǒng)一規(guī)則(標(biāo)準(zhǔn)化協(xié)議)希停,以解決用戶間互不兼容的移動(dòng)電子設(shè)備。1997年前愛立信公司以此概念接觸了移動(dòng)設(shè)備制造商署隘,討論其項(xiàng)目合作發(fā)展宠能,結(jié)果獲得支持。
1998年5月20日磁餐,索尼愛立信违崇、國(guó)際商業(yè)機(jī)器、諾基亞等業(yè)界龍頭創(chuàng)立“特別興趣小組”(Special Interest Group诊霹,SIG)羞延,即[藍(lán)牙技術(shù)聯(lián)盟的前身,目標(biāo)是開發(fā)一個(gè)成本低畅哑、效益高肴楷、可以在短距離范圍內(nèi)隨意無線連接的藍(lán)牙技術(shù)標(biāo)準(zhǔn)。
這項(xiàng)無線技術(shù)的名稱取自古代丹麥維京國(guó)王Harald Bl?tand的名字荠呐,他以統(tǒng)一了因宗教戰(zhàn)爭(zhēng)和領(lǐng)土爭(zhēng)議而分裂的挪威與丹麥而聞名于世赛蔫,而這個(gè)名字的英文便是Harald Bluetooth。
1998年時(shí)藍(lán)牙推出0.7規(guī)格泥张,支持Baseband與LMP(Link Manager Protocol)通訊協(xié)定兩部分呵恢。1999年推出先后0.8版,0.9版媚创、1.0 Draft版渗钉,1.0a版、1.0B版。1.0 Draft版鳄橘,完成SDP(Service Discovery Protocol)協(xié)定声离、TCS(Telephony Control Specification)協(xié)定。1999年7月26日正式公布1.0版瘫怜,確定使用2.4GHz頻譜术徊,最高資料傳輸速度1Mbps,同時(shí)開始了大規(guī)模宣傳鲸湃。和當(dāng)時(shí)流行的紅外線技術(shù)相比赠涮,藍(lán)牙有著更高的傳輸速度,而且不需要像紅外線那樣進(jìn)行接口對(duì)接口的連接暗挑,所有藍(lán)牙設(shè)備基本上只要在有效通訊范圍內(nèi)使用笋除,就可以進(jìn)行隨時(shí)連接。
當(dāng)1.0規(guī)格推出以后炸裆,藍(lán)牙并未立即受到廣泛的應(yīng)用垃它,除了當(dāng)時(shí)對(duì)應(yīng)藍(lán)牙功能的電子設(shè)備種類少,藍(lán)牙裝置也十分昂貴晒衩。2001年的1.1版正式列入IEEE標(biāo)準(zhǔn)嗤瞎,Bluetooth 1.1即為IEEE 802.15.1。同年听系,SIG成員公司超過2000家贝奇。過了幾年之后,采用藍(lán)牙技術(shù)的電子裝置如雨后春筍般增加靠胜,售價(jià)也大幅下降掉瞳。為了擴(kuò)寬藍(lán)牙的應(yīng)用層面和傳輸速度,SIG先后推出了1.2浪漠、2.0版陕习,以及其他附加新功能,例如EDR(Enhanced Data Rate址愿,配合2.0的技術(shù)標(biāo)準(zhǔn)该镣,將最大傳輸速度提高到3Mbps)、A2DP(Advanced Audio Distribution Profile响谓,一個(gè)控音軌分配技術(shù)损合,主要應(yīng)用于立體聲耳機(jī)、AVRCP(A/V Remote Control Profile)等娘纷。Bluetooth 2.0將傳輸率提升至2Mbps嫁审、3Mbps,遠(yuǎn)大于1.x版的1Mbps(實(shí)際約723.2kbps)赖晶。
藍(lán)牙從1.0到2.0其速度與傳輸距離一直是其硬傷律适,使用體驗(yàn)極差文件型的數(shù)據(jù)傳輸幾乎等于不可用,所以我一直對(duì)藍(lán)牙設(shè)備不感冒。直至遇到BLE的出現(xiàn)也就是低功耗藍(lán)牙捂贿,來看看4.0之后的藍(lán)牙有何技術(shù)特性吧:
藍(lán)牙4.0
藍(lán)牙4.0是Bluetooth SIG于2010年7月7日推出的新的規(guī)范纠修。其最重要的特性是支持省電
- Bluetooth 4.0,協(xié)議組成和當(dāng)前主流的Bluetooth h2.x+EDR厂僧、還未普及的Bluetooth h3.0+HS不同分瘾,Bluetooth 4.0是Bluetooth從誕生至今唯一的一個(gè)綜合協(xié)議規(guī)范,
還提出了“低功耗藍(lán)牙”吁系、“傳統(tǒng)藍(lán)牙”和“高速藍(lán)牙”三種模式。 - 其中:高速藍(lán)牙主攻數(shù)據(jù)交換與傳輸白魂;傳統(tǒng)藍(lán)牙則以信息溝通汽纤、設(shè)備連接為重點(diǎn);藍(lán)牙低功耗顧名思義福荸,以不需占用太多帶寬的設(shè)備連接為主蕴坪。前身其實(shí)是NOKIA開發(fā)的Wibree技術(shù),本是作為一項(xiàng)專為移動(dòng)設(shè)備開發(fā)的極低功耗的移動(dòng)無線通信技術(shù)敬锐,在被SIG接納并規(guī)范化之后重命名為Bluetooth Low Energy(后簡(jiǎn)稱低功耗藍(lán)牙)背传。這三種協(xié)議規(guī)范還能夠互相組合搭配、從而實(shí)現(xiàn)更廣泛的應(yīng)用模式台夺,此外径玖,Bluetooth 4.0還把藍(lán)牙的傳輸距離提升到100米以上(低功耗模式條件下)。
- 分Single mode與Dual mode颤介。
- Single mode只能與BT4.0互相傳輸無法向下兼容(與3.0/2.1/2.0無法相通);Dual mode可以向下兼容可與BT4.0傳輸也可以跟3.0/2.1/2.0傳輸
- 超低的峰值梳星、平均和待機(jī)模式功耗,覆蓋范圍增強(qiáng)滚朵,最大范圍可超過100米冤灾。
- 速度:支持1Mbps數(shù)據(jù)傳輸率下的超短數(shù)據(jù)包,最少8個(gè)八組位辕近,最多27個(gè)韵吨。所有連接都使用藍(lán)牙2.1加入的減速呼吸模式(sniff subrating)來達(dá)到超低工作循環(huán)。
- 跳頻:使用所有藍(lán)牙規(guī)范版本通用的自適應(yīng)跳頻移宅,最大程度地減少和其他2.4 GHz ISM頻段無線技術(shù)的串?dāng)_归粉。
- 主控制:可以休眠更長(zhǎng)時(shí)間,只在需要執(zhí)行動(dòng)作的時(shí)候才喚醒吞杭。
- 延遲:最短可在3毫秒內(nèi)完成連接設(shè)置并開始傳輸數(shù)據(jù)盏浇。
- 健壯性:所有數(shù)據(jù)包都使用24-bit CRC校驗(yàn),確保最大程度抵御干擾芽狗。
- 安全:使用AES-128 CCM加密算法進(jìn)行數(shù)據(jù)包加密和認(rèn)證绢掰。
- 拓?fù)洌好總€(gè)數(shù)據(jù)包的每次接收都使用32位尋址,理論上可連接數(shù)十億設(shè)備;針對(duì)一對(duì)一連接最優(yōu)化滴劲,并支持星形拓?fù)涞囊粚?duì)多連接攻晒;使用快速連接和斷開,數(shù)據(jù)可以在網(wǎng)狀拓?fù)鋬?nèi)轉(zhuǎn)移而無需維持復(fù)雜的網(wǎng)狀網(wǎng)絡(luò)班挖。
藍(lán)牙4.1
藍(lán)牙4.1是藍(lán)牙技術(shù)聯(lián)盟于2013年底推出的新的規(guī)范鲁捏,其目的是為了讓 Bluetooth Smart 技術(shù)最終成為物聯(lián)網(wǎng)(Internet of Things)發(fā)展的核心動(dòng)力。
此版本為藍(lán)牙4.0的軟件更新版本萧芙,搭載藍(lán)牙4.0設(shè)備的終端可通過軟件更新獲得此版本给梅。
對(duì)于開發(fā)人員而言,該更新是藍(lán)牙技術(shù)發(fā)展史上一項(xiàng)重要的進(jìn)步双揪。該更新提供了更高的靈活性和掌控度动羽,讓開發(fā)人員能創(chuàng)造更具創(chuàng)新并催化物聯(lián)網(wǎng)(IOT)發(fā)展的產(chǎn)品。
支持多設(shè)備連接渔期。
- 智能連接:增加設(shè)置設(shè)備間連接頻率的支持运吓。制造商可以對(duì)設(shè)備設(shè)置連接進(jìn)行設(shè)置,使得設(shè)備可以更加智能的控制設(shè)備電量疯趟。
藍(lán)牙4.2
藍(lán)牙4.2是藍(lán)牙技術(shù)聯(lián)盟于2014年12月推出的新的規(guī)范拘哨。
藍(lán)牙5
藍(lán)牙5在2016年6月被宣布。在有效傳輸距離上將是4.2LE版本的4倍(理論上可達(dá)300米)信峻,傳輸速度將是4.2LE版本的2倍(速度上限為24Mbps)倦青。藍(lán)牙5.0還支持室內(nèi)定位導(dǎo)航功能(結(jié)合WiFi可以實(shí)現(xiàn)精度小于1米的室內(nèi)定位),允許無需配對(duì)接受信標(biāo)的數(shù)據(jù)(比如廣告盹舞、Beacon姨夹、位置信息等,傳輸率提高了8倍)矾策,針對(duì)物聯(lián)網(wǎng)進(jìn)行了很多底層優(yōu)化磷账。
看完這些特性除了不能上網(wǎng)以外其它的無線能力幾乎都能秒殺WIFI了。
藍(lán)牙常見名稱和縮寫
在進(jìn)入IOS之前我們得深入到的理論領(lǐng)域贾虽,了解藍(lán)牙4.0中的一些基本的術(shù)語:
- MFI:make for ipad, iphone, itouch 專們?yōu)樘O果設(shè)備制作的設(shè)備
- BLE:buletouch low energy逃糟,藍(lán)牙4.0設(shè)備因?yàn)榈秃碾姡砸步凶鯞LE
- peripheral:外設(shè)蓬豁,被連接的設(shè)備
- central:中心绰咽,發(fā)起連接的時(shí)central
- service:服務(wù),每個(gè)外設(shè)會(huì)有很多服務(wù)地粪,每個(gè)服務(wù)中包含很多字段取募,這些字段的權(quán)限一般分為 讀read,寫write蟆技,通知notiy幾種玩敏,就是我們連接設(shè)備后具體需要操作的內(nèi)容斗忌。
- characteristic:特征 每個(gè)設(shè)備會(huì)提供服務(wù)和特征,類似于服務(wù)端的api旺聚,但是機(jī)構(gòu)不同织阳。
- Description:每個(gè)characteristic可以對(duì)應(yīng)一個(gè)或多個(gè)Description用戶描述characteristic的信息或?qū)傩?br> 外設(shè)、服務(wù)砰粹、特征間的關(guān)系
外設(shè)唧躲、服務(wù)、特征間的關(guān)系
下圖你在Apple的開發(fā)者網(wǎng)站上也能找到:
藍(lán)牙中心模式流程
- 建立中心角色
- 掃描外設(shè)(discover)
- 連接外設(shè)(connect)
- 掃描外設(shè)中的服務(wù)和特征(discover)
4.1 獲取外設(shè)的services
4.2 獲取外設(shè)的Characteristics,獲取Characteristics的值,獲取Characteristics的Descriptor和Descriptor的值 - 與外設(shè)做數(shù)據(jù)交互(explore and interact)
- 訂閱Characteristic的通知
- 斷開連接(disconnect)
藍(lán)牙設(shè)備工作的狀態(tài)
- 準(zhǔn)備(standby)
- 廣播(advertising)
- 監(jiān)聽掃描(Scanning
- 發(fā)起連接(Initiating)
- 已連接(Connected)
藍(lán)牙和版本的使用限制
- 藍(lán)牙2.0:越獄設(shè)備
- 藍(lán)牙4.0:IOS6 以上
- MFI認(rèn)證設(shè)備(Make For ipod/ipad/iphone):無限制
iOS 的實(shí)現(xiàn)
先創(chuàng)建一個(gè) Swift 的工程嵌器,然后引入CoreBluetooth
界酒,它就是iOS中提供藍(lán)牙通信的核心庫。然后ViewController必須實(shí)現(xiàn) CBCentralManagerDelegate
,CBPeripheralDelegate
兩個(gè)接口:
import CoreBluetooth
import UIKit
class ViewController: UIViewController, CBCentralManagerDelegate,CBPeripheralDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
}
1.) 建立中心角色
然后要定義一個(gè)管理中心的對(duì)象變量嘴秸,它就是藍(lán)牙控制的主入口,然后在viewDidLoad()
中實(shí)例化它:
class ViewController: UIViewController, CBCentralManagerDelegate,CBPeripheralDelegate {
var manager : CBCentralManager!
override func viewDidLoad() {
super.viewDidLoad()
manager = CBCentralManager.init(delegate: self, queue: DispatchQueue.main)
}
}
2.) 掃描外設(shè)
管理中心一但被初始化后就會(huì)檢查當(dāng)前手機(jī)上的藍(lán)牙狀態(tài)庇谆,并調(diào)用 centralManagerDidUpdateState
方法岳掐,假設(shè)完整初始化后就馬上進(jìn)行設(shè)備掃描,那就要在centralManagerDidUpdateState
中進(jìn)行饭耳,在 viewDidLoad
下方加入以下的代碼:
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .unknown:
print("未知的藍(lán)牙設(shè)備")
case .resetting:
print("藍(lán)牙正在被重置中")
case .unsupported:
print("不支持藍(lán)牙服務(wù)")
case .unauthorized:
print("藍(lán)牙服務(wù)未被授權(quán)")
case .poweredOff:
print("藍(lán)牙服務(wù)已關(guān)閉")
case .poweredOn:
print("藍(lán)牙已啟動(dòng),開始掃描...")
startScan()
}
}
/// 掃描藍(lán)牙設(shè)備
func startScan() {
manager.scanForPeripherals(withServices: nil, options: nil)
}
注:只有返回
.poweredOn
狀態(tài)下才能進(jìn)行藍(lán)牙設(shè)備的掃描串述。
scanForPeripherals
方法就是對(duì)可發(fā)現(xiàn)的藍(lán)牙設(shè)備進(jìn)行掃描,輸入的參數(shù)可以作一些過濾條件寞肖,我這里是不加任何的過濾條件無差別化地掃描纲酗。
3.) 連接外設(shè)
當(dāng)scanForPeripherals
方法被調(diào)用后,CoreBluetooth
就會(huì)調(diào)用centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber)
新蟆,所以我們就得在這個(gè)方法內(nèi)將我們的目標(biāo)藍(lán)牙設(shè)備找出來觅赊,然后用一個(gè)變量Hold住它,否則這個(gè)外設(shè)就會(huì)被釋放掉琼稻,然后你就會(huì)在XCode中得到一條提示信息說你沒有Hold住你需要的設(shè)備變量了吮螺。
// 定義一個(gè)變量來Hold住目標(biāo)設(shè)備
var connectedPeripheral : CBPeripheral!
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if (peripheral.name=="BT05") {
manager.connect(peripheral, options:nil)
// 找到的設(shè)備必須持有它,否則CBCentralManager中也不會(huì)保存peripheral帕翻,那么CBPeripheralDelegate中的方法也不會(huì)被調(diào)用鸠补!
connectedPeripheral = peripheral
print("正在連接:\(peripheral.name)...")
}
}
由于我不知道我的設(shè)備的ServiceUUID是什么,為了方便我編碼的需要所以我只找一個(gè)名為"BT05"的設(shè)備名稱(這是我藍(lán)牙模塊的默認(rèn)名字)找到之后就馬上調(diào)用connect
進(jìn)行連接嘀掸,注意:當(dāng)中心對(duì)象不停止掃描(manager.stopScan()
)以上的方法就會(huì)不斷地被調(diào)用
一個(gè)主設(shè)備最多能連7個(gè)外設(shè)紫岩,每個(gè)外設(shè)最多只能給一個(gè)主設(shè)備連接,連接成功,失敗睬塌,斷開會(huì)進(jìn)入各自的委托
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?)
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?)
下文就會(huì)補(bǔ)充這幾個(gè)委托方法的實(shí)現(xiàn)
4.1) 獲取外設(shè)的服務(wù)
當(dāng)連接成功后 centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
就會(huì)被調(diào)用泉蝌,在這里我們會(huì)設(shè)置找到的外設(shè)對(duì)象的委托(self)歇万,通常這個(gè)方法內(nèi)會(huì)做另一種篩選那就是服務(wù)特征,通俗點(diǎn)說就是這個(gè)藍(lán)牙設(shè)備可以提供些啥服務(wù)梨与,例如寫入堕花,讀取,或者其它什么的一些動(dòng)作粥鞋。
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral){
print("正在查找Service")
// 外設(shè)尋找目標(biāo)服務(wù)
peripheral.discoverServices(nil)
peripheral.delegate = self
self.title = peripheral.name
// 停止掃描
manager.stopScan()
}
4.2) 獲取外設(shè)特征
discoverServices(nil)
傳入了nil
那么就啥服務(wù)信息都直接獲取,然后對(duì)服務(wù)進(jìn)行發(fā)現(xiàn)缘挽,這個(gè)過程和前文中的設(shè)備發(fā)現(xiàn)非常的像
// 這個(gè)服務(wù)地址可以從設(shè)備中查到的
let ServiceUUID = "FFE0"
//掃描到Services
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?){
if (error != nil){
print("查找 services 時(shí) \(peripheral.name) 報(bào)錯(cuò) \(error?.localizedDescription)")
}
for service in peripheral.services! {
// 需要連接的 CBCharacteristic 的 UUID
if service.uuid.uuidString == ServiceUUID {
peripheral.discoverCharacteristics(nil, for: service)
}
}
}
5) 與外設(shè)做數(shù)據(jù)交互
這樣我們實(shí)現(xiàn)的CBPeripheralDelegate
委托接口中的peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?)
將會(huì)被調(diào)用,用于讀取藍(lán)牙傳過來的數(shù)據(jù)呻粹。
// 同理我們要Hold住特征變量壕曼,否則會(huì)被釋放掉
var savedCharacteristic : CBCharacteristic!
var lastString : NSString!
// Interface Build 中的標(biāo)簽對(duì)象,用來顯示從傳感器讀取的室溫
@IBOutlet weak var ?lbTemperature: UILabel!
//獲取的charateristic的值等浊,處理收接到的數(shù)據(jù)
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
// 好了腮郊,charcteristic.value 就是從藍(lán)牙設(shè)備傳過來的原數(shù)據(jù)內(nèi)容,我們可以在這里進(jìn)行處理
let resultStr = NSString(data: characteristic.value!, encoding: String.Encoding.utf8.rawValue)
print(resultStr)
// 將溫度顯示到標(biāo)簽中
lbTemperature.text = resultStr
if lastString == resultStr {
return;
}
self.savedCharacteristic = characteristic
}
6) 訂閱 Characteristic 的通知
由于BLE4.0的"減弱式呼吸"工作特性我們需要對(duì)外設(shè)置發(fā)出的通知進(jìn)行訂閱筹燕,如數(shù)據(jù)發(fā)生改變中心可以第一時(shí)間獲知轧飞。
/// 掃描到 characteristic 時(shí)
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error? {
if error != nil {
print("查找 characteristics 時(shí) \(peripheral.name) 報(bào)錯(cuò) \(error?.localizedDescription)")
}
//獲取Characteristic的值,讀到數(shù)據(jù)會(huì)進(jìn)入方法:
for characteristic in service.characteristics! {
peripheral.readValue(for: characteristic)
//設(shè)置 characteristic 的 notifying 屬性 為 true 撒踪, 表示接受廣播
peripheral.setNotifyValue(true, for: characteristic)
}
}
7) 斷開連接
其實(shí)到此這個(gè)App就完成了过咬,以下的這些代碼是對(duì)相關(guān)的錯(cuò)誤處理進(jìn)行補(bǔ)全:
/// 連接到Peripherals-失敗
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?){
print("連接到名字為 \(peripheral.name) 的設(shè)備失敗,原因是 \(error?.localizedDescription)")
}
/// 斷開
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?){
print("連接到名字為 \(peripheral.name) 的設(shè)備斷開制妄,原因是 \(error?.localizedDescription)"
let alertView = UIAlertController.init(title: "抱歉", message: "藍(lán)牙設(shè)備\(peripheral.name)連接斷開掸绞,請(qǐng)重新掃描設(shè)備連接", preferredStyle: UIAlertControllerStyle.alert)
alertView.show(self, sender: nil)
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?){
if error != nil{
print("寫入 characteristics 時(shí) \(peripheral.name) 報(bào)錯(cuò) \(error?.localizedDescription)")
}
// 這里可以處理向設(shè)備寫入數(shù)據(jù)時(shí)的回調(diào)
}
在下一篇中將會(huì)介紹藍(lán)牙設(shè)備與Arduino 一端關(guān)于硬件部分與固件部分的制作。