上周一个做蓝牙小家电的兄弟半夜发消息问我手头有两块杰理63系列的开发板想做一个主从连接一块板子采集传感器数据往另一块传结果照着文档折腾了两天就是连不上。我太理解这种状态了——杰理的SDK资料版本多、命名乱官方文档又经常写得像给内部人看的真正碰到主从连接和透传踩坑的点一个比一个隐蔽。这篇文章就把我从选型、配置到跑通数据收发、再到排查问题的完整过程写下来给后面做杰理63系列AC692x、AC695x这几个常用型号双设备主从透传的兄弟当个参考帮你少熬两个通宵。1. 上手前先想清楚63系列的主从到底有哪些玩法1.1 这个系列芯片的定位杰理63系列在市面上最常见的几颗料是AC6925A、AC6926A、AC6928A蓝牙4.2双模以及AC6955A、AC6956A、AC69568这颗蓝牙5.1双模。不同型号在内核、Flash、RAM和协议栈版本上差别不小但主从连接和透传的应用思路是贯通的。做产品选型时如果只做低功耗数据采集优先选BLE资源友好的型号如果还要兼顾音频A2DP/HFP就必须上双模芯片AC6928A就经常被拿来做蓝牙伴音数据透传一个片子同时干两件事。很多刚接触的人以为杰理只能做蓝牙音箱和耳机其实它的串口透传方案在工控、医疗小设备、玩具遥控、数据采集模块里出货量非常大。原因很简单成本够低、外围电路简单、SDK虽然文档乱但该有的API都有。主从双设备传输数据本质上就是把两颗芯片分别配成主机和从机然后通过标准蓝牙协议把数据从一端搬到另一端。1.2 别把主从连接和TWS搞混这里必须先纠正一个最常见的误解很多人把主从和TWS左右耳互联混为一谈。TWS是两颗同型号芯片用私有2.4G互联同步播放音频走的是杰理内部的TWS私有协议不是标准蓝牙。而我们说的双设备主从连接传输数据是标准的蓝牙主从关系——一台设备做Central主机、中心设备负责扫描和发起连接另一台做Peripheral从机、外设负责广播并等待连接。数据通过SPP或BLE GATT通道传输和手机连接一个蓝牙模块的原理完全一样。这样区分清楚之后你的整体设计思路就不会跑偏不需要研究TWS配对那套私有命令只需要按照标准蓝牙协议栈的节奏来配置角色、配置服务、处理回调、收发数据。1.3 主从玩法取决于你要传什么同样是主从连接传输的数据类型决定了你走哪条链路传感器状态类数据量小、频率低几十到几百字节一跳用BLE GATT的Notify就够省电是第一优先级。串口透传类要模拟有线UART做双向数据通路不定长、连续、吞吐要求高用SPP最省事丢包和延迟都好控制。音频数据混合必须走经典蓝牙连接SPP承载数据A2DP承载音频这种场景下芯片选型就要主动往双模高配置上靠。所以动手配置之前先把传什么、多大包、多频繁、功耗要求、要不要同时出声这几个问题写下来后面每一步配置都有了依据不会反复推翻重来。2. 数据走哪条链路SPP与BLE的取舍2.1 经典蓝牙SPP适合的场景SPP对应经典蓝牙的RFCOMM层从使用者的视角看它就是一根无线串口线。在杰理SDK里打开SPP选项之后从机对外暴露一个标准蓝牙串口服务主机侧无论是手机还是另一块杰理板子连接成功之后就能像读写串口一样收发数据。SPP有几个特点很关键。第一它要求配对绑定连接的时候会触发配对流程默认PIN码一般是1234或0000这个在板级配置里能改第二它建立连接之后是长时间占用的功耗比BLE高一个量级不太适合纽扣电池方案第三它的吞吐和稳定性在同等条件下比BLE更好我用AC6928A实测SPP单向传输稳定在20~60KB/s之间延迟大约10~30ms这取决于UART波特率、协议栈缓冲区大小和连接质量。如果做的是蓝牙转串口这种模块类产品SPP是首选。2.2 BLE GATT适合的场景BLE走的是GATT服务模型你需要自定义一个Service服务里面放Write、Notify、Read三种Characteristic。主机发给从机用Write从机主动上报用Notify主机主动拉取用Read。杰理SDK里默认会有一个自定义服务初学阶段建议直接用官方Demo里的UUID把服务跑通了再改成业务专用UUID。BLE的优点是功耗低、连接参数灵活、支持广播和扫描的高效发现机制代价是单包长度短、throughput没有想象中高。默认MTU只有23字节刨掉ATT头实际有效载荷更少需要协商MTU才能传稍大的包。我实测在7.5ms连接间隔下BLE GATT的稳定吞吐在8~15KB/s之间对传感器数据、控制指令这类小包高频业务完全够用但别指望用它推文件。2.3 一主一从、一主多从和连接表主从拓扑上我建议按下面这个原则选一主一从最简单两边资源压力都小适合大多数透传场景。一主二从一个主机维护两条连接两条连接都处于活跃状态主机的内存开销明显上升老型号AC692x系列会比较吃力AC695x系列相对从容。双主机连一个从机从机要同时被两个中心设备连接这要求协议栈支持多连接和合理的调度老款63系列基本不用想新一点的型号也要实测内存占用。连接表这个概念很多人忽略。芯片能同时保持几条蓝牙连接是协议栈在编译时就分配好的不是想连几台就连几台。配置工具里如果没找到连接数目的选项那多半是SDK写死的改代码前先去翻协议栈配置头文件里的宏定义。对比项SPPBLE GATT底层通道经典蓝牙RFCOMM低功耗蓝牙ATT/GATT功耗较高低传输速率实测约20~60KB/s约8~15KB/s延迟10~30ms连接间隔相关通常20ms内连接前是否配对需要可选承载数据特点不定长、连续、大流量小包、低频、状态类典型场景串口透传模块传感器上报、遥控3. 工程配置实操从SDK到协议栈开关3.1 SDK目录里需要关心的几个地方拿到杰理官方的SDKAC692x或AC695x之后不要一上来就全局搜索代码先认目录。以我常用的SDK版本为例主要关心四块apps/应用层代码我们的业务逻辑基本都写在这里。include/协议栈对外暴露的头文件想找API先来这儿搜。board/板级配置涉及引脚复用、时钟、外设初始化。tool/烧录和调试工具以及一些PC端小软件。很多问题其实是配置没生效而不是代码写错了。杰理这套代码的配置分散在好几个地方板级头文件里是引脚和资源应用头文件里是功能开关工具生成的文件里是蓝牙协议栈参数。改一处而不同步其他位置就会出现编译能过但行为不对的诡异现象。3.2 用配置工具生成板级配置杰理官方提供蓝牙配置工具不同SDK版本里的名字不太一样常见的是蓝牙配置工具或BT Setting Tool它的作用是生成一份协议栈参数文件编译时会合并进固件里。需要重点确认的配置项有这几个蓝牙名称从机的广播名调试阶段建议改成有辨识度的名字避免和周围设备混淆。Profile开关勾选SPP、BLE或者SPPBLE同时开。BLE服务的Service UUID和Characteristic UUID先用官方默认值后面再改成产品自定义的。主机角色是否开启注意不是所有SDK版本都默认开放Central角色有些版本需要额外的宏或配置项。配对方式、PIN码、安全等级SPP场景下一般选Just Works或固定PIN。配置完成后生成文件替换进工程对应位置然后重新编译烧录。这步很多新手容易漏——改了工具不生成、生成了不替换、替换了不重新编译最后来问为什么没变化。建议每次改完配置都确认生成文件的修改时间确保真的更新了。3.3 主从角色相关的宏开关以我接触过的SDK版本为例应用配置里会看到类似下面这些宏#define CONFIG_BT_SPP_ENABLE 1 // 打开SPP #define CONFIG_BT_BLE_ENABLE 1 // 打开BLE #define CONFIG_BT_MASTER_ENABLE 1 // 打开主机角色 #define CONFIG_BT_SLAVE_ENABLE 1 // 打开从机角色这里面有一个非常关键的注意点同时打开主机和从机角色协议栈占用的RAM会比单角色多出一大截。老型号AC692x系列Flash和RAM本来就紧张主从同时开之后编出来的固件很容易超资源表现就是链接时报告内存溢出或者编译报错。我见过有人为了一主一从硬上双角色结果是程序跑起来不稳定、连接后随机死机。如果只是双设备互传建议一台刷主机版本、一台刷从机版本双方宏定义不同烧录不同的固件这样资源压力最小问题也最好定位。编译烧录之后先用手机上的蓝牙调试工具nRF Connect或LightBlue都行验证从机能搜到广播、能连上、能看到服务列表和Characteristic。这一步能快速过滤掉一大半配置没生效的问题。手机验证通过了再上双设备联调否则两边都是黑盒出了问题根本不知道是谁的错。3.4 烧录验证与串口日志杰理的下载工具通过UART或USB接口下载固件烧录前确认板子的BOOT引脚状态正确不要用错串口这个环节最常见的错误是下载工具报连接失败十有八九是BOOT模式没进对。下载完成后开启SDK的打印日志功能把协议栈事件打出来连接、断连、收发数据都会有日志输出。这条日志会贯穿整个调试过程是排查问题最重要的信息来源。4. 代码层面实现主从连接与数据收发4.1 从机端的初始化与事件处理从机代码的核心是广播 事件回调。初始化阶段设置广播参数、注册回调之后的事都由协议栈事件驱动。以我用的SDK版本为参考从机初始化大致是这样// 从机初始化 void app_ble_slave_init(void) { // 设置广播参数设备名称、广播间隔、广播内容 // 打开广播 // 注册连接/断连/数据接收回调 }事件回调里重点处理三个事件连接成功、断连、收到数据。static void ble_slave_event(u16 opcode, u8 *buf, u16 len) { switch (opcode) { case BLE_SLAVE_CONNECTED: // 连接成功此时可以关闭广播省电也准备好收发缓冲 break; case BLE_SLAVE_DISCONNECTED: // 断线了重新打开广播进入可被发现状态 break; case BLE_SLAVE_RECIVE_DATA: // 主机下发数据buf为数据指针len为长度 handle_rx_data(buf, len); break; } }这里有个经验收到数据之后不要在回调里直接做耗时的处理比如写Flash、开文件、长时间循环回调函数是跑在协议栈上下文里的占用太久会导致蓝牙协议栈喂狗不及时或丢包。正确做法是拷到自己的缓冲区交给应用任务去处理。4.2 主机端的扫描、连接和服务发现主机端代码比从机多一个找设备的阶段。流程是开启扫描、扫描回调里匹配目标设备名或MAC地址、停止扫描、发起连接、连接成功后做服务发现、找到Notify特征后订阅通知。void app_ble_master_start_scan(void) { // 开启扫描设置扫描窗口和扫描间隔 // 扫描结果在回调里处理匹配到目标设备后停止扫描并发起连接 }服务发现是很多新手容易卡住的地方。BLE的GATT服务不是连接建立就自动暴露给主机的主机必须显式地遍历从机的Service、Characteristic、Descriptor找到自己关心的UUID然后才能收发数据。这一步如果没做后面调用发送接口一定会失败或没反应。建议在日志里把发现到的服务和Characteristic UUID全部打印出来确认和从机配置工具里设置的一致。4.3 数据收发的完整闭环与实际接口把收发接口按用途封装一下业务层就好写了。从机向上发数据// BLE Notify方式发送单包不要超过MTU-3字节 ble_slave_send_data(buf, len); // 如果是SPP通道 spp_send_data(buf, len);主机向下发数据// 往已连接的从机写数据 app_ble_client_write(conn_handle, buf, len);主机订阅从机的Notify之后从机调用的发送接口会触发主机的接收回调数据在回调里同样拷贝出来。实际项目里最常见的形态是做UART透传桥MCU的串口收到数据转发到蓝牙通道发出去蓝牙通道收到的数据从串口发出去。这种桥接逻辑很好写但要注意缓冲区设计——串口的速率可能比蓝牙通道快如果你在串口中断里直接调用蓝牙发送接口数据量一大就会出现发送失败原因是协议栈内部缓冲满了。我建议维护一个环形缓冲区串口中断只往环形缓冲区里塞数据应用层定期取出并调用蓝牙发送接口。// 伪代码串口数据进环形缓冲应用层发蓝牙 void uart_rx_isr(u8 byte) { ring_buf_push(tx_ring, byte); } void app_task_loop(void) { u8 tmp[128]; u16 len ring_buf_pop(tx_ring, tmp, sizeof(tmp)); if (len 0) { ble_slave_send_data(tmp, len); } }这个缓冲任务发的模式能避免绝大多数丢包和发送失败问题不管是SPP还是BLE都适用。5. 实测参数与排坑记录5.1 我实测的吞吐和延迟不同SDK版本、不同连接参数实测数据差异不小但可以给你一个参考范围。我在AC6928A双板主从SPP透传场景下测试UART波特率115200单向连续发送稳定吞吐约45KB/s基本跑满了SPP的上限。换成BLE GATT、连接间隔7.5ms、MTU协商到247字节单向吞吐大约12KB/s。延迟方面SPP从发出到对端接收约15ms左右BLE大约在10~20ms之间浮动。如果你测出来的数值比这个低很多先检查是不是UART波特率配错了或者发送端是不是一包一包等确认这会让实际速率大打折扣。5.2 排查问题要按链路走别瞎试我把自己经常遇到的几个问题和排查顺序整理成下面这个表遇到问题先按链路一层层查效率比随机改参数高得多。现象排查链路常见根因主机扫描不到从机广播开关→广播名→广播间隔→MAC过滤→硬件天线从机没开广播、配置工具没重新生成、天线匹配差连接后几秒就断配对流程→安全等级→连接超时参数→看门狗配对未完成、交互超时太短、回调里耗时操作能连上但收不到数据MTU协商→Notify订阅→UUID匹配→缓冲区主机没有订阅Notify、服务UUID不一致发送接口返回失败连接句柄→协议栈发送缓冲→单包长度连接还没建立就发数据、单包超MTU一拖二连第二个就掉线连接表数量→剩余RAM→扫描是否停止内存不足、连接参数配置过于激进这里面有几个特别容易被忽略的坑。第一个是蓝牙天线匹配我在调试时遇到过两次扫描不到设备最后发现是板载天线焊盘虚焊信号强度太低手机能搜到但另一块杰理板子搜不到因为板载天线的灵敏度本身就不高。这种情况用仪器测一下RSSI就明白了。第二个是配对缓存如果从机里存了旧的主机Link Key主机换了设备或重刷固件后连接会异常解决办法是把从机的配对信息清掉或者在做开发调试时直接关闭绑定存储。5.3 几条能省下大把时间的经验最后分享几条我反复用到的实操经验。第一先把两端固件都编译成手机可调试的模式。从机用手机连主机也用手机模拟连接。两边分别通了再把两块板子放在一起联调这样每个环节出问题都清楚是哪端的事。第二SDK里自带的Demo一定要先原样烧录跑通再改你的业务逻辑。很多问题是你改代码引入的不是配置问题。跑通官方Demo之后再逐步加自己的代码出错了也容易二分定位。第三所有配置文件和生成的代码记得纳入版本管理并在发布前用对比工具确认当前工程用的参数和你以为的一致。杰理的SDK版本更新频繁网上找到的教程和你的SDK很可能对不上函数名、宏定义、配置工具界面都不一样不要照搬硬抄。以你自己SDK包里的Demo为准把API名字查清楚再动手。第四调试透传功能时建议先跑一个固定格式的心跳包或计数值程序比如从机每秒向主机发一次递增数据主机串口打印出来。这样链路是否通、延迟是否正常一眼就能看出来比上来就传真实业务数据好定位得多。链路通了再挂真实业务问题范围一下就能缩小。这块内容我后续还会接着整理杰理BLE配网、OTA升级和低功耗唤醒的实测记录等新板子到了继续填坑。