【nRF51822学习教程】SDK框架分析
而51822的SDK本質上只是提供了各種調用接口,比如開啟初始化協議棧,初始化一些硬件功能模塊,開始廣播,發起鏈接等等。這些接口怎么用完全取決于自己。不過一般固件開發都是一些類似的流程各種資源的初始化,51822也不例外。所以sdk中的作為從機的例子main函數都是類似如下的步驟:
以官方的串口BLE 為例:
[cpp]?view plaincopy
可以看到其實核心必要的只有這5個函數而已。你可以將其他代碼全都去掉,只要留下這5個函數設備一樣可以運行,手機也能搜到設備并與設備通信。
這種初始化的方式可以說是與我們一般的單片機開發沒有區別。
那么初始化之后呢。以前的裸板單片機開發我們就是進入一個while循環執行一些周而復始的事,后面為了降低功耗開始在while(1)循環中加個睡眠代碼讓沒有工作時芯片處于睡眠狀態,并依靠中斷來喚醒從而處理到來的事物。
而上面的51822的main函數最后也是一個for{}循環,power_manage(); 內部代碼其實就是一個睡眠指令。Main函數到這里就已經沒了,最后其實就是一個循環睡眠。這里看不到任何任務(task),只有睡眠。那么可想而知,51822的協議棧實現應該是基于”事件喚醒”的,也就是沒事的時候睡眠,有事的時候喚醒工作而后繼續睡眠。那么那些處理事件的代碼都是在哪里的?
那協議棧到底是怎么運作的?我希望創建一個服務在哪里添加?手機發送來的數據在哪里?我怎么發送數據給手機?
下面一一解釋這些問題:
協議棧如何運作?
要明白協議棧怎么運作,首先就要理解51822的協議棧是基于100%的事件驅動的。就是說協議棧向app發送的任何數據都是基于事件的。
比如設備收到手機發來的鏈接請求,或是手機發過來的數據等等。協議棧首先收到這些數據后做一些處理,然后將這些數據(比如鏈接請求,或是普通數據等)打包成一個結構體,并附上事件ID,比如BLE_GAP_EVT_CONNECTED或BLE_GATTS_EVT_WRITE來分別告訴上層app這個事件結構體代表的事件。
比如BLE_GAP_EVT_CONNECTED代表鏈接事件,那么這個事件結構體中包含的數據就是連接參數等數據。而BLE_GATTS_EVT_WRITE代表寫事件,那么結構體中的數據就是對端設備(比如手機)寫給板子的數據。
比如uart的demo中dispatch派發函數
[cpp]?view plaincopy
連接參數管理處理函數ble_conn_params_on_ble_evt
Uart服務的事件處理函數ble_nus_on_ble_evt (nus為Nordicuart server)
通用的事件處理函數on_ble_evt
不同的事件在事件結構體ble_evt_t中通過id來區別。不同是事件處理函數通常也只是處理自己感情去的事件,我們來看看ble_nus_on_ble_evt事件處理函數的內部
[cpp]?view plaincopy
可以看到,uart服務事件處理函數只關心三個事件,鏈接事件,斷開鏈接事件以及寫事件(對端設備發數據過來),不同的事件再針對做不同的,這個就由開發人員自己來實現了。比如對于連接事件通常應該記錄下事件結構體中的連接句柄,因為后續的BLE操作基本都要基于連接句柄(可以看做是兩個設備通信的信道ID,實際為鏈路層中的數據接入地址概念)。
PS: 事件是交給dispatch來派發給各個服務以及模塊的,對于更底層的事件又是如何交給dispatch函數的過程請參考群公告中的 51822教程-協議棧概述教程。
解決了所謂的事件驅動再來解決:如果希望創建一個服務在哪里添加?
在main函數的初始化過程中有一個services_init();這個函數的內部就是添加服務,添加特征值等代碼。
函數內部其實就是注冊了一會回調函數nus_data_handler(該函數會在手機發數據給板子時將數據從電腦串口打印出來) 然后再執行真正的初始化函數ble_nus_init。
該函數的內部又會調用sd_ble_gatts_service_add這個協議棧的api接口來添加服務。
后面也會調用sd_ble_gatts_characteristic_add這個協議棧的api接口來添加特征值。
層次關系如下:
也就是說完成一個完整的服務建立函數其實只要sd_ble_gatts_service_add()和sd_ble_gatts_characteristic_add ()這兩個核心函數。
通常建立服務并不需要自己去從頭寫過。而是直接賦值官方的這個services_init()函數,然后做一些小改動就可以。比如修改一下uuid, 修改一下讀/寫屬性,多添加一個特征值等。要修改的其實很少。
下面解決最后兩個問題:手機發送來的數據在哪里?我怎么發送數據給手機?
要搞清楚這兩個問題,先來看一下群里常問的幾個與上面相關的問題:
問:手機發給51822設備的數據在哪個函數里出來的?
答:
沒有函數
協議棧會拋上來一個事件結構體
收到的數據在結構體中
問:藍牙上傳函數,與下發函數都是一樣的嗎?都是服務API函數?
答:
只有上傳函數 是服務器用來將數據傳給客戶端的。
下發數據 是藍牙芯片收到數據后,協議棧會拋上來一個有數據的事件結 構體。具體參看示例代碼中的 dispatch派發程序中各個事件處理函數對各 種事件的數據。
問:sd_ble_gatts_hvx()這個函數是 藍牙的發送函數,有知道藍牙的接收函數 ?
答:
藍牙沒有接收函數,藍牙的數據接收在底層,接收完后會返回事件給上層的 ble_evt_dispatch 分發函數,它將事件分發給各個服務或者事件處理函數。 服 務或處理函數會捕獲是否存在寫事件case BLE_GATTS_EVT_WRITE: 存在就做 相應的處理。收到的數據都在返回的事件結構體里
其實看完這三個問題基本上上面的問題其實已經解決差不多了。作為從設備,BLE的發送數據給手機是有API接口的,就是上面問到的sd_ble_gatts_hvx(),可以通過參數來設置是以通知方式發送還是指示方式發送(通知不需要回復確認,指示需要)。但是手機發過來數據卻是沒有接收函數,為什么?因為協議棧是基于事件驅動的!所以收到數據后協議棧會給上層app一個寫事件(指示對端設備寫數據過來了),而寫過來的數據時在這個事件結構體中。我們只要提取出來就行了。所以沒有接收函數API。
總結
以上是生活随笔為你收集整理的【nRF51822学习教程】SDK框架分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 51822模拟ble广播-理论
- 下一篇: nRF51822 SDK初体验