中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

用樹莓派玩轉藍牙

發布時間:2020-06-14 10:15:05 來源:網絡 閱讀:641 作者:余凱力 欄目:建站服務器

藍牙是一個使用廣泛的無線通信協議,這兩年又隨著物聯網概念進一步推廣。我將介紹藍牙協議,特別是低功耗藍牙,并用樹莓派來實踐。樹莓派3中內置了藍牙模塊。樹莓派通過UART接口和該模塊通信。樹莓派1和樹莓派2中沒有內置的藍牙模塊,不過你可以通過USB安裝額外的藍牙適配器。

 

藍牙介紹 

藍牙最初由愛立信創制,旨在實現可不同設備之間的無線連接。藍牙無線通信的頻率在2.4GHz附近,和WiFi一樣,都屬于特高頻。相對于低頻信號來說,高頻傳輸的速度比較快,穿透能力強,但傳輸距離比較受限。在沒有遮蔽和干擾的情況下,藍牙設備的最大通信距離能達到30米。但在大多數情況下,藍牙的實際通信距離在2到5米。相比之下,低頻433MHz設備的通信距離很容易超過百米。因此,藍牙常用于近距離的無線設備,比如無線鼠標和鍵盤。

用樹莓派玩轉藍牙

藍牙的標志 

 

藍牙的基本工作流程如下:

  1. 廣播/掃描:通信的一方向外廣播自己的信息。另一方通過掃描知道自己周邊有哪些藍牙設備在廣播,這些設備的地址是什么,以及是否可以連接。

  2. 連接:通信的一方向另一方發起連接請求。雙方通過一系列的數據交換建立連接。

  3. 數據通信

根據細節上的差別,藍牙通信又細分為兩種:經典藍牙和低功耗藍牙。早期的藍牙通信方式稱為經典藍牙(classic bluetooth)。經典藍牙中的數據傳輸協議是串行仿真協議RFCOMM。RFCOMM仿真了常見的串口連接。數據從一端輸入,從另一端取出。經典藍牙的開發非常簡單。基于串口開發的有線鍵鼠程序,就可以直接用于RFCOMM連接的無線鍵鼠。此外,經典藍牙可以快速傳輸數據。因此,諾基亞N95這樣的早期智能手機,也用RFCOMM來互傳圖片和文件。

用樹莓派玩轉藍牙

RFCOMM通信

 

經典藍牙的缺點是比較耗電。后來,諾基亞發明了一種可以降低功耗的藍牙通信方式。2010年出臺的藍牙4.0把這種通信方式規范為“低功耗藍牙”(BLE,Bluetooth Low Energy)。BLE把通信雙方分為非對稱的雙方,盡量讓其中的一方承擔主要的開銷,減少另一方的負擔。舉例來說,手環電量少,而且需要長時間待機。BLE通信的主要負擔可以放在電量較充裕且充電方便的手機一側,從而減少手環的能耗。

用樹莓派玩轉藍牙

手環作為外設

BLE通信一般也包含廣播/掃描的步驟。主動發起廣播的設備稱為外設(Peripheral),掃描設備稱為中心設備(Central)。BLE連接成功之后,就可以開始數據傳輸。BLE的數據傳輸協議是ATT和GATT協議。ATT是GATT的基礎。ATT協議把通信雙方分為服務器(server)和客戶(client)。客戶主動向服務器發起讀寫操作。需要注意的是,ATT中的服務器和客戶,與廣播階段的外設和中心設備相互獨立。當然,在手環這樣的應用場景下,外設通常也是服務器。ATT協議以屬性(attribute)為單位進行該數據傳輸。一個屬性的格式如下:

用樹莓派玩轉藍牙

ATT屬性

我們分別來理解屬性的不同部分:

  1. handle:屬性的唯一編號,長度為16位。

  2. type:屬性的類型。每種類型用一個UUID編號。

  3. value:屬性的值。

  4. permission:屬性的權限,分為無、可讀、可寫、可讀寫。

服務器儲存了多個屬性。當客戶向服務器請求時,服務器會把自己的屬性列表發給客戶。隨后,客戶可以向服務器讀取或寫入某一個屬性值。用讀寫的方式,通信雙方實現了雙向通信。

用樹莓派玩轉藍牙

以智能手表為例。智能手表和手機配對后,手機可以用讀的方式獲得智能手表中某個屬性下保存的步數,也可以用寫的方式寫入另一個屬性負責的時間。在讀寫操作中,都是由客戶采取主動,服務器只能被動應答。ATT還提供了通知(notification)的工作方式。當服務器改變了某個屬性值時,可以主動通知訂閱了該屬性值的客戶。智能手表中的手勢識別,就可以通過通知的方式告知手機。這樣的話,手機就可以實時地獲知手勢改變信息。

用樹莓派玩轉藍牙

GATT協議構建在ATT協議之上,為屬性提供了組織形式。GATT的最小組織單元是Characteristic,可以由數條屬性組成。下圖中就是一個Characteristic,用于傳輸紅外測溫獲得的數據。這個例子來自TI的SensorTag:

用樹莓派玩轉藍牙

 從左到右:handle(16進制),handle(10進制),type(16進制),type(文字說明),value(16進制),permission,備注

 

Characteristc的第一條屬性用于聲明屬性,其類型總是0x2803。這條聲明的value部分又可以細分為三部分。第一個部分是0x12,稱為Characteristic Properties,是GATT協議層面上的權限控制。其具體含義可參考資料。第二部分0x0025,是Characteristic值的handle。找到handle為0x0025的屬性,就在聲明屬性的下面一行。0x0025的value部分就是紅外溫度的真正數值。剩下的部分是該Characteristic的UUID,總共128位:

F000-AA01-0451-4000-B000-000000000000

檢查Characteristic值的那一行屬性,也就是0x0025屬性。它的類型也是該Characteristic UUID。除了128位的UUID,藍牙官方還提供了16位的UUID可供使用,可參考資料。

 

可以看到,一個Characterstic至少需要兩個屬性,一個用于聲明,一個用于儲存它的數據。除此之外,Characteristic還有稱為Descriptor的額外描述信息。每個Decriptor占據一行。比如0x0027這個Descriptor,其屬性值是54:65:6D:70:7E:20:44:61:74:61,翻譯成ASCII就是:

Temp~ Data

此外,溫度單位、測量頻率等描述信息也經常會以Descriptor的形式放入到Characteristic中。在下一個Characteristic聲明出現前的屬性,都是該Characteristic的Descriptor。

 

我們再來看更高級的組織單位Service。一個Service也有行屬性作為聲明,其類型UUID是0x2800。聲明屬性的值就是該Service的128位UUID。藍牙官方也提供了16位的UUID,預留給特定的Service,可參考資料。在下一個Service聲明出現前的屬性,都屬于該Service,比如下圖中從0x0023到0x002D的屬性:

用樹莓派玩轉藍牙

圖中包含了一個與紅外溫度計相關的Service。Service里又有三個Characteristic,分別0x0024-0x0027、0x0028-0x002A、0x002B-0x002D。我已經介紹過第一個Characteristic。第二個Characteristic用于傳輸溫度計參數,第三個用于設置測溫頻率。

 

Service和Characteristic都是屬性的組織形式。客戶可以向服務器請求Service和Characteristic列表,然后對其進行操作。GATT還提供了Profile,可以包括多個Service。不過,Profile并不像前面兩者那樣存在于服務器。Profile是一種標準,用于說明一個特型設備應該有哪些Service。比如說,HID(Human Interface Device)這種Profile,就說明了藍牙輸入設備應該提供的Service。藍牙官方定義的Profile可參考資料。

 

BlueZ

我們用樹莓派來深入實踐上面學到的藍牙知識。首先要在樹莓派上安裝必要的工具。BlueZ是Linux官方的藍牙協議棧。你可以通過BlueZ提供的接口,進行豐富的藍牙操作。Raspbian中已經安裝了BlueZ。我使用的版本是5.43。你可以檢查自己的BlueZ版本:

bluetoothd -v

低版本的BlueZ對低功耗藍牙的支持有限。如果你的使用版本低于5.43,那么我建議你升級BlueZ。

 

你可以用下面的命令檢查BlueZ的運行狀態:

systemctl status bluetooth

我的返回結果是:

用樹莓派玩轉藍牙

● bluetooth.service - Bluetooth service
   Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled)
   Active: active (running) since Sun 2017-04-23 19:03:08 CST; 1 day 6h ago
     Docs: man:bluetoothd(8)
 Main PID: 709 (bluetoothd)
   Status: "Running"
   CGroup: /system.slice/bluetooth.service
           └─709 /usr/lib/bluetooth/bluetoothd -C

用樹莓派玩轉藍牙

