本文將基於Nordic nRF5 SDK開發咱們的第一個BLE應用程序——Blinky(相似跑馬燈小程序),哪怕你以前沒有任何BLE開發經驗,也不用擔憂,只要跟着文中所述步驟,你就能夠一步步搭建本身的第一個BLE應用程序。經過這個Blinky程序的搭建,你將體會到BLE的一些基本概念,對BLE將會有一個很是直觀的認識,爲後續本身的BLE應用程序開發打下一個堅實的基礎。html
若是你已經有一些BLE應用開發經驗,只是對Nordic產品開發不熟,那麼建議你能夠直接去閱讀下一篇文章:手把手教你開發BLE數據透傳應用程序git
下文所述的代碼工程我已經將其上傳到百度雲盤中,有須要的同窗能夠到以下連接下載:github
1) nRF52或者nRF51開發板1塊。請參考「Nordic nRF51/nRF52開發流程說明」,購買相應開發板(DK)。小程序
2) 開發環境搭建。簡述以下(詳細說明請參考「Nordic nRF51/nRF52開發環境搭建」):app
注:若是你使用的是Linux系統/Mac系統,或者你使用的不是Keil5-MDK,請參考「Nordic nRF51/nRF52開發環境搭建」來搭建你的開發環境。jsp
請按照以下步驟運行SDK自帶的Blinky程序ide
1) 確認本身的芯片型號或者開發板。若是採用Nordic官方開發板的話,芯片型號和開發板編號對應關係以下:函數
這裏我會以nRF52832開發板PCA10040爲例闡述整個開發過程,其餘開發板與之相似,你們本身能夠觸類旁通來開始本身的開發之旅。工具
2) 將開發板與PC機經過USB線相連,同時打開開發板電源(將左下角的撥位開關打到「ON」位置),打開桌面版nRF Connect,選擇啓動「Programmer」應用,因爲驅動以前已經安裝好了,設備能夠當即識別成功。執行「Erase all」操做,以擦除芯片原始內容。測試
3) 打開SDK中的Blinky程序。對於blinky程序,若是是52832開發板,請打開:nRF5_SDK_15.3.0_59ac345\examples\ble_peripheral\ble_app_blinky\pca10040\s132\arm5_no_packs;若是是51822開發板,請打開:nRF5_SDK_12.3.0_d7731ad\examples\ble_peripheral\experimental_ble_app_blinky\pca10028\s130\arm5_no_packs
後續將以52832開發板爲例來闡述,51822與之相似就再也不闡述了。
注:Nordic SDK例程目錄結構爲:SDK版本/ examples /協議角色/例子名稱/開發板型號/協議棧型號/工具鏈類型/具體工程,好比下面例子:
Nordic每個例子都支持5種工具鏈:Keil5/Keil4/IAR/GCC/SES,以下所示:
4) 編譯上面的blinky程序。若是你已經按照以前的說明配置好了開發環境,那麼這裏編譯是不會報任何錯的。(若是你遇到了編譯錯誤,請從新按照前面說明去搭建你的開發環境,不要懷疑SDK例子代碼有問題哦)
5) 程序下載。程序下載包括2步:先下載softdevice,再下載應用。Softdevice是Nordic藍牙協議棧的名稱,整個開發過程當中只需下載一次。應用就是咱們這裏的blinky程序。
6) 打開手機藍牙和手機版nRF connect。在nRF connect中,你將看到一個廣播設備:Nordic_Blinky,這個就是咱們的開發板。
7) 鏈接設備。點擊「CONNECT」,手機將與設備創建鏈接,並開始服務發現過程,鏈接成功後,LED1熄滅,LED2點亮,最後將獲得以下界面。
由上圖可見,Blinky程序包含三個service:Generic Access(GAP),Generic Attribute(GATT),以及Nordic LED Button Service,GAP和GATT都是標準的藍牙service,Nordic LED Button Service是Blinky程序自定義的service,它又具體包括兩個characteristic:Button和LED。
8) 測試Blinky程序。點擊右上角的「Enable CCCDs」以使能notification,以下:
按下開發板上的Button1按鍵,你會發現nRF connect中的Button characteristic Value會實時顯示按鍵狀態:pressed或者released。
點擊nRF connect中的LED characteristic右邊的向上箭頭,選擇「ON」並「SEND」,你會發現開發板的LED3將點亮;選擇「OFF」並「SEND」,LED3又將熄滅。
如前所述,Blinky程序默認的廣播名字是:Nordic_Blinky,咱們如今將其修改成「My_Blinky」,怎麼作呢?咱們在Keil中全文搜索「Nordic_Blinky」,發現有以下宏定義:
#define DEVICE_NAME "Nordic_Blinky"
咱們只需將這裏的Nordic_Blinky換成My_Blinky,即
#define DEVICE_NAME "My_Blinky"
就能夠實現咱們的目標了。從新編譯下載blinky程序,在nRF connect中,你將看到:
你再全文搜索一下「DEVICE_NAME」,你會發現廣播名字實際上是經過以下API來完成修改的:
err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)DEVICE_NAME, strlen(DEVICE_NAME));
注:Keil的搜索功能很是好用,不少問題均可以經過它來解決
如nRF connect界面所示,blinky程序的廣播間隔大概爲40ms左右,如今爲了節省功耗,咱們將其改成200ms,經過搜索,咱們能夠看到以下宏定義:
#define APP_ADV_INTERVAL 64 /**< The advertising interval (in units of 0.625 ms; this value corresponds to 40 ms). */
所以爲了將廣播間隔改成200ms,只需將APP_ADV_INTERVAL改爲200/0.625 = 320,即
#define APP_ADV_INTERVAL 320
從新編譯下載blinky程序,在nRF connect中,你將發現廣播間隔已改成200ms了:
如今的Blinky程序,只有按下開發板的Button1時,nRF connect的Button characteristic 值纔會更新。咱們如今新增一個功能:當按下開發板的Button 2時,讓Button characteristic value更新爲5(注: nRF connect把1當成按鍵按下,把0當成按鍵釋放,爲了更直觀,咱們沒有選擇0或者1,而是隨便選擇一個值:5)。咱們先找到Button1按下的回調函數,以下所示:
case LEDBUTTON_BUTTON: NRF_LOG_INFO("Send button state change."); err_code = ble_lbs_on_button_change(m_conn_handle, &m_lbs, button_action); if (err_code != NRF_SUCCESS && err_code != BLE_ERROR_INVALID_CONN_HANDLE && err_code != NRF_ERROR_INVALID_STATE && err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING) { APP_ERROR_CHECK(err_code); } break;
能夠看出,咱們是經過ble_lbs_on_button_change來更新Button characteristic的值的,ble_lbs_on_button_change具體函數實現以下所示:
uint32_t ble_lbs_on_button_change(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t button_state) { ble_gatts_hvx_params_t params; uint16_t len = sizeof(button_state); memset(¶ms, 0, sizeof(params)); params.type = BLE_GATT_HVX_NOTIFICATION; params.handle = p_lbs->button_char_handles.value_handle; params.p_data = &button_state; params.p_len = &len; return sd_ble_gatts_hvx(conn_handle, ¶ms); }
咱們能夠仿照Button1的作法,來添加Button2的代碼。首先初始化app_button模塊,讓button2按下事件能夠被button_event_handler捕獲,以下:
static app_button_cfg_t buttons[] = { {LEDBUTTON_BUTTON, false, BUTTON_PULL, button_event_handler}, {BSP_BUTTON_1, false, BUTTON_PULL, button_event_handler} };
而後在button_event_handler調用ble_button2_send(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t val),以更新Button characteristic的值,代碼以下所示:
case BSP_BUTTON_1: NRF_LOG_INFO("Button2 pressed."); ble_button2_send(m_conn_handle, &m_lbs, 5); break;
ble_button2_send(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t val)實現代碼以下所示:
uint32_t ble_button2_send(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t val) { ble_gatts_hvx_params_t params; uint16_t len = sizeof(val); memset(¶ms, 0, sizeof(params)); params.type = BLE_GATT_HVX_NOTIFICATION; params.handle = p_lbs->button_char_handles.value_handle; //Button characteristic value handle params.p_data = &val; params.p_len = &len; return sd_ble_gatts_hvx(conn_handle, ¶ms); }
從新編譯下載blinky程序,鏈接設備,使能cccd,按下Button2,你會看到Button characteristic的值變爲5:
因爲nRF connect把LED characteristic的值寫死了,只能發送「ON」或者「OFF」,前面也測試過,發送「ON」以後,LED3將點亮,其實這裏的「ON」,就是數值1。咱們如今增長一個新的功能:在收到「ON」命令後,把LED4 toggle一下。
這個實現起來比較簡單,咱們只需在led_write_handler中添加bsp_board_led_invert(BSP_BOARD_LED_3),總體代碼以下所示:
static void led_write_handler(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t led_state) { if (led_state) { bsp_board_led_on(LEDBUTTON_LED); NRF_LOG_INFO("Received LED ON!"); bsp_board_led_invert(BSP_BOARD_LED_3); } else { bsp_board_led_off(LEDBUTTON_LED); NRF_LOG_INFO("Received LED OFF!"); } }
從新編譯下載blinky程序,鏈接設備,你會發現第一次發送「ON」,LED4點亮,第二次發送「ON」,LED4又將熄滅。
經過全文搜索「led_write_handler」,你會發現這個函數是被ble_lbs.c中的on_write調用,而on_write又被ble_lbs_on_ble_evt調用,而ble_lbs_on_ble_evt就是咱們的BLE事件回調函數,每當softdevice收到LED characteristic的寫操做時,都會調用它,這就是經過nRF connect操做設備的過程和原理。
上述代碼工程我已經將其上傳到百度雲盤中,有須要的同窗能夠到以下連接下載:
下載「tutorial_ble_app_blinky_SDK15_3_0.rar」,而後解壓縮到SDK15.3.0以下目錄下:nRF5_SDK_15.3.0_59ac345\examples\ble_peripheral\
便可成功編譯。
Nordic同時提供手機端的Blinky程序,該程序源代碼徹底向用戶開放,以幫助用戶快速開發本身的第一個Android或者iOS BLE應用程序。用戶能夠先到app store下載iOS版nRF blinky,或者到Github下載Android版nRF blinky(下載連接:https://github.com/NordicSemiconductor/Android-nRF-Blinky/releases)。手機版的nRF Blinky跟前面介紹的Blinky固件是配合工做的,經過手機版nRF Blinky能夠對前面的blinky固件進行操做。nRF Blinky app圖標以下所示:
nRF Blinky操做界面以下所示:
這篇文章主要讓你們對BLE有個大概的認識,後面我會專門寫一篇文章來介紹上面提到的BLE service,characteristic,write,notify以及CCCD等,以幫助你們深入理解這些概念,感興趣的讀者請參考: