[{"data":1,"prerenderedAt":208},["ShallowReactive",2],{"content:\u002F2026\u002Fnrf52840-directed-connection":3,"surround:\u002F2026\u002Fnrf52840-directed-connection":202},{"id":4,"title":5,"body":6,"categories":175,"date":177,"description":178,"draft":179,"extension":180,"image":181,"meta":182,"navigation":184,"path":185,"permalink":186,"published":186,"readingTime":187,"recommend":186,"references":186,"seo":192,"sitemap":193,"stem":194,"tags":195,"type":200,"updated":186,"__hash__":201},"content\u002Fposts\u002F2026\u002Fnrf52840-directed-connection.md","NRF52840开发笔记：定向直连",{"type":7,"value":8,"toc":164},"minimark",[9,14,23,27,32,40,50,54,76,82,89,95,99,116,141,147,156],[10,11,13],"h2",{"id":12},"一需求","一、需求",[15,16,17,18,22],"p",{},"毕设项目里面需要实现在每个设备成功交换信息之后，从机需要选择一个综合指标最好的设备进行连接，一开始想的是在主机端进行处理，但大规模的设备组网对从机和主机的负担都很大。最简单最好的办法是从机使用",[19,20,21],"strong",{},"定向直连","的广播模式与目标主机设备进行连接。",[10,24,26],{"id":25},"二代码实现","二、代码实现",[28,29,31],"h3",{"id":30},"_1-广播初始化","1. 广播初始化",[15,33,34,35,39],{},"SDK中的广播方式是递进的，顺序为Direct High Duty -> Direct -> Fast -> Slow -> Idle。如果开启广播时选择Direct模式，即代码",[36,37,38],"code",{"code":38},"ble_advertising_start(&m_advertising, BLE_ADV_MODE_DIRECTED)","，但是未在初始化时设置Direct模式的相关参数，那么它就会尝试Fast模式，如果初始化时Fast模式的相关信息也没设置，就会再尝试Slow模式，如果初始化时Slow模式相关信息也没设置最后就直接进入到Idle模式了。在我的广播初始化中，我只初始化了Direct和Fast两个模式的参数。",[41,42,48],"pre",{"className":43,"code":45,"language":46,"meta":47},[44],"language-C","\u002F**\n * @brief 用于初始化广告功能的函数.\n *\u002F\nstatic void advertising_init(void)\n{\n    ret_code_t             err_code;\n    ble_advertising_init_t init;\n    \u002F\u002F 发送功率值\n    int8_t tx_power_value = -12;\n    \u002F\u002F service uuid\n    ble_uuid_t adv_uuids[] = {{SNS_UUID_SERVICE, BLE_UUID_TYPE_BLE}};\n    \u002F\u002F 自定义广播数据\n    uint8_t my_data[3] = {0x01, 0x02, 0x03};\n    ble_advdata_manuf_data_t manuf_data;\n    manuf_data.company_identifier = 0x0059;\n    manuf_data.data.p_data = my_data;\n    manuf_data.data.size = sizeof(my_data);\n\n    memset(&init, 0, sizeof(init));\n\n    \u002F\u002F Advertising data: name, appearance, discovery flags, and more. 广播数据\n    init.advdata.name_type               = BLE_ADVDATA_FULL_NAME;   \u002F\u002F 广播名字信息\n    init.advdata.include_appearance      = true;                    \u002F\u002F 广播图标信息\n    init.advdata.flags                   = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;   \u002F\u002F 通用广播模式\n    init.advdata.uuids_complete.uuid_cnt = sizeof(adv_uuids) \u002F sizeof(adv_uuids[0]);\n    init.advdata.uuids_complete.p_uuids  = adv_uuids;\n    init.advdata.p_tx_power_level        = &tx_power_value;         \u002F\u002F 显示的发送功率值\n    init.advdata.p_manuf_specific_data   = &manuf_data;\n\n    \u002F\u002F 选择将使用的广告模式和时间间隔\n    \u002F\u002F 广播流程是Direct High Duty -> Direct -> Fast -> Slow -> Idle\n    \u002F\u002F interval 广播一次的间隔(uint 0.625ms)  timeout 广播持续事件(uint 10ms)\n    init.config.ble_adv_directed_enabled  = true;\n    init.config.ble_adv_directed_interval = 1600;  \n    init.config.ble_adv_directed_timeout  = 1800;\n    init.config.ble_adv_fast_enabled  = true;\n    init.config.ble_adv_fast_interval = 1600;  \n    init.config.ble_adv_fast_timeout  = 1800;\n\n    \u002F\u002F 广播事件的回调函数\n    init.evt_handler = on_adv_evt; \n\n    err_code = ble_advertising_init(&m_advertising, &init);\n    APP_ERROR_CHECK(err_code);\n\n    ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);\n\n    \u002F\u002F 实际修改的功率\n    \u002F\u002F BLE_GAP_TX_POWER_ROLE_ADV        = 1     广播角色\n    \u002F\u002F BLE_GAP_TX_POWER_ROLE_SCAN_INIT  = 2     扫描和发起者角色\n    \u002F\u002F BLE_GAP_TX_POWER_ROLE_CONN       = 3     连接角色\n    err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, m_advertising.adv_handle, tx_power_value);\n    APP_ERROR_CHECK(err_code);\n}\n","C","",[36,49,45],{"__ignoreMap":47},[28,51,53],{"id":52},"_2-广播回调函数","2. 广播回调函数",[15,55,56,57,60,61,63,64,67,68,71,72,75],{},"在程序的",[36,58,59],{"code":59},"while(1)","开始前，我调用",[36,62,38],{"code":38},"开启广播，在广播回调函数中会抛出",[36,65,66],{"code":66},"BLE_ADV_EVT_PEER_ADDR_REQUEST","的请求。然而在开始时，还没有获得需要连接的设备的对等地址，所以全局变量",[36,69,70],{"code":70},"direct_peer_adr","还未赋值，则不会执行",[36,73,74],{"code":74},"ble_advertising_peer_addr_reply(&m_advertising, &direct_peer_adr)","。此时会跳过Direct模式的广播，直接进入Fast广播模式。",[41,77,80],{"className":78,"code":79,"language":46,"meta":47},[44],"\u002F**\n * @brief 用于处理广告事件的功能，广播观察者回调函数\n * @param[in] ble_adv_evt  广告活动.\n *\u002F\nstatic void on_adv_evt(ble_adv_evt_t ble_adv_evt)\n{\n    switch (ble_adv_evt)\n    {\n        \u002F\u002F 开始直连模式的回调\n        case BLE_ADV_EVT_DIRECTED:\n        {\n            NRF_LOG_INFO(\"Directed advertising.\");\n            bsp_board_led_on(ADVERTISING_LED);\n        }break;\n        \u002F\u002F 直连模式下对等地址的请求\n        case BLE_ADV_EVT_PEER_ADDR_REQUEST:\n        {   \n            NRF_LOG_INFO(\"peer addr request.\");\n            if(direct_peer_adr.addr[5] != 0x00)\n            {\n                ret_code_t err_code;\n                err_code = ble_advertising_peer_addr_reply(&m_advertising, &direct_peer_adr);\n                APP_ERROR_CHECK(err_code);\n            }\n        }break;\n        \u002F\u002F 开始快速广播时的回调\n        case BLE_ADV_EVT_FAST:\n        {\n            NRF_LOG_INFO(\"Fast advertising.\");\n            bsp_board_led_on(ADVERTISING_LED);\n        } break;\n        \u002F\u002F 广播超时的回调\n        case BLE_ADV_EVT_IDLE:\n        {\n            NRF_LOG_INFO(\"advertising time out.\");\n            bsp_board_led_off(ADVERTISING_LED);\n\n        } break;\n\n        default:\n            \u002F\u002F No implementation needed.\n            break;\n    }\n}\n",[36,81,79],{"__ignoreMap":47},[15,83,84,85,88],{},"下面是系统程序开始时，",[19,86,87],{},"从机端","输出的RTT日志信息：",[15,90,91],{},[92,93],"img",{"alt":47,"src":94},"https:\u002F\u002Fpub-6de6fb4a58154712aeace91d52d1828e.r2.dev\u002FPicGo\u002F47c71d328055824b8d9b7372c55e6b0d.png",[28,96,98],{"id":97},"_3-扫描回调函数","3. 扫描回调函数",[15,100,101,102,105,106,109,110,112,113,115],{},"对于",[19,103,104],{},"从机","而言，扫描到可连接的广播数据后，判断广播数据的对等设备是否是自己需要连接的，为了测试，我这里使用了简单的判断",[36,107,108],{"code":108},"if(p_adv->peer_addr.addr[0] \u003C DEVICE_ID)","，如果满足条件，就把变量",[36,111,70],{"code":70},"赋值为需要连接设备的对等地址。关闭后又打开广播是因为让广播从定向广播模式开始，在对等地址请求时会成功执行",[36,114,74],{"code":74},"而进入直连广播模式。",[15,117,101,118,121,122,125,126,129,130,133,134,137,138,140],{},[19,119,120],{},"需要被连接的主机","而言，从机发送定向广播后，会收到",[36,123,124],{"code":124},"directed","定向广播数据。",[19,127,128],{},"需要注意的是","，如果开启了扫描过滤，定向数据是不会出现在",[36,131,132],{"code":132},"NRF_BLE_SCAN_EVT_FILTER_MATCH","里的，而是出现在",[36,135,136],{"code":136},"NRF_BLE_SCAN_EVT_NOT_FOUND","里，这里我卡了很久！最后调用连接函数连接即可。此外，直连模式的广播是无法被Sniffer捕捉到的，因此我在没有收到直连数据时尝试过这个方法，后来才发现是在",[36,139,136],{"code":136},"里。",[41,142,145],{"className":143,"code":144,"language":46,"meta":47},[44],"\u002F**\n * @brief 扫描观察者回调函数\n * @param p_scan_evt \n *\u002F\nstatic void scan_evt_handler(scan_evt_t const * p_scan_evt)\n{\n    ret_code_t err_code;\n    ble_gap_evt_adv_report_t const * p_adv = p_scan_evt->params.filter_match.p_adv_report;\n    ble_gap_scan_params_t    const * p_scan_param = p_scan_evt->p_scan_params;\n    ble_gap_addr_t                   m_addr = p_adv->peer_addr;\n    \u002F\u002F uint8_t *data = NULL;\n    \u002F\u002F uint16_t dat_len;\n\n    switch(p_scan_evt->scan_evt_id)\n    {\n        \u002F\u002F 找到了过滤后的匹配项\n        case NRF_BLE_SCAN_EVT_FILTER_MATCH:\n        {\n            \u002F\u002F 可连接的\n            if(p_adv->type.connectable)\n            {\n                NRF_LOG_INFO(\"receive connectable data!\");\n                NRF_LOG_INFO(\"find device id: %d\", m_addr.addr[0]);\n                if(p_adv->peer_addr.addr[0] \u003C DEVICE_ID)\n                {\n                    NRF_LOG_INFO(\"turn to direct adv!\");\n                    direct_peer_adr.addr_type = m_addr.addr_type;\n                    direct_peer_adr.addr_id_peer = m_addr.addr_id_peer;\n                    strcpy((char *)direct_peer_adr.addr, (const char *)m_addr.addr);\n                    controlAdvertise(CLOSE);\n                    controlAdvertise(OPEN);\n                    controlScan(CLOSE);\n                }\n            }\n\n        } break;\n        \u002F\u002F 不匹配\n        case NRF_BLE_SCAN_EVT_NOT_FOUND:\n        {\n            \u002F\u002F 定向的\n            if(p_adv->type.directed)\n            {\n                NRF_LOG_INFO(\"receive directed data!\");\n                NRF_LOG_INFO(\"find device id: %d\", m_addr.addr[0]);\n                \u002F\u002F Initiate connection. 开始连接\n                \u002F\u002F 参数为目标MAC地址, 扫描参数, 连接参数, 连接配置标签, 这些参数均可以在扫描初始化参数部分获取.\n                \u002F\u002F 所及基本只需要得到目标的MAC地址就可以进行连接\n                err_code = sd_ble_gap_connect(&p_adv->peer_addr,\n                                            p_scan_param,\n                                            &m_scan.conn_params,\n                                            APP_BLE_CONN_CFG_TAG);\n                APP_ERROR_CHECK(err_code);\n            }\n        }break;\n        \u002F\u002F 扫描超时\n        case NRF_BLE_SCAN_EVT_SCAN_TIMEOUT:\n        {\n            NRF_LOG_INFO(\"scan timeout.\");\n            bsp_board_led_off(SCANNING_LED);\n        }break;\n\n        default:\n            break;\n    }\n}\n",[36,146,144],{"__ignoreMap":47},[15,148,149,150,153],{},"下面是直连时，主机和从机输出的RTT日志信息，从机通过判断条件设置了需要连接的对等地址，并重新开始广播使得定向广播成功开启。主机在扫描回调函数中，匹配项里发现了可连接非定向的数据，未匹配项里发现了定向数据，选择连接，并发现了自定义的sns服务。\n",[19,151,152],{},"主机输出：",[92,154],{"alt":47,"src":155},"https:\u002F\u002Fpub-6de6fb4a58154712aeace91d52d1828e.r2.dev\u002FPicGo\u002Fcb49783cc264e7a3de66ff3b91e59ca6.png",[15,157,158,161],{},[19,159,160],{},"从机输出：",[92,162],{"alt":47,"src":163},"https:\u002F\u002Fpub-6de6fb4a58154712aeace91d52d1828e.r2.dev\u002FPicGo\u002Fe7f268fed86b742c0c46aa7f97d3b5d1.png",{"title":47,"searchDepth":165,"depth":165,"links":166},4,[167,169],{"id":12,"depth":168,"text":13},2,{"id":25,"depth":168,"text":26,"children":170},[171,173,174],{"id":30,"depth":172,"text":31},3,{"id":52,"depth":172,"text":53},{"id":97,"depth":172,"text":98},[176],"技术","2026-05-14 18:10:00","记录在 NRF52840 项目中使用定向直连广播模式实现设备定向连接的思路与代码。",false,"md","https:\u002F\u002Fpub-6de6fb4a58154712aeace91d52d1828e.r2.dev\u002FPicGo\u002FNordic-Semiconductor-logo-horizontal.svg",{"slots":183},{},true,"\u002F2026\u002Fnrf52840-directed-connection",null,{"text":188,"minutes":189,"time":190,"words":191},"7 min read",6.86,411600,1372,{"title":5,"description":178},{"loc":185},"posts\u002F2026\u002Fnrf52840-directed-connection",[196,197,198,199],"NRF52840","BLE","Nordic","嵌入式","tech","iBA-L8jsnrDlOHDUpl97A4PBlv5Nw6zWq14rihENIt0",[186,203],{"title":204,"path":205,"stem":206,"date":207,"type":200,"children":-1},"MySQL建立远程连接","\u002F2026\u002Fmysql-build-remote","posts\u002F2026\u002Fmysql-build-remote","2026-05-18 13:26:46",1779084420459]