可以看到,藍牙服務已經打開,并在正常運行。

 

你可以用下面命令手動啟動或關閉藍牙服務:

sudo systemctl start bluetoothsudo systemctl stop bluetooth

 

此外,你還可以讓藍牙服務隨系統啟動:

sudo systemctl enable bluetooth

 

了解樹莓派上的藍牙

在Raspbian中,基本的藍牙操作可以通過bluez中的bluetoothctl命令進行。該命令運行后,將進入到一個新的Shell。在這個shell中輸入:

 

list

 

將顯示樹莓派上可用的藍牙模塊,例如:

Controller B8:27:EB:72:47:5E raspberrypi [default]

 

運行scan命令,開啟掃描:

scan on

掃描啟動后,用devices命令,可以打印掃描到藍牙設備的MAC地址和名稱,例如:

Device 00:9E:C8:62:AF:55 MiBOX3
Device 4D:CE:7A:1D:B8:6A vamei

此外,你還可以用help命令獲得幫助。使用結束后,你可以用exit命令推出bluetoothctl。

 

 

除了bluetoothctl,在Raspbian是shell中可以通過hciconfig來控制藍牙模塊。比如開關藍牙模塊:

sudo hciconfig hci0 up   #啟動hci設備
sudo hciconfig hci0 down #關閉hci設備

命令中的hci0指的是0號HCI設備,即樹莓派的藍牙適配器。 

 

與此同時,你可以用下面命令來查看藍牙設備的工作日志: 

hcidump

bluez本身還提供了連接和讀寫工具。但不同版本的bluez相關功能的差異比較大,而且使用起來不太方便,所以我下面使用Node.js的工具來實現相關功能。

 

樹莓派作為BLE外設 

下一步,我們嘗試用樹莓派進行BLE通信。我們先把一個樹莓派改造成BLE外設,同時它也將充當連接建立后的服務器。這個過程較為復雜。你可以借用Node.js下的bleno庫。首先,安裝Node.js: 

curl -sL https://deb.nodesource.com/setup_5.x | sudo bash -
sudo apt-get install nodejs

第一行的命令是為了確保安裝高版本的Node.js。

 

安裝bleno: 

mkdir ble-test-peripheral
cd ble-test-peripheral
npm install bleno

 

運行pizza的例子: 

sudo node node_modules/bleno/examples/pizza/peripheral

你可以在node_modules/bleno/examples/pizza/看到源代碼,或者到github查看。這個例子提供了一個Service,它的UUID是1333-3333-3333-3333-3333-333333333337。Service中包含了三個Characteristics,分別是用于披薩餅參數、配料參數和烤披薩:

功能權限UUID
披薩餅選項讀/寫13333333333333333333333333330001
配料讀/寫13333333333333333333333333330002
烤披薩寫/通知13333333333333333333333333330003

 

通過這些Characteristic,我們可以對樹莓派進行BLE讀寫。讀寫操作會作用于一個代表比薩的對象。披薩餅選項有:

數值描述
0x00正常
0x01
0x02

 

配料是一個8位的參數,每一位代表了一種配料。當這一位是1時,那么說明添加該配料:

第n位76543210
描述SAUSAGEBELL_PEPPERSPINEAPPLECANADIAN_BACONBLACK_OLIVESEXTRA_CHEESEMUSHROOMSPEPPERONI

 

因此,0x1A代表了添加MUSHROOMS、BLACK_OLIVES、CANADIAN_BACON,感覺味道還不錯。

 

對于烤披薩來說,寫操作設定了烘烤的溫度和時間。時間到了之后,中心設備會發出通知,告訴客戶端烘烤完成。我們下一步將用另一個樹莓派作為BLE中心設備。不過,即使你沒有額外的樹莓派,你可以用iPhone上LightBlue這樣的App來測試這一部分完成的BLE外設。

 

樹莓派作為BLE中心設備

我們拿另一個作為BLE的中心設備進行掃描,并發起連接請求。連接建立后,該服務器將充當客戶。和bleno對應,Node.js下有一個叫noble的項目,可以便捷地完成這一任務。首先,安裝noble:

mkdir ble-test-central
cd ble-test-central
npm install noble

  

noble中有一個同樣名為pizza的例子,不過這個例子實現的是客戶端。運行該例子:

sudo node node_modules/noble/examples/pizza/peripheral

