NRF51822主模式扫描连接实战:从扫描到连接的状态机与参数调优
简介这份资源面向低功耗蓝牙开发初学者与物联网嵌入式工程师聚焦NRF51822芯片的主模式扫描与连接实现解决主设备如何发现目标蓝牙模块、建立连接并完成主从数据透传的问题。压缩包共3个文件包含2个C源文件与1个H头文件整体约11KB其中nrf_uart_at.c与nrf_uart_at.h封装了串口与BLE交互的接口main.c则承载主流程逻辑便于直接移植到Nordic开发环境。内容覆盖BLE初始化、扫描参数配置、广告数据解析、连接请求发起、连接参数协商以及自定义服务与特征值的数据读写可帮助读者理解GATT服务下的透明传输机制。目前已有422人学习下载适合需要快速搭建主从通信原型、构建远程控制或健康监测类物联网应用的开发者参考也可作为蓝牙网络多跳通信的入门实践素材。1. NRF51822主模式扫描连接从被动等待到主动出击的那一步很多刚接触低功耗蓝牙的开发者第一次把NRF51822当从机跑通广播后都会卡在同一个地方两块板子面对面却怎么也连不上。问题往往不在射频而在于没人告诉你主模式扫描连接到底该怎么配。NRF51822主模式扫描连接说白了就是让这颗芯片从被动广播的从机角色切换到主动搜索、发起连接的主机角色。它解决的是设备间自主组网的问题适合做数据采集网关、多节点传感器汇聚、手持终端主动读取设备信息这类场景。如果你只会从机广播那设备永远只能等别人来连学会主模式你才能让设备自己去发现、去连接、去拿数据。这一章不堆概念先把主模式扫描连接在NRF51822上到底意味着什么讲清楚后面再一步步落到协议栈配置、参数设置和实际排错上。2. 主模式扫描连接在协议栈里到底走了哪几步2.1 扫描和连接是两个独立阶段别混在一起调NRF51822的蓝牙协议栈把主模式行为拆成了扫描和连接两个独立阶段。扫描阶段只负责监听空中广播包把广播地址、RSSI、广播数据解析出来连接阶段才是真正向目标设备发起连接请求建立链路层连接。很多新手一上来就调连接参数结果扫描都没扫到设备自然连不上。常见做法是先用扫描把目标设备地址拿到再拿这个地址去发起连接。扫描又分被动扫描和主动扫描被动扫描只收广播包主动扫描还会发扫描请求让从机回扫描响应能多拿一些数据。如果你只需要设备地址和RSSI被动扫描就够了如果要读扫描响应里的自定义数据就得开主动扫描。2.2 协议栈初始化时主模式相关的几个关键配置NRF51822的协议栈初始化结构体里跟主模式直接相关的是角色使能和外设数量配置。下面这段代码是常见的最小配置只开中央角色不开广播。// 协议栈初始化只使能中央角色关闭广播 ble_gap_addr_t gap_addr; uint32_t err_code; // 设置本机蓝牙地址主模式也需要一个合法地址 gap_addr.addr_type BLE_GAP_ADDR_TYPE_RANDOM_STATIC; gap_addr.addr[0] 0x01; gap_addr.addr[1] 0x02; gap_addr.addr[2] 0x03; gap_addr.addr[3] 0x04; gap_addr.addr[4] 0x05; gap_addr.addr[5] 0xC0; err_code sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, gap_addr); APP_ERROR_CHECK(err_code); // 协议栈使能参数中央角色连接数设为1外设角色连接数设为0 ble_enable_params_t ble_enable_params; memset(ble_enable_params, 0, sizeof(ble_enable_params)); ble_enable_params.gap_enable_params.role BLE_GAP_ROLE_CENTRAL; ble_enable_params.gap_enable_params.periph_conn_count 0; ble_enable_params.gap_enable_params.central_conn_count 1; ble_enable_params.common_enable_params.vs_uuid_count 1; err_code sd_ble_enable(ble_enable_params); APP_ERROR_CHECK(err_code);这段代码里role设成BLE_GAP_ROLE_CENTRAL表示只做主机periph_conn_count设0表示不接收别人连我central_conn_count设1表示我最多连一个从机。如果你要做多节点汇聚这个值可以往上调但要注意NRF51822的RAM和连接数上限一般建议不超过4个。地址类型用随机静态地址就行不用纠结公共地址主模式对地址类型不敏感。2.3 扫描参数怎么设间隔、窗口和超时扫描参数直接决定你能不能扫到目标设备以及扫到得快不快。下面是一个常用的扫描配置。// 扫描参数配置主动扫描间隔160ms窗口80ms不超时 ble_gap_scan_params_t scan_params; memset(scan_params, 0, sizeof(scan_params)); scan_params.active 1; // 主动扫描发扫描请求 scan_params.interval MSEC_TO_UNITS(160, UNIT_0_625_MS); // 扫描间隔160ms scan_params.window MSEC_TO_UNITS(80, UNIT_0_625_MS); // 扫描窗口80ms scan_params.timeout 0; // 0表示不超时一直扫 scan_params.selective 0; // 不启用白名单过滤 err_code sd_ble_gap_scan_start(scan_params); APP_ERROR_CHECK(err_code);interval是两次扫描窗口起始的时间差window是每次扫描持续监听的时间。window必须小于等于interval否则协议栈会报错。上面这组参数的意思是每160ms里有80ms在监听占空比50%。占空比越高扫到设备越快但功耗越大。如果你做的是电池供电的网关可以把window降到interval的20%左右比如interval 160ms、window 32ms牺牲一点扫描速度换功耗。timeout设0表示一直扫设非0值则单位是10ms比如设100就是1秒后自动停。实际项目里我一般先设0扫到目标后再手动停避免扫到一半超时了还得重来。2.4 扫到设备后怎么发起连接扫描回调里拿到目标设备地址后就可以发起连接了。连接参数比扫描参数更敏感设不好会连上就断。// 扫描回调拿到目标地址后发起连接 static void on_ble_adv_report(ble_gap_evt_adv_report_t const *p_adv_report) { // 判断广播地址是否为目标设备 if (memcmp(p_adv_report-peer_addr.addr, target_addr, 6) 0) { // 先停止扫描再发起连接 sd_ble_gap_scan_stop(); ble_gap_conn_params_t conn_params; memset(conn_params, 0, sizeof(conn_params)); conn_params.min_conn_interval MSEC_TO_UNITS(20, UNIT_1_25_MS); // 最小连接间隔20ms conn_params.max_conn_interval MSEC_TO_UNITS(40, UNIT_1_25_MS); // 最大连接间隔40ms conn_params.slave_latency 0; // 从机延迟0 conn_params.conn_sup_timeout MSEC_TO_UNITS(4000, UNIT_10_MS); // 连接超时4s uint32_t err sd_ble_gap_connect(p_adv_report-peer_addr, scan_params, conn_params); APP_ERROR_CHECK(err); } }连接参数里min_conn_interval和max_conn_interval是连接间隔范围单位1.25ms。上面设的是20ms到40ms意思是双方协商一个在这个范围内的间隔。slave_latency允许从机跳过多少次连接事件不响应设0表示每次都响应设大了省电但响应慢。conn_sup_timeout是连接超时单位10ms设4000就是4秒。注意超时时间必须大于 (1 slave_latency) × max_conn_interval × 2否则协议栈会拒绝这组参数。我一般会留足余量避免玄学断连。3. 扫描连接过程中最容易翻车的几个地方3.1 扫不到设备先查地址类型和广播通道现象是扫描回调一直不触发或者只扫到别的设备就是扫不到目标。原因通常是目标设备用的是随机私有地址每次上电地址都变你拿旧地址去匹配自然匹配不上。解决方法是扫描时不要写死地址而是根据广播数据里的厂商自定义字段或者设备名称来过滤。另一个常见原因是广播通道干扰NRF51822默认在37、38、39三个通道轮流扫如果周围2.4G设备太多可以适当加大扫描窗口。还有个小概率情况是目标设备广播间隔太长比如设了2秒而你扫描窗口只有30ms那就得等好几个周期才能撞上。3.2 连上就断连接参数超出从机接受范围现象是连接建立后几百毫秒内就断开错误码常见0x08或0x3B。原因是主机提的连接参数从机不接受比如从机要求最小连接间隔不得低于100ms你提了20ms从机直接拒绝。解决方法是连接发起前先读从机的设备信息或者用通用连接参数把min_conn_interval设大一点比如100ms起步连上后再通过连接参数更新流程往下降。NRF51822的协议栈支持连接后发起参数更新不用一开始就卡死。3.3 扫描和连接切换时协议栈返回忙现象是调用sd_ble_gap_connect返回NRF_ERROR_BUSY。原因是扫描停止命令还没执行完协议栈还在处理扫描停止事件你就急着发起连接。解决方法是不要在扫描回调里直接调连接而是设一个标志位在主循环里等扫描停止事件BLE_GAP_EVT_SCAN_TIMEOUT或者BLE_GAP_EVT_ADV_REPORT处理完之后再发起连接。我一般会在扫描停止后延时10ms再调连接给协议栈留出清理时间。3.4 多设备环境下连错目标现象是周围有好几个同型号设备你连上了其中一个但不是你想要的那个。原因是只按地址过滤而地址可能重复或者随机变化。解决方法是在广播数据里加一个自定义的厂商ID或者序列号字段扫描时解析广播数据匹配这个字段而不是只匹配地址。NRF51822的广播数据解析可以用ble_advdata_decode相关接口把厂商自定义数据解出来比对。3.5 连接成功后收不到从机数据现象是连接建立成功但GATT服务发现或者特征值读取一直失败。原因通常是连接间隔太短或者从机延迟设太大导致数据交互窗口不够。解决方法是先把连接间隔放宽到50ms以上slave_latency设0确保每次连接事件双方都有机会收发。等链路稳定后再逐步收紧参数。另外注意NRF51822的协议栈事件回调里不要做耗时操作否则会阻塞协议栈导致数据丢失。4. 把主模式扫描连接做成可复用的状态机4.1 用状态机管理扫描、连接、服务发现三个阶段主模式流程不是一条直线扫描可能失败要重扫连接可能断开要重连服务发现可能超时要重试。用状态机来管最稳。下面是一个简化状态机框架。typedef enum { STATE_IDLE, // 空闲 STATE_SCANNING, // 扫描中 STATE_CONNECTING, // 连接中 STATE_DISCOVERING, // 服务发现中 STATE_CONNECTED, // 已连接可用 STATE_ERROR // 错误处理 } main_state_t; static main_state_t m_state STATE_IDLE; // 主循环里根据状态推进 void main_loop(void) { switch (m_state) { case STATE_IDLE: start_scan(); // 启动扫描 m_state STATE_SCANNING; break; case STATE_SCANNING: // 扫描回调里扫到目标后置标志这里检查标志 if (scan_target_found) { stop_scan(); m_state STATE_CONNECTING; } break; case STATE_CONNECTING: if (connect_success) { m_state STATE_DISCOVERING; start_service_discovery(); } else if (connect_failed) { m_state STATE_ERROR; } break; case STATE_DISCOVERING: if (discovery_done) { m_state STATE_CONNECTED; } break; case STATE_CONNECTED: // 正常数据交互 break; case STATE_ERROR: // 错误处理延时后重试 nrf_delay_ms(500); m_state STATE_IDLE; break; } }这个状态机的核心是把每个阶段的进入条件、退出条件和失败处理分开。扫描失败就回IDLE重扫连接失败也回IDLE服务发现失败可以重试一次再回IDLE。实际项目里我会给每个状态加一个超时计数器比如扫描超过10秒没结果就强制回IDLE避免卡死。4.2 连接参数动态调整先连上再优化不要指望一次就把连接参数设到最优。我的习惯是分两步第一步用保守参数连上比如min_conn_interval 100ms、max_conn_interval 200ms、slave_latency 0、timeout 4s第二步连上并完成服务发现后再根据实际数据吞吐需求发起连接参数更新。NRF51822的协议栈里用sd_ble_gap_conn_param_update发起更新从机可以接受也可以拒绝。如果从机拒绝就保持保守参数继续用别硬来。下面是一个参数更新的例子。// 连接建立后尝试更新到更快的连接参数 ble_gap_conn_params_t new_params; new_params.min_conn_interval MSEC_TO_UNITS(30, UNIT_1_25_MS); new_params.max_conn_interval MSEC_TO_UNITS(50, UNIT_1_25_MS); new_params.slave_latency 0; new_params.conn_sup_timeout MSEC_TO_UNITS(4000, UNIT_10_MS); uint32_t err sd_ble_gap_conn_param_update(conn_handle, new_params); if (err ! NRF_SUCCESS) { // 更新失败就保持原参数不影响使用 }4.3 扫描过滤用白名单和自定义数据减少无效连接如果周围设备很多每次扫描都遍历所有广播包效率很低。NRF51822支持白名单过滤可以先把目标设备地址加到白名单里扫描时只上报白名单内的设备。白名单用sd_ble_gap_whitelist_set设置最多支持8个地址。但白名单对随机地址不友好因为随机地址会变。更通用的做法是在扫描回调里解析广播数据只处理包含特定厂商ID或服务UUID的广播包其他直接忽略。这样即使周围有几十个设备你的扫描回调也只会被目标设备触发。5. 主模式扫描连接的一个实战技巧用RSSI做连接决策5.1 为什么RSSI比地址更值得关注地址只能告诉你“这是不是目标设备”RSSI能告诉你“这个设备离我多远、信号稳不稳”。在多节点场景里同一个设备可能被多个网关扫到这时候选RSSI最强的那个网关去连链路质量最好。NRF51822的扫描回调里p_adv_report-rssi就是当前广播包的信号强度单位dBm典型值在-30到-90之间。我一般会设一个阈值比如-70dBm低于这个值就不发起连接避免连上就断。5.2 用滑动平均过滤RSSI抖动单次RSSI抖动很大直接拿来决策容易误判。常见做法是维护一个最近N次RSSI的滑动平均N取5到10。下面是一个简单的滑动平均实现。#define RSSI_WINDOW_SIZE 8 static int8_t rssi_buf[RSSI_WINDOW_SIZE]; static uint8_t rssi_idx 0; static uint8_t rssi_cnt 0; int8_t rssi_filter(int8_t new_rssi) { rssi_buf[rssi_idx] new_rssi; rssi_idx (rssi_idx 1) % RSSI_WINDOW_SIZE; if (rssi_cnt RSSI_WINDOW_SIZE) rssi_cnt; int16_t sum 0; for (uint8_t i 0; i rssi_cnt; i) { sum rssi_buf[i]; } return (int8_t)(sum / rssi_cnt); }这个函数每收到一个广播包就更新一次返回平滑后的RSSI。用平滑值跟阈值比较比单次值稳得多。注意RSSI是负值比较的时候别搞反了-60比-80强。5.3 连接后持续监控RSSI决定是否断开重连连上不代表一劳永逸。设备可能移动信号可能变差。我一般会在连接状态下定期读一次RSSINRF51822可以用sd_ble_gap_rssi_get获取当前连接的RSSI。如果连续几次低于断开阈值比如-85dBm就主动断开回到扫描状态重新找更强的节点。这个策略在移动场景里特别有用避免抱着一个弱链路死扛。但要注意别频繁断开重连加一个滞回区间比如低于-85断开、高于-75才允许重连中间区域保持现状。5.4 一个容易忽略的细节扫描期间的功耗控制主模式扫描比从机广播更耗电因为接收窗口占空比高。如果设备是电池供电扫描参数要精打细算。我的经验是扫描间隔设200ms、窗口设30ms占空比15%配合RSSI阈值过滤大部分场景够用。如果目标设备广播间隔是100ms那200ms的扫描间隔意味着平均2个广播周期能撞上1次可以接受。真要追求低功耗还可以用sd_ble_gap_scan_start的timeout参数做间歇扫描扫5秒停5秒进一步降功耗。这些参数没有标准答案得根据你的目标设备广播行为和功耗预算去试。我踩过的坑是照搬别人的参数结果自己的设备广播间隔是500ms扫了半分钟没扫到还以为是代码问题。后来把扫描窗口拉长到100ms才解决。所以参数这东西一定要对着自己的实际设备调别迷信任何一组“万能参数”。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

STM32无感BLDC驱动:反电动势过零检测实战指南

STM32无感BLDC驱动:反电动势过零检测实战指南

简介:本资源是一套基于STM32F10x系列(ARM Cortex-M3内核)实现无霍尔传感器BLDC电机控制的完整嵌入式开发例程,面向嵌入式工程师、电机控制初学者及高校电类专业实践者,解决Hall sensorless场景下如何通过反电动势&…

2026/10/16 21:05:29 阅读更多 →
DeepSeek API调用全流程指南:从获取密钥到流式响应与工程封装

DeepSeek API调用全流程指南:从获取密钥到流式响应与工程封装

简介:DeepSeek API调用指南是一份面向软件工程师、科研人员及对AI应用集成感兴趣的技术人员的完整操作手册,系统梳理了从获取API访问权限(包括提交必要信息、等待审核获取密钥)到深入阅读官方接口文档、明确不同接口适用场景、选定…

2026/10/16 21:05:29 阅读更多 →
OpenSolver开源优化插件:Excel中零代码建模求解线性规划

OpenSolver开源优化插件:Excel中零代码建模求解线性规划

简介:OpenSolver 是一款面向运筹学、管理科学与工程优化学习者的开源线性与整数规划求解工具,兼容 Microsoft Excel(Windows/macOS),可替代 Excel 内置规划求解器,支持 Coin-OR CBC、Gurobi 及 NEOS 云平台…

2026/10/16 21:04:28 阅读更多 →

最新新闻

Kali Linux入门指南:虚拟机搭建与渗透测试工具实战

Kali Linux入门指南:虚拟机搭建与渗透测试工具实战

第一次打开 Kali Linux 之前,我以为这会是一个“装上就能扫描一切、破解一切”的神奇系统。真正用了一个月之后,我才意识到它更像一把多功能瑞士军刀——工具非常多,但每把都需要你自己去掌握使用时机和发力方式。这篇文章不是照着官方文档念…

2026/10/17 0:57:13 阅读更多 →
stdint.h与inttypes.h:C语言跨平台整数类型与PRI格式宏完全指南

stdint.h与inttypes.h:C语言跨平台整数类型与PRI格式宏完全指南

简介:这是一份面向 C/C 开发者的标准头文件资源,包含 inttypes.h 与 stdint.h 两个文件,用于解决老旧 MSVC 环境缺少 C99 标准整数类型定义而导致的编译报错。资源来自 msinttypes 项目,整体压缩包仅 7KB,共 3 个文件&…

2026/10/17 0:57:13 阅读更多 →
CTC7132交换芯片设计指南:端口映射、时钟同步与低时延验证

CTC7132交换芯片设计指南:端口映射、时钟同步与低时延验证

简介:这份资源是盛科网络CTC7132(TsingMa)云时代边缘接入路由交换芯片的官方产品手册,面向从事嵌入式硬件、单片机与网络设备开发的工程师,以及需要选型或设计企业网、城域以太网、XGPON/NGPON线卡与超融合设备的研发人…

2026/10/17 0:57:13 阅读更多 →
RayManPro全流程:气象数据如何转成PET热舒适指标

RayManPro全流程:气象数据如何转成PET热舒适指标

简介:RayManPro.zip 是一套基于 RayMan 模型的人体生理等效温度(PET)计算工具,面向城市气候、建筑环境与室外热舒适研究领域的科研人员、规划师及高校相关专业学生。通过输入云量、空气温度、相对湿度、风速等常规气象参数&#x…

2026/10/17 0:57:13 阅读更多 →
几何分布实战:算准“第几次成功”,优化重试与保底机制

几何分布实战:算准“第几次成功”,优化重试与保底机制

不是每一次等待都有结果,但几何分布能算准“第几次成功”做数据分析这些年,我越来越觉得,很多业务问题归根到底都在问三件事:还要试多少次才能成功?失败到第几个才算正常?这个“第一次成功”到底值不值得等…

2026/10/17 0:57:13 阅读更多 →
车辆路径问题(VRP)详解:约束模型、求解算法与实战应用

车辆路径问题(VRP)详解:约束模型、求解算法与实战应用

1. VRP到底在解决什么:从一个真实的配送场景说起先提个场景,你大概率遇到过:某社区团购平台每天有上百个订单要送到不同小区,每辆配送车的载重有限,司机的工作时长也有限,怎么安排路线才能让总行驶里程最短…

2026/10/17 0:56:12 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →