NRF52840开发笔记——定向直连

一、需求

毕设项目里面需要实现在每个设备成功交换信息之后,从机需要选择一个综合指标最好的设备进行连接,一开始想的是在主机端进行处理,但大规模的设备组网对从机和主机的负担都很大。最简单最好的办法是从机使用定向直连的广播模式与目标主机设备进行连接。

二、代码实现

1. 广播初始化

SDK中的广播方式是递进的,顺序为Direct High Duty -> Direct -> Fast -> Slow -> Idle。如果开启广播时选择Direct模式,即代码ble_advertising_start(&m_advertising, BLE_ADV_MODE_DIRECTED),但是未在初始化时设置Direct模式的相关参数,那么它就会尝试Fast模式,如果初始化时Fast模式的相关信息也没设置,就会再尝试Slow模式,如果初始化时Slow模式相关信息也没设置最后就直接进入到Idle模式了。在我的广播初始化中,我只初始化了Direct和Fast两个模式的参数。

/**
 * @brief 用于初始化广告功能的函数.
 */
static void advertising_init(void)
{
    ret_code_t             err_code;
    ble_advertising_init_t init;
    // 发送功率值
    int8_t tx_power_value = -12;
    // service uuid
    ble_uuid_t adv_uuids[] = {{SNS_UUID_SERVICE, BLE_UUID_TYPE_BLE}};
    // 自定义广播数据
    uint8_t my_data[3] = {0x01, 0x02, 0x03};
    ble_advdata_manuf_data_t manuf_data;
    manuf_data.company_identifier = 0x0059;
    manuf_data.data.p_data = my_data;
    manuf_data.data.size = sizeof(my_data);

    memset(&init, 0, sizeof(init));

    // Advertising data: name, appearance, discovery flags, and more. 广播数据
    init.advdata.name_type               = BLE_ADVDATA_FULL_NAME;   // 广播名字信息
    init.advdata.include_appearance      = true;                    // 广播图标信息
    init.advdata.flags                   = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;   // 通用广播模式
    init.advdata.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]);
    init.advdata.uuids_complete.p_uuids  = adv_uuids;
    init.advdata.p_tx_power_level        = &tx_power_value;         // 显示的发送功率值
    init.advdata.p_manuf_specific_data   = &manuf_data;

    // 选择将使用的广告模式和时间间隔
    // 广播流程是Direct High Duty -> Direct -> Fast -> Slow -> Idle
    // interval 广播一次的间隔(uint 0.625ms)  timeout 广播持续事件(uint 10ms)
    init.config.ble_adv_directed_enabled  = true;
    init.config.ble_adv_directed_interval = 1600;  
    init.config.ble_adv_directed_timeout  = 1800;
    init.config.ble_adv_fast_enabled  = true;
    init.config.ble_adv_fast_interval = 1600;  
    init.config.ble_adv_fast_timeout  = 1800;

    // 广播事件的回调函数
    init.evt_handler = on_adv_evt; 

    err_code = ble_advertising_init(&m_advertising, &init);
    APP_ERROR_CHECK(err_code);

    ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);

    // 实际修改的功率
    // BLE_GAP_TX_POWER_ROLE_ADV        = 1     广播角色
    // BLE_GAP_TX_POWER_ROLE_SCAN_INIT  = 2     扫描和发起者角色
    // BLE_GAP_TX_POWER_ROLE_CONN       = 3     连接角色
    err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, m_advertising.adv_handle, tx_power_value);
    APP_ERROR_CHECK(err_code);
}

2. 广播回调函数

在程序的while(1)开始前,我调用ble_advertising_start(&m_advertising, BLE_ADV_MODE_DIRECTED)开启广播,在广播回调函数中会抛出BLE_ADV_EVT_PEER_ADDR_REQUEST的请求。然而在开始时,还没有获得需要连接的设备的对等地址,所以全局变量direct_peer_adr还未赋值,则不会执行ble_advertising_peer_addr_reply(&m_advertising, &direct_peer_adr)。此时会跳过Direct模式的广播,直接进入Fast广播模式。

/**
 * @brief 用于处理广告事件的功能,广播观察者回调函数
 * @param[in] ble_adv_evt  广告活动.
 */
