代码编写
1.添加device_stor()函数(保存设备地址和连接句柄函数)
//定义保存从机MAC地址的数组:
//NRF_SDH_BLE_CENTRAL_LINK_COUNT行,BLE_GAP_ADDR_LEN列
uint8_t addrs[NRF_SDH_BLE_CENTRAL_LINK_COUNT][BLE_GAP_ADDR_LEN];//mac地址保存
//保存设备地址和连接句柄
void device_stor(ble_nus_c_t * p_ble_nus_c, ble_gap_evt_t const * connect)
{
p_ble_nus_c->addr.addr[0] = connect->params.connected.peer_addr.addr[0];
p_ble_nus_c->addr.addr[1] = connect->params.connected.peer_addr.addr[1];
p_ble_nus_c->addr.addr[2] = connect->params.connected.peer_addr.addr[2];
p_ble_nus_c->addr.addr[3] = connect->params.connected.peer_addr.addr[3];
p_ble_nus_c->addr.addr[4] = connect->params.connected.peer_addr.addr[4];
p_ble_nus_c->addr.addr[5] = connect->params.connected.peer_addr.addr[5];
//保存MAC地址到自己定义的数组
memcpy(addrs[connect->conn_handle], connect->params.connected.peer_addr.addr, 6);
// p_ble_nus_c->conn_handle=connect->conn_handle; //保存连接句柄
}
2.多服务发现和句柄分配
//BLE_DB_DISCOVERY_DEF(m_db_disc); // BLE_ DB_ DISCOVERY_ DEF发现观察函数注册的本次发现
//BLE_NUS_C_DEF(m_ble_nus_c);
BLE_NUS_C_ARRAY_DEF(m_ble_nus_c, NRF_SDH_BLE_CENTRAL_LINK_COUNT);
BLE_DB_DISCOVERY_ARRAY_DEF(m_db_disc, NRF_SDH_BLE_CENTRAL_LINK_COUNT); /**< Database discovery module instances. */ /**< Database discovery module instance. */
3.修改ble_evt_handler()函数(蓝牙事件处理函数)
3.1 屏蔽单主机的服务查找代码
如下图:
3.2 添加一主机多从机连接代码
case BLE_GAP_EVT_CONNECTED:
//================发现从机服务添加===START
//一主机多从机:屏蔽单从机的时候服务发现函数
// err_code = ble_nus_c_handles_assign(&m_ble_nus_c, p_ble_evt->evt.gap_evt.conn_handle, NULL);
// APP_ERROR_CHECK(err_code);
//================发现从机服务添加===END
//连接的时候指示灯亮
err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
NRF_LOG_INFO("conn_handle: 0x%x",
p_gap_evt->conn_handle
);
APP_ERROR_CHECK(err_code);
NRF_LOG_INFO("connect OK!");
//主机发起PHY更新请求
err_code = sd_ble_gap_phy_update(p_gap_evt->conn_handle, &phys);
APP_ERROR_CHECK(err_code);
//打印更新请求的参数值
NRF_LOG_INFO("LL_PHY_REQ!");
NRF_LOG_INFO("rx_phys: %d",phys.rx_phys);
NRF_LOG_INFO("tx_phys: %d",phys.tx_phys);
//================发现从机服务添加===START
//一主机多从机:屏蔽单从机的时候服务发现函数
// NRF_LOG_INFO("start discovery services");//添加开始发现服务提示
// // 添加主服务数据发现汗水//开启发现服务,nus客户端等地啊发现结果
// err_code = ble_db_discovery_start(&m_db_disc, p_ble_evt->evt.gap_evt.conn_handle);
// APP_ERROR_CHECK(err_code);
//================发现从机服务添加===END
//====一主机多从机添加==================
APP_ERROR_CHECK_BOOL(p_gap_evt->conn_handle < NRF_SDH_BLE_CENTRAL_LINK_COUNT);
//分配不同的连接句柄
err_code = ble_nus_c_handles_assign(&m_ble_nus_c[p_gap_evt->conn_handle],
p_gap_evt->conn_handle,
NULL);
APP_ERROR_CHECK(err_code);
// 开始发现服务,需要分配不同的句柄
err_code = ble_db_discovery_start(&m_db_disc[p_gap_evt->conn_handle],
p_gap_evt->conn_handle);
APP_ERROR_CHECK(err_code);
//打印MAC地址
printf("Connecting to target %02x%02x%02x%02x%02x%02x",
p_gap_evt->params.connected.peer_addr.addr[0],
p_gap_evt->params.connected.peer_addr.addr[1],
p_gap_evt->params.connected.peer_addr.addr[2],
p_gap_evt->params.connected.peer_addr.addr[3],
p_gap_evt->params.connected.peer_addr.addr[4],
p_gap_evt->params.connected.peer_addr.addr[5]
);
//打印MAC地址对应的连接句柄
printf("Connection 0x%x established, starting DB discovery.",
p_gap_evt->conn_handle);
device_stor(&m_ble_nus_c[p_gap_evt->conn_handle],p_gap_evt);
if (err_code != NRF_ERROR_BUSY)
{
APP_ERROR_CHECK(err_code);
}
// Update LEDs status and check whether it is needed to look for more
// peripherals to connect to.
bsp_board_led_on(CENTRAL_CONNECTED_LED);//连接成功点亮LED指示
if (ble_conn_state_central_conn_count() == NRF_SDH_BLE_CENTRAL_LINK_COUNT)
{
bsp_board_led_off(CENTRAL_SCANNING_LED);//连接完所有设备LED指示
}
else
{
// Resume scanning.
bsp_board_led_on(CENTRAL_SCANNING_LED);
scan_start();
}
//一主机多从机添加======================
break;
3.3 添加LED宏定义
#define CENTRAL_SCANNING_LED BSP_BOARD_LED_0
#define CENTRAL_CONNECTED_LED BSP_BOARD_LED_1
4.修改nus_c_init()函数(主机客户端初始化函数)
将主机初始化函数修改成如下内容:
static void nus_c_init(void)//主机客户端初始化
{
ret_code_t err_code;
ble_nus_c_init_t init;
init.evt_handler = ble_nus_c_evt_handler;
for (uint32_t i = 0; i < NRF_SDH_BLE_CENTRAL_LINK_COUNT; i++)
{
err_code = ble_nus_c_init(&m_ble_nus_c[i], &init);
APP_ERROR_CHECK(err_code);
}
}
5. 添加设备地址比较函数
//输入地址和连接的设备地址
//con_addr:连接设备的地址
//uart_addr:输入的地址
uint8_t compare_addr(uint8_t con_addr[BLE_GAP_ADDR_LEN],uint8_t uart_addr[BLE_GAP_ADDR_LEN])
{
for(uint8_t i=0;i<BLE_GAP_ADDR_LEN;i++)
{
if(con_addr[i] != uart_addr[i])return 1;
}
return 0;
}
//如果输入的地址符合连接的设备地址,则把连接地址的连接句柄赋值给本次输入
//p_ble_nus_c:本次连接结构
//addr:输入的地址
uint16_t set_con_handle(ble_nus_c_t * p_ble_nus_c,uint8_t * addr)
{
for(uint32_t i=0;i<NRF_SDH_BLE_CENTRAL_LINK_COUNT;i++)
{
if((p_ble_nus_c->addr.addr[0] != 0x00) && (p_ble_nus_c->conn_handle != BLE_CONN_HANDLE_INVALID))
{
if(compare_addr(&p_ble_nus_c->addr.addr[0],addr) == 0)//表示输入的地址和存储的地址相等
{
return p_ble_nus_c->conn_handle;//分配存储的地址对应的句柄
}
}
p_ble_nus_c++;//如果不相等,继续搜寻
}
return 0xFFFF;
}
6.修改db_disc_handler()函数(注册的数据发现事件处理函数:函数)
//发现处理事件需要区分不同的句柄
static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
{
NRF_LOG_DEBUG("call to ble_lbs_on_db_disc_evt for instance %d and link 0x%x!",
p_evt->conn_handle,
p_evt->conn_handle);
ble_nus_c_on_db_disc_evt(&m_ble_nus_c[p_evt->conn_handle], p_evt);
}
7.编写主机向从机发送函数
//主机向从机发送数据函数
void Master_to_slave(uint8_t *addr, uint8_t* data_array, uint8_t dataA_len)
{
//获取连接句柄
uint16_t con_handle;
for(uint8_t i = 0;i < NRF_SDH_BLE_CENTRAL_LINK_COUNT; i++)
{
//遍历获取MAC地址对应的连接句柄
con_handle = set_con_handle(&m_ble_nus_c[i],addr);
if(con_handle != 0xFFFF)
{
//如果获取到响应MAC地址的句柄,结束遍历
break;
}
}
uint32_t ret_val;
if(con_handle != 0xFFFF)
{
//打印发送MAC地址
NRF_LOG_INFO("Send to target:");
NRF_LOG_HEXDUMP_DEBUG(addr, 6);//打印数组
//打印发送的数据
NRF_LOG_INFO("Send data:");
NRF_LOG_HEXDUMP_DEBUG(data_array, dataA_len);//打印数组
do
{
//向对应连接句柄的从机发送数据
ret_val = ble_nus_c_string_send(&m_ble_nus_c[con_handle], data_array, dataA_len);
if ( (ret_val != NRF_ERROR_INVALID_STATE) && (ret_val != NRF_ERROR_RESOURCES) )
{
APP_ERROR_CHECK(ret_val);
}
} while (ret_val == NRF_ERROR_RESOURCES);
}
else
{
NRF_LOG_DEBUG("send con_handle 0x%x",con_handle);
}
}
工程配置
1.修改ble_nus_c_s结构体
由于需要连接多个设备,需要添加保存设备MAC地址的数组;
struct ble_nus_c_s
{
ble_gap_addr_t addr;//添加保存MAC地址的数组
uint8_t uuid_type; /**< UUID type. */
uint16_t conn_handle; /**< Handle of the current connection. Set with @ref ble_nus_c_handles_assign when connected. */
ble_nus_c_handles_t handles; /**< Handles on the connected peer device needed to interact with it. */
ble_nus_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the NUS. */
};
2.文件添加
2.1 添加头文件以及目录
添加头文件:#include "ble_conn_state.h"
添加文件目录
2.2 添加.c文件
添加文件ble_conn_state.c
添加文件nrf_atflags.c
3.配置sdk_config.h文件
错误调试
错误1,工程RAM设置不对
现象
原因
工程的RAM设置没有根据增加从机的数量而改变;
解决
将工程RAM按照log打印提示修改
结果:问题解决
错误2,运行卡在连接的地方
现象:
log打印:
断点运行如下图
原因
重启之后可以运行到断点1却不能运行到断点2,说明程序是卡在断点1的语句处;
这里我们可以注意到,断点1处是串口打印语句,是我们从18.《一主机多从机(串口主机)》例程复制代码的时候一起复制过来的,但是本工程并没有用到串口,我们使用了未初始化的外设,所以程序会卡着。
解决:
将串口相关代码替换成LOG打印;
测试与总结
测试连接设备
测试方法:开启蓝牙板作为从机,开启仿真之后,可以看到log打印:
在watch窗口查看保存MAC地址的数组,如下图:
设备MAC地址保存成功,说明连接成功;
测试数据发送:
连接成功之后,按下按键4,主机每2秒向从机发送一次0X02;
log打印:
打开抓包器软件查看从机收到的数据和从机收到的时间
测试数据接收
按下按键3停止定时发送,按下按键2向从机发送0x05,从机即可返回已拍摄照片张数;
log打印如下:
抓包器抓包如下: