藍牙設計問與答

1.    問:什麼是藍牙通信?

答:藍牙通訊最初設計初衷是方便移動電話(手機)與配件之間進行低成本、低功耗無線通信連接,現在已經成爲IEEE802.15標準,得到全球上萬家廠商支持。

 

2.    問:如果從事藍牙開發有沒有前途?

答:嚴格地說,這不是一個技術問題,而是一個世界觀問題。什麼是前途?如果單純是金錢,從事技術是不太可能暴富的(注意比爾.蓋茨是個技術商人);如果想用你所能改善世界,這是可能的,畢竟藍牙的主要用途是民用。附帶說一句,考慮賺錢和改變世界是中國和西方人世界觀的主要差別。

 

3.    問:藍牙有什麼優勢?

答:首先是低功耗,以BLE 4.0爲例,一節鈕釦電池在靜態工作狀態可以支持一年;其次是低成本,TI公司的CC2540藍牙SOC方案芯片出售價僅1美元,可以讓人們低廉使用藍牙技術;再次是開放性,2.4GHz的頻段全球開放,沒有政府監管;最後是適合時代潮流,現在是手機的時代,藍牙技術本來就爲它而生。

 

4.    問:藍牙4.0協議和BLE是什麼?

答:藍牙4.0協議是2010年6月由SIG(Special Interest Group)發佈的最新標準,它有2種模式:BLE(Bluetooth low energy)只能與4.0協議設備通信,適應節能且僅收發少量數據的設備(如家用電子);BR/EDR(Basic Rate / Enhanced Data Rate),向下兼容(能與3.0/2.1/2.0通信),適應收發數據較多的設備(如耳機)。

 

5.    問:目前支持藍牙4.0的移動設備有哪些?

答:蘋果公司的iPhone 4S、iPhone 5、miniPad和iPad 3;小米手機2;三星公司的Galaxy SIII和Note II;HTC ONE系列。

 

6.    問:如何開始藍牙4.0的開發呢?

答:概括地講至少以下三方面的準備吧。硬件方面,需要購買TI公司藍牙迷你套件,包括藍牙USB電子狗和KeyFob以及CC Debugger傳真器;軟件方面,安裝IAR for 8051,TI公司BTool軟件;技術知識,《CC2540/41 BLE Software Developer’s Guide 1.3》和《CC2540/41 User’s Guide》。

 

7.    問:剛開始接觸藍牙如何快速上手?

答:理論聯繫實踐是比較好的學習方法,建議先學習《CC2540/41 BLE Software Developer’s Guide 1.3》,然後將SimpleBLEPerepheral工程導入IAR for 8051,結合電子狗和BTool,調試藍牙通訊中的廣播/連接/綁定/訪問。光看書不動手,空虛;不看書光動手,淺薄。

 

8.    問:IAR調試CC2540時程序導入到了芯片的Flash中了嗎?

答:確實。CC2540是SOC(System On Chip)芯片,它的內核就是8051,它需要從ROM中取指令,從RAM中取數據來運行。仿真時,CC Debugger會把程序導入芯片Flash中,再執行仿真。

 

9.    問:當IAR調試中出現警告“缺少斷點,無法運行到main()”?

答:出現這個錯誤的原因是,IAR for 8051最多隻能設置3個斷點,如果設置過多,當程序下載後,將出現些調試警告。解決的方法很簡單,去掉一些斷點,再重新載入程序。

 

10. 問:爲什麼IAR調試時有很多變量無法查看它的值?

答:主要的原因是IAR編譯器設置了優化功能,函數中的自動變量以及一些靜態函數都被優化過了,所以沒有生成對應的調試信息,無法查看和設置斷點。解決的方法是關閉編譯器的優化功能,右鍵點擊工程的Options -> C/C++ Compiler -> Optimizations中的Level設置爲None。

 

11. 問:藍牙協議分層很多且比較複雜,該如何掌握呢?

答:藍牙協議從應用層到物理層一共分了8層,看上去比較複雜且API函數很多。首先不必要知道每一層的具體實現,掌握與應用緊密關聯GAP/GATT(或者GAP Role和GATT Profiles)層就可以滿足大部分設計需要;每一層的軟件都是通過OSAL來調用的,因此需要了解OSAL的基本原理:任務/事件/消息/定時器/動態分配內存;最後把藍牙通訊過程理解,將有助於開發。

 

12. 問:OSAL是一個操作系統嗎?

答:OSAL(Operating System Abstraction Layer)操作系統抽象層,它不是一個真正的操作系統(它沒有Context Switch上下文切換功能),但它巧妙地組織各任務,支持任務優先級,任務之間可以通過事件和消息來通信,爲任務提供軟定時器和動態內存分配。要避免的陷阱是,應用任務的單個函數運行時間不能太長(如操作大批量數據的Flash寫),否則它無法及時調度高優先級的LL(Link Layer)任務而導致藍牙通信中斷。

 

13. 問:藍牙節點是如何組成微微網的呢?

答:藍牙節點組網中,只能存在一個主節點(Central)和多個從節點(Peripheral),從節點是發出信號者,主節點是掃描且發起連接者。

 

14. 問:主節點和從節點通信的過程是怎樣的呢?

答:當從節點發出廣告信號(包括設備地址和設備名稱之類的附加信息);主節點收到此廣告信號後,向從節點發出掃描請求;當從節點回應掃描時,就完成了設備發現過程。

接着主節點向從節點發出連接請求(包括連接時隙、從節點待機次數、連接超時值),從節點回應連接,就完成了建立連接。

爲了安全起見,一些數據的訪問需要認證,它的完成是這樣的:一方(可以是主節點,也可以是從節點)向另一方索要6位數字的密碼,之後,兩個節點彼此交換安全密鑰用於加密和認證,此過程稱爲配對。

認證的過程比較繁瑣,BLE協議支持兩節點保存認證的安全密鑰(一般是非易失性存儲器中),以便於兩節點下次連接後快速認證,這就是綁定技術。

 

15. 問:藍牙通信中兩個節點如何交換數據?

答:這是藍牙通信中最讓初學者迷惑的地方。大部分通信,尤其是TCP/IP,交換數據的婚介是數據包,但藍牙通信中,工程師找不到數據包訪問方式,於是就產生疑問。其實藍牙最底層也是基於無線數據包交換,只是通過層層封裝,交付給工程師的API接口就變成了Client訪問Server的方式。

 

16. 問:Client和Server節點是如何定義呢?

答:通俗地說吧,Server(服務器)就是數據中心,Client(客戶端)就是訪問數據者。特別說明,它與主/從設備是獨立的概念:一個主設備既可以充當Server,又可以充當Client;從設備亦然。

 

17. 問:Server是如何提供數據呢?

答:Server首先將一個服務按“屬性/句柄/數值/描述”這種格式予以組織,然後調用API函數GATTServApp_RegisterService將服務數據進行註冊。舉個實例吧,設提供一個電池電量服務字節,它允許Client讀取,數據爲一個8比特無符號數(0~100%),它的組織如下:02 25 00 19 2A, 這5個數據(小端格式)分別是:0x02=只讀屬性,0x0025=句柄;0x2A19=服務UUID。

 

18. 問:不明白Server提供服務中的UUID?

答:UUID(Universal Unique Identifier)全球惟一標識符,本來是SIC組織分配給特定藍牙服務的標識,如分配0x2A25爲設備序列號的UUID,這樣任意藍牙設備都可以通過它得到另一個設備的序列號。

打個類比,它就像書名,如《現代操作系統》,所有人一看就知道它是計算機大師Andrew S. Tanenbaum寫的書。

 

19. 問:什麼是Server提供服務中的句柄呢?

答:句柄(Handle)就是服務數據在數據中心的地址,當所有的服務數據組織起來後,它總得有個先後順序,某個服務的位置就是它的句柄。還是上面的類比,如果想去圖書館借閱《現代操作系統》,需要查明該書在哪一層樓,哪個房間,這就是該書的Hanle。

 

20. 問:爲什麼Server提供的服務中有描述?

答:有些服務是有描述(Descriptor)的,它是用於Client配置該服務的功能(通知或者顯示)。像某人沒有借到《現代操作系統》該書(可能是被別人借光了),他(她)可以打個電話給圖書館工作人員,請求一旦該書可以借閱了給他一個通知,這個過程相當於配置該書的Descriptor。

 

21. 問:服務的屬性與描述有區別嗎?

答:有區別,服務的屬性是Server設置訪問權限。就像圖書館的工作人員可以設置《現代操作系統》僅能在閱覽室看不能外借(只讀),或者即可以看也可以外借(讀/寫)。

22. 問:Client如何訪問Server的服務呢?

答:大致分三類:讀取服務的值,需要知道服務的UUID或者Handle;寫服務的值,需要知道服務的Hanle;寫服務描述符,需要知道該Descriptor的Hanle。

 

23. 問:如何知道一個服務的Handle?

答:根據服務的UUID調用API函數GATT_ReadUsingCharUUID

協議棧會返回該服務的Handle。特別注意的是,一個服務的Descriptor的Handle總是該服務的Handle+1,如電池電量服務的Handle是0x0025,那麼它的Descriptor的Handle是0x0026。

 

24. 問:Server可以訪問Client嗎?

答:藍牙通信中,Server不能直接訪問(讀/寫)Client,但是可以通知(Notification)Client,通知的前提是Client通過寫Descriptor使能通知功能。例如,某Server發現電池電量已經低於安全閥值,它可以調用GATT_Notification通知所有已連接的Client,但是Client接收後如果處理是它自己的事情。

 

25. 問:如果得知電池容量?

答:任何使用電池供電的設備都必須精確監控電池容量,否則設備可以突然斷電而停止工作,它的基本原理是通過ADC(模數轉換器)計算電池電壓。以CC2540芯片用一鈕釦電池爲例,電池電壓從2.0v~3.0v,即電量的0%~100%;CC2540有一10比特的ADC,量程範圍爲0~511,參考電壓爲1.25v,最大測量電壓爲3.75v,以上信息可以得知:(v/3)/ 1.25 * 511 = adc,則2.0v=273adc,3.0v=409adc,根據下圖可以很容易得知ADC轉換爲電壓的公式:

Percentage / (X – 273) = 100 / 136 = 25 / 34,變換後爲:

Percentage = (X - 273) * 25 / 34,爲四捨五入提高計算精度則有:

Percentage = [(X - 273) * 25 + 33] / 34。

 

26. 問:藍牙發射信號功率調整會影響通信距離嗎?

答:會,以TI公司的CC2540爲例,它支持4種發射功率選擇:4dBm、0dBm、-6dBm和-23dBm,按無線電功率定義:LdBm=10lg(Pwr/1mW),以上4種分貝值換算成瓦特爲:2.51mW、1mW、0.251mW和0.005mW,有效通信距離分別爲:30米、10米、7米和3米。

 

27. 問:如何知道兩個藍牙通信節點之間的距離?

答:要知道藍牙通信節點(如手機和藍牙設備)之間的距離,最容易實現的方法是通過讀取接收RSSI(Received Signal Strength

Indication)值來計算。無線通訊中功率與距離的關係如下:

 其中A可以看作是信號傳輸1米遠時接收信號的功率,n是傳播因子(它受障礙,溫度和溼度等影響),r是節點之間的距離。當確定了常數A與n的值後,距離r就可以根據PR(dBm)計算出來。

 

28. 問:如何獲取藍牙節點的接收RSSI值?

答:具體的設備接收RSSI值的方法不一樣,以iPhone手機爲例,iOS提供API函數獲取RSSI值;TI公司的CC2540芯片的BLE協議棧中,首先將讀取RSSI值回調函數掛載到gapRolesRssiRead_t類型的指針下,建立連接後,主設備調用GAPCentralRole_StartRssi(),從設備調用

GAPRole_SetParameter(GAPROLE_RSSI_READ_RATE, ……)。這樣就可以定時讀取接收的RSSI值了。

 

29. 問:如何開展讀取RSSI值的實驗?

答:讀取RSSI值的實驗可以這樣搭建,主設備固定位置,向從設備發送信號,從設備LED光和Buzzer報警爲通信成功,逐次移動從設備,而獲取RSSI值隨物理距離之間的關係。下圖是筆者做實驗的數據:

Distance(m)

1

2

3

4

5

6

7

8

9

10

RSSI(dBm)

-47

-59

-73

-80

-80

-79

-85

-88

-86

-87

Loss(p)

0

0

9

11

27

2

50

32

22

49

實驗器材爲2塊CC2540芯片,主芯片發射功率爲4dBm(2.51mW),Loss是通信節點中失敗次數。

 

30. 問:如何將接收RSSI實驗數據得到距離計算公式呢?

答:最好的工具是EXCEL軟件,以上表中的實驗數據和EXCEL 2007爲例。首先選中Distance和RSSI兩行,點擊“插入->散列圖”,軟件會自動生成如下圖:

選取其中任意點,點右鍵,“添加趨勢線->對數”,將會出現下圖:

可見RSSI與距離的關係是比較符合指數函數,再點擊“顯示公式”

此時得到指數函數公式爲:y = -49.53 – 17.7 ln (x),再把自然對數換成10常用對數,則有:y = -49.53 – 40.71 lg (x)。通過以上幾步就輕鬆得到RSSI與距離之間的計算公式。

 

31問:針對RSSI採樣值選用什麼樣的濾波算法?

答:RSSI採樣值遵循以下特點:有個別的脈衝干擾引起極大值和極小值的出現,其他採樣數據值沿平均值分佈,比較適合的算法是:滑動防脈衝干擾平均濾波法。它的原理是,設有N個單位的隊列,用新的採樣值覆蓋舊的採樣值,去除隊列中最大值和最小值後,再計算隊列中採樣數據的平均值。用C語言描述如下:

static INT8S Filter(INT8S chVal)

{

    #define FIFO_NUM    10

 

    INT8S    chMinVal, chMaxVal, chTemp;

    INT16S    nCnt, nSum;  

 

    static INT8S    s_chIx = 0, s_chIsFull = FALSE;

    static INT8S    s_achBuf[FIFO_NUM];

 

    /* Save the NEW value, kick out the OLDest one */

    s_achBuf[s_chIx] = chVal;

    if (++s_chIx >= FIFO_NUM)

    {

        s_chIx = 0;    /* Wrap to 1th unit */

        s_chIsFull = TRUE;         

    }

 

    /* Number of sampled data less than N */

    if (!s_chIsFull)

    {

        nSum = 0;

        for (nCnt = 0; nCnt < s_chIx; ++nCnt)

        {

            nSum += s_achBuf[nCnt];

        }

     

        return (INT8S)(nSum / s_chIx);        

    }

 

    /* Get the SUM and Max. and Min. */

    chMaxVal = chMinVal = nSum = 0;   

    for (nCnt = 0; nCnt < FIFO_NUM; ++nCnt)

    {

        chTemp = s_achBuf[nCnt];

        nSum += chTemp;

 

        if (chTemp > chMaxVal)   

        {

            chMaxVal = chTemp;

        }

        else if (chTemp < chMinVal)

        {

            chMinVal = chTemp;

        }

    }

 

    /* Calculate the average */

    nSum -= (chMaxVal + chMinVal);   /* SUB Max. and Min. */

    nSum /= (FIFO_NUM - 2);    /* Get average */

 

    return (INT8S)nSum;

}

發佈了8 篇原創文章 · 獲贊 1 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章