static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
{
    switch (ble_adv_evt)
    {
        // 开始直连模式的回调
        case BLE_ADV_EVT_DIRECTED:
        {
            NRF_LOG_INFO("Directed advertising.");
            bsp_board_led_on(ADVERTISING_LED);
        }break;
        // 直连模式下对等地址的请求
        case BLE_ADV_EVT_PEER_ADDR_REQUEST:
        {   
            NRF_LOG_INFO("peer addr request.");
            if(direct_peer_adr.addr[5] != 0x00)
            {
                ret_code_t err_code;
                err_code = ble_advertising_peer_addr_reply(&m_advertising, &direct_peer_adr);
                APP_ERROR_CHECK(err_code);
            }
        }break;
        // 开始快速广播时的回调
        case BLE_ADV_EVT_FAST:
        {
            NRF_LOG_INFO("Fast advertising.");
            bsp_board_led_on(ADVERTISING_LED);
        } break;
        // 广播超时的回调
        case BLE_ADV_EVT_IDLE:
        {
            NRF_LOG_INFO("advertising time out.");
            bsp_board_led_off(ADVERTISING_LED);

        } break;

        default:
            // No implementation needed.
            break;
    }
}

下面是系统程序开始时,从机端输出的RTT日志信息:
在这里插入图片描述

3. 扫描回调函数

对于从机而言,扫描到可连接的广播数据后,判断广播数据的对等设备是否是自己需要连接的,为了测试,我这里使用了简单的判断if(p_adv->peer_addr.addr[0] < DEVICE_ID),如果满足条件,就把变量direct_peer_adr赋值为需要连接设备的对等地址。关闭后又打开广播是因为让广播从定向广播模式开始,在对等地址请求时会成功执行ble_advertising_peer_addr_reply(&m_advertising, &direct_peer_adr)而进入直连广播模式。

对于需要被连接的主机而言,从机发送定向广播后,会收到directed定向广播数据。需要注意的是,如果开启了扫描过滤,定向数据是不会出现在NRF_BLE_SCAN_EVT_FILTER_MATCH里的,而是出现在NRF_BLE_SCAN_EVT_NOT_FOUND里,这里我卡了很久!最后调用连接函数连接即可。此外,直连模式的广播是无法被Sniffer捕捉到的,因此我在没有收到直连数据时尝试过这个方法,后来才发现是在NRF_BLE_SCAN_EVT_NOT_FOUND里。

/**
 * @brief 扫描观察者回调函数
 * @param p_scan_evt 
 */
static void scan_evt_handler(scan_evt_t const * p_scan_evt)
{
    ret_code_t err_code;
    ble_gap_evt_adv_report_t const * p_adv = p_scan_evt->params.filter_match.p_adv_report;
    ble_gap_scan_params_t    const * p_scan_param = p_scan_evt->p_scan_params;
    ble_gap_addr_t                   m_addr = p_adv->peer_addr;
    // uint8_t *data = NULL;
    // uint16_t dat_len;

    switch(p_scan_evt->scan_evt_id)
    {
        // 找到了过滤后的匹配项
        case NRF_BLE_SCAN_EVT_FILTER_MATCH:
        {
            // 可连接的
            if(p_adv->type.connectable)
            {
                NRF_LOG_INFO("receive connectable data!");
                NRF_LOG_INFO("find device id: %d", m_addr.addr[0]);
                if(p_adv->peer_addr.addr[0] < DEVICE_ID)
                {
                    NRF_LOG_INFO("turn to direct adv!");
                    direct_peer_adr.addr_type = m_addr.addr_type;
                    direct_peer_adr.addr_id_peer = m_addr.addr_id_peer;
                    strcpy((char *)direct_peer_adr.addr, (const char *)m_addr.addr);
                    controlAdvertise(CLOSE);
                    controlAdvertise(OPEN);
                    controlScan(CLOSE);
                }
            }

        } break;
        // 不匹配
        case NRF_BLE_SCAN_EVT_NOT_FOUND:
        {
            // 定向的
            if(p_adv->type.directed)
            {
                NRF_LOG_INFO("receive directed data!");
                NRF_LOG_INFO("find device id: %d", m_addr.addr[0]);
                // Initiate connection. 开始连接
                // 参数为目标MAC地址, 扫描参数, 连接参数, 连接配置标签, 这些参数均可以在扫描初始化参数部分获取.
                // 所及基本只需要得到目标的MAC地址就可以进行连接
                err_code = sd_ble_gap_connect(&p_adv->peer_addr,
                                            p_scan_param,
                                            &m_scan.conn_params,
                                            APP_BLE_CONN_CFG_TAG);
                APP_ERROR_CHECK(err_code);
            }
        }break;
        // 扫描超时
        case NRF_BLE_SCAN_EVT_SCAN_TIMEOUT:
        {
            NRF_LOG_INFO("scan timeout.");
            bsp_board_led_off(SCANNING_LED);
        }break;

        default:
            break;
    }
}

下面是直连时,主机和从机输出的RTT日志信息,从机通过判断条件设置了需要连接的对等地址,并重新开始广播使得定向广播成功开启。主机在扫描回调函数中,匹配项里发现了可连接非定向的数据,未匹配项里发现了定向数据,选择连接,并发现了自定义的sns服务。
主机输出:
在这里插入图片描述

