介紹了藉助藍牙SPP服務實現手機和嵌入式設備通信的基本原理和實現流程。 ...
高飛狗: |
"常常的想,現在的你…" |
布魯托: |
"哈羅!高飛!心情不錯嘛!" |
高飛狗: |
"嗨!又遇到難題了,百思不得其解,頭昏眼花的,心情糟透了!" |
布魯托: |
"又在研究什麼高科技項目?" |
高飛狗: |
"根本算不上什麼高科技,我有一個PM2.5監測裝置,就是能夠測量與記錄環境溫度、濕度和顆粒物濃度的東東,受應用條件的限制,沒有配備顯示屏,為了能夠在現場對其進行配置、管理並獲取測量數據,想在這個裝置上連接一個藍牙模塊,然後藉助手機通過藍牙通信實現這些功能。" |
布魯托: |
"藍牙通信是很成熟的技術,應該不難解決。" |
高飛狗: |
"在手機上當然很容易就搜索到我的藍牙模塊併成功進行了配對,但是接下來如何開發一個App與PM2.5監測裝置通信,我是一頭霧水啊!" |
布魯托: |
"開發手機App,用Android Studio就可以。" |
高飛狗: |
"Android Studio開發出來的App無法在iOS上運行。再說,我只會C++語言,而Android Studio要用java語言開發。" |
布魯托: |
"我們不妨去找找黛絲博士,聽聽她有什麼高見。" |
高飛狗: |
"又去找她? 挺不好意思的。" |
布魯托: |
"黛絲博士是個熱心人,樂於助人,上次咱倆去求助,她一點架子都沒有,而且她對你的態度大為好轉,難道你沒瞧出來? 沒準人家天天盼著你去問問題呢!" |
高飛狗: |
"真的嗎?你看出來轉機來了?我還有機會?" |
布魯托: |
"咱們這就走吧!" |
高飛狗和布魯托再次來到黛絲家並按下了門鈴,"叮鈴鈴…叮鈴鈴…"。 |
|
黛絲: |
"誰呀? 啊哦!是你們兩位,快請進!" "快請坐,喝點咖啡還是綠茶?" |
高飛狗: |
"不用這麼客氣。黛絲,今天來又得麻煩你。" |
黛絲: |
"是什麼事呀?" |
高飛狗: |
"我想用C++開發一個手機App,通過藍牙通信管理我的PM2.5監測裝置,而且這個App必須在Android和iOS上都能運行。" |
黛絲: |
"這有什麼難的呀。" |
高飛狗: |
"我就是不知該如何下手,一點思路都沒有。" |
黛絲: |
"最近剛剛做了一個類似的項目,正好跟你們說說,對我來說也算溫習所學知識吧。" |
布魯托: |
"您太謙虛了!" |
黛絲: |
"咱們先說藍牙通信的原理,然後再說具體實現吧。" "藍牙通信和TCP/UDP的原理基本相同,幾乎如出一轍。參見下表。" |
通信特征 |
TCP/UDP通信 |
藍牙通信 |
通信模式 |
客戶端-伺服器模式 |
客戶端-伺服器模式 |
通信端點 |
TCP埠 |
服務 |
通信端點標識方法 |
TCP埠號,是16位二進位數 |
服務UUID,是128位二進位數 |
客戶端通信過程 |
創建客戶端Socket 連接伺服器 發送數據 接收數據 |
創建客戶端Socket 連接伺服器 發送數據 接收數據 |
黛絲: |
"看見了吧,與TCP/UDP相比,區別僅僅在於,藍牙用服務代替埠,用服務UUID代替埠號,且服務UUID較長。" "用手機App管理嵌入式設備,手機就是客戶端,嵌入式設備上的藍牙模塊就是伺服器。" |
高飛狗: |
"真的是一目瞭然!" |
黛絲: |
"TCP/UDP標准定義了一組固定的埠對應一組標準化服務。例如,TCP埠80用於Web服務;TCP埠21用於FTP服務。" "類似地,藍牙標準也定義了一組固定的服務UUID對應一組標準化服務。"參見下表: |
藍牙服務名稱 |
服務UUID |
Serial Port |
00001101-0000-1000-8000-00805F9B34FB |
LAN Access Using PPP |
00001102-0000-1000-8000-00805F9B34FB |
DialupNetworking |
00001103-0000-1000-8000-00805F9B34FB |
OBEXObjectPush |
00001105-0000-1000-8000-00805F9B34FB |
OBEXFileTransfer |
00001106-0000-1000-8000-00805F9B34FB |
Cordless Telephony |
00001109-0000-1000-8000-00805F9B34FB |
Audio Source |
0000110A-0000-1000-8000-00805F9B34FB |
黛絲: |
"由於藍牙服務UUID太長,就用16進位數表達,遵循8-4-4-4-12的方法表示。" "藍牙通信與TCP/UDP通信的關鍵不同在於,藍牙伺服器都有一個SDP服務,也就是服務發現服務,供客戶端查詢藍牙伺服器能夠提供哪些服務。" "通常,用於嵌入式設備的藍牙模塊都提供Serial Port服務,簡稱SPP,然後提供一個UART連接嵌入式設備",如下圖所示。 |
黛絲: |
"由此,手機App與嵌入式設備通信的基本流程如下(假設藍牙模塊已經與手機配對完畢): 步驟1:選擇要進行通信的藍牙模塊 步驟2:查詢藍牙模塊的服務。通常已配對的藍牙設備的服務列表已緩存在手機里。 步驟3:如果存在SPP服務,恭喜你! 步驟4:用SPP服務UUID創建一個客戶端Socket。 步驟5:用客戶端Socket連接藍牙模塊。 步驟6:調用客戶端Socket的SendData()發送數據給藍牙模塊,藍牙模塊會將收到的數據通過UART轉發給嵌入式設備。 步驟7:如果嵌入式設備發送數據給藍牙模塊,藍牙模塊會轉發給手機,手機會緩存這些數據,App可調用客戶端Socket的ReceiveData()接收數據。" |
黛絲: |
"藍牙通信的原理就是這樣的。" |
高飛狗: |
"黛絲,你講得太明白了,今晚我一定要好好請請你、親親你! |
黛絲: |
"你就知道邪思歪想!" |
高飛狗: |
"那具體如何實現呢?" |
黛絲: |
"具體實現方法也很簡單。我們只要選擇Rad Studio作為開發工具,用C++編寫一套源代碼就可以生成適用於Android和iOS上運行的App,是不是很酷?" "有關Rad Studio就不在此累述,GUI界面的設計也很簡單,我們聚焦如何通過藍牙進行數據收發。" |
藉助藍牙SPP服務,實現手機與嵌入式設備之間的通信 |
註1:本文旨在明晰藍牙通信原理,僅列出扼要代碼,如需完整代碼,可聯繫本人。 註2:確保已開啟手機藍牙 註3:確保藍牙模塊已在手機的已配對設備列表中。 |
// 取得並保存藍牙管理器對象 TBluetoothManager *BtManager = TBluetoothManager::Current;
// 取得並保存藍牙適配器對象 BtAdapter = BtManager ->CurrentAdapter;
// 取得已配對的藍牙設備列表 TBluetoothDeviceList *PairedDevices = BtManager ->GetPairedDevices();
// 將藍牙設備列表顯示在組合框cbPairedDevices中(代碼略)
// 獲取組合框中被選中的藍牙設備對象 TBluetoothDevice * SelDevice = PairedDevices ->Items[cbPairedDevices->ItemIndex];
// 獲取該藍牙設備的服務列表 TBluetoothServiceList * ListServices = SelDevice->GetServices();
// 在服務列表中查詢是否支持SPP服務(代碼略)
// 若支持SPP服務
// 用SPP服務UUID創建一個客戶端Socket。 TBluetoothSocket *BtSocket = SelDevice ->CreateClientSocket(StringToGUID(SPP_GUI), false);
// 用客戶端Socket連接藍牙模塊。 BtSocket ->Connect();
// 調用客戶端Socket的SendData()發送數據給藍牙模塊,藍牙模塊會將收到的數據通過UART轉發給嵌入式設備。 BtSocket ->SendData(DataArray); // DataArray是一個數組
// 如果嵌入式設備發送數據給藍牙模塊,藍牙模塊會轉發給手機,手機會緩存這些數據,App可調用客戶端Socket的ReceiveData()接收數據。" BtSocket->ReceiveData(50); // 接收數據,限時等待50ms |
黛絲: |
"以上就是手機App與藍牙模塊間收發數據的基本流程及其實現。" |
高飛狗: |
"黛絲,你講得太深入淺出了!啊哦,快到飯點了,我請你吃個便飯,聊表謝意!" |
黛絲: |
"已經有人約我吃飯了,你們就趕緊回去試驗,有什麼問題隨時Call我。" |