這個例子將自動執行掃描、連接、服務發現、數據傳輸的全過程。如果你把bleno和noble部署到兩個樹莓派上,就可以在這兩個樹莓派之間進行藍牙通信了。如果你想自定義開發,那么可以在node_modules/noble/examples/pizza/參考源代碼,或者到github查看。

 

樹莓派作為Beacon

蘋果在BLE的基礎上推出了iBeacon協議。iBeacon使用了BLE的廣播部分,但不建立連接。一個遵守iBeacon協議的外設稱為Beacon。Beacon會廣播自己的身份信息和發射信號的強度。中心設備接收到廣播之后,除了可以獲知Beacon的身份之外,還能通過信號的衰減算出自己與Beacon的距離。在一個典型的超市應用場景中,每件商品可以帶上一個Beacon。消費者可以用手機看到自己周圍有哪些商品,工作人員也可以用手機來清點貨物。商家還可以在服務器上提供商品相關的質保、促銷等信息。用戶可以根據Beacon的編號,獲得這些附加信息。

用樹莓派玩轉藍牙

 

我們把配備了藍牙模塊的樹莓派改造成一個Beacon。既然Beacon只使用了藍牙中的廣播,那么應該關閉樹莓派的掃描,打開廣播,并且不接受藍牙連接:

sudo hciconfig hci0 noscan    # 不再掃描sudo hciconfig hci0 leadv 3   # 開始廣播,并且不接受連接

 

下一步,把廣播信息改為符合iBeacon協議的內容:

sudo hcitool -i hci0 cmd 0x08 0x0008 1E 02 01 1A 1A FF 4C 00 02 15 63 6F 3F 8F 64 91 4B EE 95 F7 D8 CC 64 A8 63 B5 00 01 00 02 C5

上面的命令附加了一串16進制信息。其中0x08說明了整條信息是藍牙命令,0x0008說明后面的內容將作為廣播信息。

 

1E是廣播信息開始的標志。按照藍牙通信的規定,廣播信息最多有31個字節。1E后面的廣播信息分為兩組:

02 01 1A
1A FF 4C 00 02 15 63 6F 3F 8F 64 91 4B EE 95 F7 D8 CC 64 A8 63 B5 00 01 00 02 C5

每一組一開始的一個字節說明了該組信息的長度。02說明了2個字節,1A說明是26個字節。隨后一個字節說明了改組信息的類型。第一組的01說明了該組信息是藍牙控制標志,第二組的FF說明了該組是藍牙制造商相關信息。

 

我們來看第二組信息的細節:

  • 4C 00是制造商信息,即蘋果。

  • 02 15是iBeacon協議標識。

  • 63 6F 3F 8F 64 91 4B EE 95 F7 D8 CC 64 A8 63 B5部分是設備的UUID,通常是用戶編號。

  • UUID后面的00 01是主編號(Major)。

  • 再往后的00 02是次編號(Minor)。通過UUID、主編號、次編號的組合,我們可以唯一地確定iBeacon設備。

  • 最后的C5說明了藍牙信號強度,即在1米處測得的該Beacon的RSSI值。中心設備把接收到的信號強度和該信號強度對比,就可以知道信號衰減了多少,從而推算出自己與Beacon的距離。由于我這里寫入的C5沒有經過校準,所以距離測量很可能不準確。

 

在iPhone上安裝應用Locate Beacon來測試。當我進入到樹莓派的廣播范圍時,該應用就會顯示出手機距離樹莓派的距離。

用樹莓派玩轉藍牙

 

使用結束后,可以用下面命令來恢復掃描和停止廣播:

sudo hciconfig hci0 piscan   # 恢復掃描sudo hciconfig hci0 noleadv  # 停止廣播

 

總結

這里簡單介紹了藍牙協議,特別是低功耗藍牙。我以樹莓派的藍牙模塊為基礎,實現了BLE通信。

 

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

浦江县| 特克斯县| 安康市| 遂川县| 沙坪坝区| 垦利县| 当涂县| 桓仁| 广南县| 句容市| 新闻| 烟台市| 深水埗区| 陆河县| 新平| 马鞍山市| 三穗县| 西乌| 乌鲁木齐县| 夏津县| 陆良县| 牙克石市| 长泰县| 长兴县| 博爱县| 孟州市| 和平县| 海丰县| 永吉县| 凌海市| 平遥县| 开原市| 德江县| 临澧县| 武城县| 九江县| 吴忠市| 嘉善县| 鲁甸县| 广平县| 仁寿县|