从机输出:
在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: nRF52840是一款由Nordic Semiconductor(挪威北方半导体)推出的蓝牙低功耗(Bluetooth Low Energy,BLE)芯片。nRF52840开发指南是为了帮助开发人员更好地了解和使用nRF52840芯片而编写的一份技术文档。 在nRF52840开发指南中,首先介绍了nRF52840芯片的概述,包括其主要特点和应用领域。然后详细介绍了nRF52840芯片的硬件设计,包括引脚功能、电源管理、时钟和无线电等方面的设计要点,帮助开发人员在设计电路板时更好地利用芯片的功能。 接着,nRF52840开发指南开发人员介绍了nRF5软件开发套件(SDK),该套件提供了在nRF52840芯片上进行应用程序开发所需的软件工具和示例代码。文中详细介绍了如何安装和配置SDK,并给出了一些常见的应用程序开发示例。 在软件开发部分中,nRF52840开发指南还介绍了nRF52840的软件架构和支持的协议栈,如BLE协议栈和ANT协议栈。开发人员可以根据自己的需求选择合适的协议栈,并按照指南中给出的步骤进行相应的配置和开发工作。 最后,nRF52840开发指南还提供了一些在nRF52840开发中常见问题的解答,以及针对特定应用场景的案例分析和优化建议,帮助开发人员更好地理解和应用nRF52840芯片。 综上所述,nRF52840开发指南是一本重要的技术文档,对于想要了解和使用nRF52840芯片进行开发的人员来说,是一份不可或缺的参考资料。 ### 回答2: 要下载nRF52840开发指南,可以按照以下步骤进行操作。 首先,打开Nordic Semiconductor官方网站,找到nRF52840产品页面。在该页面中,可以找到各种与nRF52840相关的文档和指南。 在该页面上,找到“开发指南”的选项,并点击进入。在这个页面上,将提供nRF52840开发指南的下载链接。 点击下载链接,然后选择保存文件的位置。可以选择将文件保存到计算机的硬盘中,或者将其保存到移动存储设备,如USB闪存驱动器。 等待下载完成后,打开下载的文件。一般来说,nRF52840开发指南会以PDF格式提供,因此需要确保计算机上有能够阅读PDF文件的软件,如Adobe Acrobat Reader。 在打开的文件中,可以找到详细的nRF52840开发指南。该指南将包含关于nRF52840芯片的详细说明、硬件设计指南、软件开发指南、编程示例和应用案例等内容。 可以根据自己的需要,阅读和学习开发指南中提供的内容。这个指南将有助于理解和学习如何使用nRF52840开发板进行硬件和软件开发,以便于设计和构建自己的应用程序。 总而言之,要下载nRF52840开发指南,需要访问Nordic Semiconductor官方网站,找到nRF52840产品页面并下载相关的开发指南。这些指南将提供关于nRF52840芯片的详细信息和相关开发技术的指导。 ### 回答3: nrf52840开发指南是一本关于nRF52840蓝牙低功耗多协议系统级芯片开发的书籍。该指南提供了有关硬件和软件开发、调试和优化的详细信息,旨在帮助开发者快速掌握nRF52840的应用。 首先,为了下载nrf52840开发指南,可以通过Nordic Semiconductor官方网站或其开发者社区获得。在网站或社区上,会提供资源下载的链接或指引。 下载nrf52840开发指南后,我们可以逐步了解如何开始使用nRF52840硬件。其中包括了nRF52840的硬件特性和规格,以及连接外部器件的方法。此外,该指南还介绍了如何使用Nordic Semiconductor的开发套件和软件工具,如nRF Connect,以开发和测试nRF52840的应用程序。 在软件开发方面,nrf52840开发指南详细介绍了nRF5 Software Development Kit(SDK)和nRF Command Line Tools的安装和使用。SDK提供了丰富的软件库和示例代码,以支持不同的应用场景。开发者可以学习如何使用SDK创建自己的应用程序,并了解如何将代码编译、烧录和调试到nRF52840芯片上。 此外,该指南还提供了有关nRF52840的低功耗特性和优化技巧的详细指导。开发者可以学习如何使用低功耗模式和功耗管理功能,以延长设备的电池寿命。 总之,nrf52840开发指南是一本全面而详细的指南,为开发者提供了学习和开发nRF52840芯片的必备工具和资源。通过下载并阅读该指南开发者可以深入了解nRF52840开发过程和技术细节,从而更好地应用该芯片开发出高性能低功耗的物联网设备。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhZeng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值