天天看點

NRF51822學習筆記之主從通信講解,另外附加把UUID更改成藍牙技術聯盟的基本UUID

最近在搞藍牙主從通信這塊,公司裡面是有之前的代碼的,但是自己想在自己52832開發闆上弄一個主從通信。從機闆子是52832的,從機代碼采用官方的序列槽例程,主機是公司的51822闆子,主機代碼也是公司的,因為對這塊不熟悉,造成主從不能通信,最後請教老員工才知道,他們把藍牙服務的UUID更改成藍牙技術聯盟的基本UUID的問題,找到問題後,自己改了一下UUID類型,也就成功了,剛好趁這次機會,把UUID從128bit改成16bit的方式,也做個筆記,寫出來。本次運用的sdk依舊是SDK12.3版本。好了,先說簡單的更改UUID這塊。

1、UUID更改步驟以及注意事項

如果你是使用官方的标準128bitUUID,也就不需要經過這個步驟,但是,如果遇到需要更改的時候,可以參考一下。更改了UUID位數,要注意的是主從通信時候,主機會根據從機的主服務UUID名和類型,來和從機通信的,這點要注意。我們先說從機的更改,主機的更改放在主從通信這塊來講解。

步驟1:在從機序列槽服務初始化函數裡面,我們修改一下紅色地方

NRF51822學習筆記之主從通信講解,另外附加把UUID更改成藍牙技術聯盟的基本UUID

第一個地方,直接屏蔽掉,

第2的地方,我們要更改一下服務類型,為BLE_UUID_TYPE_BLE

第3,4,5,的地方,我們要更改一下主服務,RX,TX的UUID宏定義

NRF51822學習筆記之主從通信講解,另外附加把UUID更改成藍牙技術聯盟的基本UUID

第4,5函數裡面更改的地方是一樣的,貼出一個就行了

NRF51822學習筆記之主從通信講解,另外附加把UUID更改成藍牙技術聯盟的基本UUID

最後,我們更改的地方是廣播數組

NRF51822學習筆記之主從通信講解,另外附加把UUID更改成藍牙技術聯盟的基本UUID

更改完成以後,我們順便把廣播名更改了,因為此次例程是根據裝置名來尋找從機裝置的,主機尋找的裝置名要和從機的一樣。

NRF51822學習筆記之主從通信講解,另外附加把UUID更改成藍牙技術聯盟的基本UUID

更改好以後,下載下傳進開發闆裡面,我們可以看到廣播與以前 的不一樣的地方。

以前的是:

NRF51822學習筆記之主從通信講解,另外附加把UUID更改成藍牙技術聯盟的基本UUID

更改以後是;

NRF51822學習筆記之主從通信講解,另外附加把UUID更改成藍牙技術聯盟的基本UUID

到這裡,就已經完成了,下面我們開始講主從通信這塊。主從通信例程這塊,大家可以對照官網給的例程檢視,路徑為D:\nRF5_SDK_12.3.0_d7731ad\examples\ble_central_and_peripheral\experimental\ble_app_hrs_rscs_relay;我也是在這個例程上修改的。

1、修改宏定義,其實這個官網例程已經修改好了,也可以不必須修改。

NRF51822學習筆記之主從通信講解,另外附加把UUID更改成藍牙技術聯盟的基本UUID

可以看圖檔上的宏定義,CENTRAL_LINK_COUNT是作為主機時候,可以連接配接多少裝置,PERIPHERAL_LINK_COUNT是作為從機時候,可以連接配接多少裝置。此處均設為1。也就是說,作為從機時候,連接配接一個主裝置。作為主機時候,連接配接一個從機裝置。

2、向下可以到協定棧初始化,協定棧初始化沒什麼改變,主要是他的回調函數裡面,與之前不一樣。我們看一下

NRF51822學習筆記之主從通信講解,另外附加把UUID更改成藍牙技術聯盟的基本UUID

我們可以看出,作為從機時候,裡面的派發函數與之前官網的一樣,但是,我們是讓他作為主機,這裡我們不必過多檢視,主要看作為主機時候的三個派發函數:

1、static void on_ble_central_evt(const ble_evt_t * const p_ble_evt) //主機事假派發函數

2、void ble_db_discovery_on_ble_evt(ble_db_discovery_t * const p_db_discovery,

const ble_evt_t * const p_ble_evt) //資料發現事件派發函數

3、ble_nus_c_on_ble_evt(&central_to_perihterial, p_ble_evt) //主從通信事件派發函數

我們按照主機發現裝置—>連接配接裝置----->資料互動過程講解。

首先是發現裝置:在on_ble_central_evt()函數裡面會有報告BLE_GAP_EVT_ADV_REPORT,可以跳過去看一下這個代碼

case BLE_GAP_EVT_ADV_REPORT:
        {
					  //¼ìÑéÐźÅ
					 uint8_t rssi_val = p_ble_evt->evt.gap_evt.params.adv_report.rssi;
					{
						if(rssi_val>0xC9)
						{
               if (strlen(m_target_periph_name) != 0)
								{
										if (find_adv_name(&p_gap_evt->params.adv_report, m_target_periph_name))
										{
												// Initiate connection.
												err_code = sd_ble_gap_connect(&p_gap_evt->params.adv_report.peer_addr,
																											&m_scan_params,
																											&m_connection_param);
										  
											
												if (err_code != NRF_SUCCESS)
												{
														NRF_LOG_INFO("Connection Request Failed, reason %d\r\n", err_code);
												}
										}
								}
					  }
					}
//            else
//            {
//               /** We do not want to connect to two peripherals offering the same service, so when
//                *  a UUID is matched, we check that we are not already connected to a peer which
//                *  offers the same service. */
//                if ((find_adv_uuid(&p_gap_evt->params.adv_report, 0xA8A0)&&
//                     (m_conn_handle_nus_c == BLE_CONN_HANDLE_INVALID)))
//                {
//                    // Initiate connection.
//                    err_code = sd_ble_gap_connect(&p_gap_evt->params.adv_report.peer_addr,
//                                                  &m_scan_params,
//                                                  &m_connection_param);
//                    if (err_code != NRF_SUCCESS)
//                    {
//                        NRF_LOG_INFO("Connection Request Failed, reason %d\r\n", err_code);
//                    }
//                }
//            }
        } break; // BLE_GAP_ADV_REPORT
           

在這裡後面的通過UUID查找裝置我屏蔽掉了,用到按照裝置名尋找裝置,我們可以看一下函數find_adv_name();

NRF51822學習筆記之主從通信講解,另外附加把UUID更改成藍牙技術聯盟的基本UUID

我用RTT列印了一下發現裝置名的名稱。看到函數,我們可以發現就是擷取到裝置名以後,通過對比我們設定的需要連接配接的裝置名數組

static const char m_target_periph_name[] = “lvyapeng”;是否一樣,

如果一樣,就開始進行連接配接,如果不是,搜尋下一個。如果連接配接成功,就會觸發連接配接事件BLE_GAP_EVT_CONNECTED,還是在這個函數裡面,我們可以看一下。

NRF51822學習筆記之主從通信講解,另外附加把UUID更改成藍牙技術聯盟的基本UUID

首先判斷結構體m_conn_handle_nus_c是否等于BLE_CONN_HANDLE_INVALID,其中,我修改了地方是定義一個全局結構體

static uint16_t m_conn_handle_nus_c = BLE_CONN_HANDLE_INVALID;

官方之前定義了兩個,我給删除了,用了自己的,因為後面的主從通信要用到。建議最好用自己定義的,把官網定義的替換掉。

在這裡,我定義了一個bool類型的全局變量Send_cmd_flag,來判斷是否可以發送資料給從機。函數ble_db_discovery_start()是進行資料發現和連接配接的功能。因為這些地方都沒修改,是以簡單講解一下。後面的兩個函數ble_db_discovery_on_ble_evt()和ble_nus_c_on_ble_evt(),也是一樣沒有修改的地方,不做講解。

3、藍牙資料發現初始化

static void db_discovery_init(void)
{
    ret_code_t err_code = ble_db_discovery_init(db_disc_handler);
    APP_ERROR_CHECK(err_code);
}

           

這個沒什麼好說的,不過,我們要在他的回調裡面增加資料發現處理

static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
{
//    ble_rscs_on_db_disc_evt(&m_ble_rsc_c, p_evt);
//    ble_hrs_on_db_disc_evt(&m_ble_hrs_c, p_evt);
    ble_nus_c_on_db_disc_evt(&m_ble_nus_c, p_evt);

}
           

在void ble_nus_c_on_db_disc_evt(ble_nus_c_t * p_ble_nus_c, ble_db_discovery_evt_t * p_evt)函數裡面,我們要修改的地方在下面

NRF51822學習筆記之主從通信講解,另外附加把UUID更改成藍牙技術聯盟的基本UUID

因為這裡就是判斷哪個服務是自己要進行通信的,之前我們修改了從機的類型和服務UUID,是以這裡也要修改。

4、主機到從機資料流向。

nus_c_init();就是初始化主從資料通信這塊了,我們可以跳進去看一下

static void nus_c_init(void)
{
    uint32_t           err_code;
    ble_nus_c_init_t   nus_c_init_obj;

    nus_c_init_obj.evt_handler = ble_nus_c_evt_handler;

    err_code = ble_nus_c_init(&m_ble_nus_c, &nus_c_init_obj);
    APP_ERROR_CHECK(err_code);
}
           

這些就是主從通信資料互動的初始化,、因為從機修改了服務UUID和類型,這裡也要修改,具體如下

NRF51822學習筆記之主從通信講解,另外附加把UUID更改成藍牙技術聯盟的基本UUID

步驟和從機一樣,把服務類型和uuID修改了

NRF51822學習筆記之主從通信講解,另外附加把UUID更改成藍牙技術聯盟的基本UUID

簡單修改就行,這裡主要注意他的回調函數。

static void ble_nus_c_evt_handler(ble_nus_c_t * p_ble_nus_c, const ble_nus_c_evt_t * p_ble_nus_evt)

NRF51822學習筆記之主從通信講解,另外附加把UUID更改成藍牙技術聯盟的基本UUID

兩者進行資料互動的時候,首先是觸發資料發現事件BLE_NUS_C_EVT_DISCOVERY_COMPLETE

如果需要從機發送資料給主機,就使能rx_notify。使能以後,就可接收資料,觸發BLE_NUS_C_EVT_NUS_RX_EVT事件,這裡我隻是列印一個資料就行了。

這兩個函數,ble_nus_c_handles_assign是獲得校驗從機服務參數的

ble_nus_c_rx_notif_enable是發現有RX通知特性,就打開RX使能,進行資料接收。

4、當主從連接配接好以後,就可以使用發送函數ble_nus_c_string_send(),我在測試過程中,發現雖然我的标志位Send_cmd_flag置1,主循環判斷标志位,然後發送,但是會出現發送失敗現象,經過測試,發現需要在連接配接成功以後,延時一段時間在發送才行,我是延時1s在發送資料的。

uint32_t ble_nus_c_string_send(ble_nus_c_t * p_ble_nus_c, uint8_t * p_string, uint16_t length)
           

發送資料。

5、主機開始掃描

static void adv_scan_start(void)
{
    ret_code_t err_code;
    uint32_t count;
    //check if there are no flash operations in progress
    printf"scan_start%02x\r\n",count);
    if (count == 0)
    {
        scan_start();
        err_code = ble_advertising_start(BLE_ADV_MODE_FAST);
        APP_ERROR_CHECK(err_code);
    }
}
           

在這裡面,主要是開始掃描和廣播開始,我們關注掃描函數

static void scan_start(void)
{
    ret_code_t err_code;

    (void) sd_ble_gap_scan_stop();

    err_code = sd_ble_gap_scan_start(&m_scan_params);
    // It is okay to ignore this error since we are stopping the scan anyway.
    if (err_code != NRF_ERROR_INVALID_STATE)
    {
        APP_ERROR_CHECK(err_code);
    }
}
           

這個函數裡面有一個結構體

static const ble_gap_scan_params_t m_scan_params =
{
    .active   = 1,
    .interval = SCAN_INTERVAL,
    .window   = SCAN_WINDOW,
    .timeout  = SCAN_TIMEOUT,
    #if (NRF_SD_BLE_API_VERSION == 2)
        .selective   = 0,
        .p_whitelist = NULL,
    #endif
    #if (NRF_SD_BLE_API_VERSION == 3)
        .use_whitelist = 0,
    #endif
};
           

我在這裡就不細說了,直接截屏網上的一段資料給大家

NRF51822學習筆記之主從通信講解,另外附加把UUID更改成藍牙技術聯盟的基本UUID

6、發送函數,是定義一個軟體定時,10ms觸發一次回調函數

NRF51822學習筆記之主從通信講解,另外附加把UUID更改成藍牙技術聯盟的基本UUID

這樣就可以打開RTT,把主從程式下載下傳進去,檢視一下資料就行了,條件可以,也可以仿真一下,資料發送與接收的對不對,我的測試是沒有問題的。

NRF51822學習筆記之主從通信講解,另外附加把UUID更改成藍牙技術聯盟的基本UUID