2020年1月31日 星期五

開發你的第一個BLE應用程序

cnblogs.com

開發你的第一個BLE應用程序—Blinky - iini - 博客園

iini 關注 - 0 粉絲 - 93 +加關注

本文將基於Nordic nRF5 SDK開發我們的第一個BLE應用程序——Blinky(類似跑馬燈小程序),哪怕你之前沒有任何BLE開發經驗,也不用擔心,只要跟著文中所述步驟,你就可以一步步搭建自己的第一個BLE應用程序。通過這個Blinky程序的搭建,你將體會到BLE的一些基本概念,對BLE將會有一個非常直觀的認識,為後續自己的BLE應用程序開發打下一個堅實的基礎。
如果你已經有一些BLE應用開發經驗,只是對Nordic產品開發不熟,那麼建議你可以直接去閱讀下一篇文章:手把手教你開發BLE數據透傳應用程序
下文所述的代碼工程我已經將其上傳到百度雲盤中,有需要的同學可以到如下鏈接下載:

1. 開發準備

1)      nRF52或者nRF51開發板1塊。請參考「Nordic nRF51/nRF52開發流程說明」,購買相應開發板(DK)。
2)      開發環境搭建。簡述如下(詳細說明請參考「Nordic nRF51/nRF52開發環境搭建」):
  1. 安裝Keil5 MDK
  2. 安裝SDK。SDK下載鏈接:https://www.nordicsemi.com/Software-and-Tools/Software/nRF5-SDK/Download#infotabs。如果你開發的是nRF52系列,請選擇最新版SDK(當前是SDK15.3.0);如果你開發的是nRF51系列,請下載nRF5 SDK12.3.0(nRF51最高SDK版本只能到12.3.0,後續SDK就不再支持nRF51
  3. 安裝ARM CMSIS4.5.0,下載鏈接:https://github.com/ARM-software/CMSIS/releases/download/v4.5.0/ARM.CMSIS.4.5.0.pack
  4. 安裝Keil5 Device Family Pack,下載鏈接:https://www.nordicsemi.com/Software-and-Tools/Development-Tools/nRF-MDK/Download#infotabs,請選擇「Pack,3-clause BSD license」
  5. 安裝nRF5 Command Line Tools,下載鏈接(Windows版):https://www.nordicsemi.com/Software-and-Tools/Development-Tools/nRF5-Command-Line-Tools/Download#infotabs
  6. 安裝安卓版或者iOS版nRF connect。iOS版nRF connect請到蘋果app store下載,搜索「nRF」即可以找到。安卓版nRF connect可以到Nordic Github官網上下載,下載鏈接為:https://github.com/NordicSemiconductor/Android-nRF-Connect/releases
  7. 安裝PC版nRF connect或者nRFgo studio。PC版nRF connect下載鏈接(Windows版):https://www.nordicsemi.com/Software-and-Tools/Development-Tools/nRF-Connect-for-desktop/Download#infotabs
註:如果你使用的是Linux系統/Mac系統,或者你使用的不是Keil5-MDK,請參考「Nordic nRF51/nRF52開發環境搭建」來搭建你的開發環境。

2. 運行Blinky程序

請按照如下步驟運行SDK自帶的Blinky程序
1)      確認自己的芯片型號或者開發板。如果採用Nordic官方開發板的話,芯片型號和開發板編號對應關係如下:
  • nRF52832和nRF52810對應開發板編號為PCA10040。雖然52832和52810共用同一塊開發板,但是他們在SDK中的項目編號是不一樣的,52832對應PCA10040目錄,52810對應PCA10040e目錄,由於52810和52832 PIN to PIN兼容,軟件也是完全兼容的,因此SDK很多項目只有PCA10040的目錄,而沒有PCA10040e目錄,此時需要你自己來建立PCA10040e對應的目錄和工程,具體說明可參考:https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v15.3.0%2Fnrf52810_user_guide.html
  • nRF52840和nRF52811對應開發板編號為PCA10056。雖然52840和52811共用同一塊開發板,但是他們在SDK中的項目編號是不一樣的,52840對應PCA10056目錄,52811對應PCA10056e目錄,由於52811和52840 PIN to PIN兼容,軟件也是完全兼容的,因此SDK很多項目只有PCA10056的目錄,而沒有PCA10056e目錄,此時需要你自己來建立PCA10056e對應的目錄和工程,具體說明可參考:https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v15.3.0%2Fnrf52811_user_guide.html&cp=5_1_5_1
  • nRF52840 dongle編號為PCA10059
  • nRF51系列對應開發板編號為PCA10028
這裡我會以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程序。
  • 藍牙協議棧下載(整個開發週期只下載一次)。在Keil 『select target'下拉列表中,默認選擇的是Keil工程對應的Target,即『nrf52832_xxaa'。但我們還可以選擇另一個target 『flash_s132_nrf52_6.1.1_softdevice',即softdevice對應的target,然後點擊「下載download」(不需要編譯哦!),此時會把softdevice下載到開發板中。
 
  • 應用下載。重新選擇Target:『nrf52832_xxaa',點擊「下載Download」,此時會把Blinky程序下載到開發板中。此時開發板的LED1常亮,表示程序運行正常。
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又將熄滅。
 

3. 修改Blinky程序

3.1 修改廣播名稱

如前所述,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的搜索功能非常好用,很多問題都可以通過它來解決

3.2 修改廣播間隔

如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了:
 

3.3 修改Button characteristic行為 (設備發數據給手機)

現在的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(&params, 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, &params);

}
我們可以仿照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(&params, 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, &params);      

}
重新編譯下載blinky程序,連接設備,使能cccd,按下Button2,你會看到Button characteristic的值變為5:
 

3.4 修改LED characteristic行為(手機發數據給設備)

由於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\
即可成功編譯。

4. 開發手機端Blinky程序

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等,以幫助大家深刻理解這些概念,感興趣的讀者請參考:

手把手教你開發BLE數據透傳應用程序


沒有留言: