510
个编辑
更改
→实验简介
==== 实验简介 ====
==== 实验现象 ====
主机上电后发起扫描,一旦扫描到我们过滤的设备之后,就会发起连接。
连接成功后,打印连接的handle,以及主从机之间的连接参数。
当从机发起连接参数更新请求后,我们使用从机申请的连接参数,去发起连接参数的更新。
[[文件:Nrf rtt 17.png|边框|居中|无框|657x657像素]]
从机上电后广播,被主机连接后打印连接的handle,以及连接参数。
5000ms后,从机发起参数更新请求,主机接收请求后发起更新,更新成功后,从机打印新的连接参数。
[[文件:Nrf rtt 27.png|边框|居中|无框|648x648像素]]
==== 工程及源码讲解 ====
===== 主机部分 =====
主机部分大部分和之前的过滤连接是一样的,唯一的区别在于接收从机连接参数更新请求,并发起更新。
====== ble_evt_handler()回调函数 ======
在BLE事件回调中可以看到两个新增的事件处理,一个是连接参数更新请求BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST,另一个是连接参数更新BLE_GAP_EVT_CONN_PARAM_UPDATE。
BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:连接参数更新请求,这个状态是主机接收到从机发起更新参数的请求时返回,在这个状态下,我们可以获取从机申请更新的参数数值,并且调用sd_ble_gap_conn_param_update()函数去发起连接参数的更新。
BLE_GAP_EVT_CONN_PARAM_UPDATE:连接参数更新,当连接参数完成更新的时候,会返回这个状态,在这个状态中,我们可以获取到更新完成后的新的连接参数。<syntaxhighlight lang="c" line="1" start="202">
//******************************************************************
// fn : ble_evt_handler
//
// brief : BLE事件回调
// details : 包含以下几种事件类型:COMMON、GAP、GATT Client、GATT Server、L2CAP
//
// param : ble_evt_t 事件类型
// p_context 未使用
//
// return : none
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;
ble_gap_evt_connected_t const * p_connected_evt = &p_gap_evt->params.connected;
switch (p_ble_evt->header.evt_id)
{
// 连接
case BLE_GAP_EVT_CONNECTED:
NRF_LOG_INFO("Connected. conn_DevAddr: %s\nConnected. conn_handle: 0x%04x\nConnected. conn_Param: %d,%d,%d,%d",
Util_convertBdAddr2Str((uint8_t*)p_connected_evt->peer_addr.addr),
p_gap_evt->conn_handle,
p_connected_evt->conn_params.min_conn_interval,
p_connected_evt->conn_params.max_conn_interval,
p_connected_evt->conn_params.slave_latency,
p_connected_evt->conn_params.conn_sup_timeout
);
break;
// 断开连接
case BLE_GAP_EVT_DISCONNECTED:
NRF_LOG_INFO("Disconnected. conn_handle: 0x%x, reason: 0x%04x",
p_gap_evt->conn_handle,
p_gap_evt->params.disconnected.reason);
// 如果需要异常断开重连,可以打开下面的注释
// scan_start(); // 重新开始扫描
break;
// 连接参数更新请求
case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
NRF_LOG_INFO("conn_Param Update Request");
sd_ble_gap_conn_param_update(p_gap_evt->conn_handle,
&p_gap_evt->params.conn_param_update_request.conn_params);
break;
// 连接参数更新
case BLE_GAP_EVT_CONN_PARAM_UPDATE:
NRF_LOG_INFO("conn_Param Update: %d,%d,%d,%d",
p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.min_conn_interval,
p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.max_conn_interval,
p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.slave_latency,
p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.conn_sup_timeout
);
break;
default:
break;
}
}
</syntaxhighlight>
===== 从机部分 =====
从机部分,我们主要关注两个地方,一个是连接参数的更新请求conn_params_init()函数,另一个是和主机部分一样的,连接参数更新成功的状态返回。
====== conn_params_init()函数 ======
连接参数初始化函数,在这个函数中,我们配置了新的连接参数,以及连接参数更新的时间及尝试的次数,并且包含了两个回调函数,一个是更新是否成功的返回,一个是携带的连接参数是否正确的返回。
我们配置了第一次更新的时间为连接成功后5s(由frist_xx_delay控制),后面的几次也是间隔5s(由next_xx_delay控制),然后尝试更新次数为3。这个尝试次数3的含义是,如果申请了3次更新,都未成功,那么将从on_conn_params_evt回调中返回更新失败。<syntaxhighlight lang="c" line="1" start="245">
//******************************************************************
// fn : conn_params_init
//
// brief : 初始化连接参数模块的功能
//
// param : none
//
// return : none
static void conn_params_init(void)
{
uint32_t err_code;
ble_conn_params_init_t cp_init;
memset(&cp_init, 0, sizeof(cp_init));
cp_init.p_conn_params = &m_conn_params;
cp_init.first_conn_params_update_delay = APP_TIMER_TICKS(5000);
cp_init.next_conn_params_update_delay = APP_TIMER_TICKS(5000);
cp_init.max_conn_params_update_count = 3;
cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID;
cp_init.disconnect_on_fail = false;
cp_init.evt_handler = on_conn_params_evt;
cp_init.error_handler = conn_params_error_handler;
err_code = ble_conn_params_init(&cp_init);
APP_ERROR_CHECK(err_code);
}
</syntaxhighlight>可以看到,我们新的连接参数,连接间隔40ms,隐藏周期0,超时时间4s。<syntaxhighlight lang="c" line="1" start="57">
// 定义连接参数(为了展示连接参数的更新,我们设置连接间隔为固定的20ms)
static ble_gap_conn_params_t m_conn_params =
{
.min_conn_interval = MSEC_TO_UNITS(40, UNIT_1_25_MS), // 最小连接间隔40ms
.max_conn_interval = MSEC_TO_UNITS(40, UNIT_1_25_MS), // 最大连接间隔40ms
.slave_latency = 0, // 隐藏周期0
.conn_sup_timeout = MSEC_TO_UNITS(2000, UNIT_10_MS), // 超时时间4000ms
};
</syntaxhighlight>在on_conn_params_evt()回调函数中,我们可以看到连接参数更新成功或者失败的返回。
这边需要注意的问题点如下,以我们这个实验为例,例如我们的参数更新请求会尝试3次:
1、如果第一次就更新成功,那么会直接返回更新SUCCESS,并且后面2次更新请求将不会再起作用
2、如果三次更新都不成功(这个不成功,可能是更新失败,可能是主机不响应等等),那么才会返回更新failed
也就是3次只要有一次更新成功就认为我们更新完成了,如果3次都失败,才会认为失败。<syntaxhighlight lang="c" line="1" start="211">
//******************************************************************
// fn : on_conn_params_evt
//
// brief : 处理连接更新参数的事件回调
//
// param : p_evt -> 接收到的连接模块返回的任务事件
//
// return : none
static void on_conn_params_evt(ble_conn_params_evt_t * p_evt)
{
if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_SUCCEEDED)
{
NRF_LOG_INFO("connParam Update Success");
}
if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED)
{
NRF_LOG_INFO("connParam Update Failed");
}
}
</syntaxhighlight>这边的conn_params_error_handler()错误回调函数,当我们申请更新的连接参数不符合协议时才会返回,也就是提示我们连接参数异常。<syntaxhighlight lang="c" line="1" start="232">
//******************************************************************
// fn : conn_params_error_handler
//
// brief : 处理连接更新参数异常的事件回调
//
// param : nrf_error -> 异常标志
//
// return : none
static void conn_params_error_handler(uint32_t nrf_error)
{
APP_ERROR_HANDLER(nrf_error);
}
</syntaxhighlight>
====== ble_evt_handler()回调函数 ======
BLE事件回调函数,和主机一样的,当我们成功更新连接参数之后,返回BLE_GAP_EVT_CONN_PARAM_UPDATE事件,在这个事件中我们可以获取新的连接参数。<syntaxhighlight lang="c" line="1" start="159">
//******************************************************************
// fn : ble_evt_handler
//
// brief : BLE事件回调
// details : 包含以下几种事件类型:COMMON、GAP、GATT Client、GATT Server、L2CAP
//
// param : ble_evt_t 事件类型
// p_context 未使用
//
// return : none
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;
ble_gap_evt_connected_t const * p_connected_evt = &p_gap_evt->params.connected;
switch (p_ble_evt->header.evt_id)
{
// 连接
case BLE_GAP_EVT_CONNECTED:
NRF_LOG_INFO("Connected. conn_DevAddr: %s\nConnected. conn_handle: 0x%04x\nConnected. conn_Param: %d,%d,%d,%d",
Util_convertBdAddr2Str((uint8_t*)p_connected_evt->peer_addr.addr),
p_gap_evt->conn_handle,
p_connected_evt->conn_params.min_conn_interval,
p_connected_evt->conn_params.max_conn_interval,
p_connected_evt->conn_params.slave_latency,
p_connected_evt->conn_params.conn_sup_timeout
);
break;
// 断开连接
case BLE_GAP_EVT_DISCONNECTED:
NRF_LOG_INFO("Disconnected. conn_handle: 0x%x, reason: 0x%04x",
p_gap_evt->conn_handle,
p_gap_evt->params.disconnected.reason);
break;
// 连接参数更新
case BLE_GAP_EVT_CONN_PARAM_UPDATE:
NRF_LOG_INFO("conn_Param Update: %d,%d,%d,%d",
p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.min_conn_interval,
p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.max_conn_interval,
p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.slave_latency,
p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.conn_sup_timeout
);
break;
default:
break;
}
}
</syntaxhighlight>
==== 实验总结 ====
这一章的实验,想要交给大家的内容是如何配置连接参数。需要了解的重点如下:
1、了解连接参数的含义,明白连接参数越小,通信的速率越快。
2、了解主从机之间的连接参数的配置流程。
3、了解从机如何申请更新连接参数,ble_conn_params_init()函数。
4、了解主机如何更新连接参数,sd_ble_gap_conn_param_update()函数。
=== MTU更新实验 ===