ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PHY6252 BLE串口透传实战:从GATT服务到环形缓冲的工程实现

PHY6252 BLE串口透传实战:从GATT服务到环形缓冲的工程实现 1. 为什么选择 PHY6252 做 BLE 串口透传1.1 这个项目到底在做什么BLE 串口透传说白了就是把蓝牙低功耗的无线链路当成一根看不见的串口线来用。单片机这边往 UART 里丢什么字节对端手机 App、另一个模块、上位机就能原样收到什么字节反过来也一样。它不关心你传的是传感器数据、控制指令还是调试日志只负责把数据从 A 搬到 B。这个需求在工业现场、智能家居、医疗设备里非常普遍。很多老设备只有 UART 口想让它无线上云或者手机可控最省事的做法就是挂一个 BLE 模块做透传主控代码几乎不用改。PHY6252 是奉加微PHYPLUS推出的一颗 BLE SoC内核是 Cortex-M0片上集成了 BLE 5.0 射频、Flash、RAM 和丰富的外设。它在这类透传场景里受欢迎的原因很直接单芯片方案不需要外挂 MCU成本低SDK 里自带串口透传的参考例程改改就能用。相比 nRF52840 这类高端方案PHY6252 的定位更偏够用就好做透传这种轻量任务绰绰有余。适合读这篇的人有 C 语言和单片机基础、用过 Keil、想快速把 BLE 透传跑起来的嵌入式工程师也适合刚接触 BLE 协议栈、想找一个完整项目练手的朋友。如果你连 UART 中断都没写过建议先把串口收发啃明白再回来。1.2 透传方案的核心取舍做 BLE 透传绕不开一个关键选择用现成的 AT 指令模块还是自己基于 SDK 开发AT 指令模块市面上很多串口蓝牙模块上手极快发几条指令配好名字、UUID、波特率就能用。但它的坑也很明显透传速率受限于模块固件的缓冲策略遇到突发大数据容易丢包想改协议、加自定义服务基本没戏批量出货时每颗模块的固件版本还可能不一致。自己基于 PHY6252 SDK 开发前期投入大一些但换来的是完全可控缓冲区大小自己定连接参数自己调功耗自己优化还能在透传基础上叠加自己的私有协议。对于要量产或者有定制需求的项目这条路更稳。我个人的判断标准是验证阶段用 AT 模块快速出原型量产阶段切到 SDK 自研。这篇博文讲的是后者因为透传看着简单真要做到不丢包、低延迟、断线能自恢复里面的细节比想象中多。1.3 整体架构长什么样PHY6252 的透传应用本质上是三个模块在协作UART 驱动层负责和外部主控或 PC 通信通常用中断或 DMA 收发配一个环形缓冲区。BLE 协议栈层SDK 提供的协议栈管理广播、连接、GATT 服务。透传一般用一个自定义的 GATT 服务里面放两个特征值——一个用于手机写数据Write一个用于模块通知数据Notify。数据搬运层这是透传的灵魂。它监听 UART 收到数据的事件把数据打包成 BLE 通知发出去同时监听 BLE 写入事件把数据从 GATT 特征值里取出来塞进 UART 发送缓冲。数据流是这样的外部设备 → UART RX → 环形缓冲 → BLE Notify → 手机手机 → BLE Write → 环形缓冲 → UART TX → 外部设备。两个方向独立互不阻塞。注意透传最容易出问题的地方就是搬运层的缓冲管理。UART 和 BLE 的速率不匹配是常态没有缓冲就会丢数据。2. 开发环境搭建与工程准备2.1 Keil 环境与 SDK 获取PHY6252 官方推荐用 Keil MDK 开发。我实测下来Keil MDK 5.36 以上版本比较稳太老的版本对 ARM Compiler 6 支持不好编译协议栈容易报错。安装 Keil 有几个点要提醒装完主程序后一定要通过 Pack Installer 安装ARM::CMSIS和对应的Device Family Pack。PHY6252 的 DFP 包在 SDK 里通常会附带双击安装即可。编译器选ARM Compiler 6AC6SDK 里的工程默认配置就是 AC6。如果你手贱切成 AC5可能会遇到一堆__asm语法报错。关于注册问题正版授权自己解决这里不展开。用评估版编译小工程也够用只是有 32KB 代码限制透传工程一般能压进去。SDK 从奉加微官网或官方提供的渠道获取解压后目录结构大致是PHY6252_SDK/ ├── components/ # 协议栈、驱动、中间件 ├── examples/ # 参考例程重点看 uart_ble 相关 ├── projects/ # Keil 工程文件 └── tools/ # 烧录、量产工具先别急着改代码把examples里跟串口透传最接近的例程编译一遍确认工具链没问题再动手改。这一步能帮你排除 80% 的环境问题。2.2 工程目录与关键文件打开透传例程的 Keil 工程后你会看到几个关键文件理解它们的分工很重要文件作用改动频率main.c初始化、主循环中uart_driver.cUART 收发与缓冲高ble_service.cGATT 服务定义高app_task.c数据搬运逻辑高phy_config.h射频、时钟配置低我的习惯是尽量不动协议栈和驱动的底层文件所有业务逻辑集中在app_task.c和自定义的服务文件里。这样 SDK 升级时重新合并代码的工作量最小。2.3 编译配置的几个坑工程配置里有两个地方必须检查Target 选项卡里的 Flash 和 RAM 地址。PHY6252 的协议栈会占用一部分 RAM如果链接脚本里的 RAM 起始地址和协议栈冲突程序跑起来会莫名其妙死机。SDK 默认配置一般是对的但如果你加了大的全局数组要留意 RAM 是否溢出。C/C 选项卡里的宏定义。透传相关的宏比如BLE_UART_TRANSFER_ENABLE要打开否则编译出来的固件没有透传功能。这个坑我踩过——代码明明写了就是不工作最后发现宏没开。提示编译后一定要看 map 文件里的 RAM 占用。如果接近上限把不用的缓冲数组调小或者把大数组放到 Flash 里用const修饰。3. BLE 服务与串口透传核心实现3.1 GATT 服务怎么设计透传服务的 GATT 结构我一般这样设计Service UUID自定义一个 128 位 UUID别用标准 UUID避免和系统服务冲突。RX 特征值手机 → 模块属性为 Write 或 Write Without Response。用 Write Without Response 延迟更低但没确认机制用 Write 有确认更可靠。透传场景我推荐Write Without Response 应用层校验兼顾速度和可靠。TX 特征值模块 → 手机属性为 Notify。手机端要主动打开通知写 CCCD 描述符否则收不到数据。这里有个新手常犯的错误忘了处理 CCCD。手机打开通知时会往 CCCD 写0x0001模块必须响应这个写操作并记住这个客户端要收通知。如果没处理Notify 发出去手机也收不到。3.2 UART 环形缓冲的实现环形缓冲是透传不丢包的关键。核心思路读写指针各自移动写满就丢最老的数据或返回错误。#define UART_BUF_SIZE 512 typedef struct { uint8_t buf[UART_BUF_SIZE]; volatile uint16_t head; // 写指针 volatile uint16_t tail; // 读指针 } ring_buf_t; static ring_buf_t uart_rx_buf; // 中断里调用写入一个字节 void ring_buf_put(ring_buf_t *rb, uint8_t data) { uint16_t next (rb-head 1) % UART_BUF_SIZE; if (next rb-tail) { // 缓冲满丢弃最老数据也可选择丢弃新数据 rb-tail (rb-tail 1) % UART_BUF_SIZE; } rb-buf[rb-head] data; rb-head next; } // 主循环里调用读取一个字节 bool ring_buf_get(ring_buf_t *rb, uint8_t *data) { if (rb-head rb-tail) return false; *data rb-buf[rb-tail]; rb-tail (rb-tail 1) % UART_BUF_SIZE; return true; }head和tail用volatile修饰因为它们在中断和主循环里都被访问。缓冲大小 512 字节是我在多数场景下的经验值——太小容易丢包太大占 RAM。如果你的数据突发量很大可以调到 1KB 甚至 2KB但要盯着 RAM 占用。3.3 数据搬运逻辑搬运逻辑分两个方向我建议都放在主循环里轮询而不是在中断里直接发 BLE。原因很简单BLE 协议栈的 API 大多不是中断安全的在中断里调用容易出玄学问题。UART → BLE 方向void uart_to_ble_task(void) { uint8_t data; uint8_t packet[20]; uint8_t len 0; // 攒够一包或缓冲空了就发 while (ring_buf_get(uart_rx_buf, data)) { packet[len] data; if (len 20) break; // 默认 MTU 23有效载荷 20 } if (len 0) { ble_notify_send(packet, len); } }这里 20 字节是默认 ATT MTU 23 减去 3 字节头的结果。如果你协商了更大的 MTU比如 247可以一次发更多吞吐量能提升好几倍。BLE → UART 方向在 GATT 写回调里把收到的数据塞进 UART 发送缓冲然后触发发送。注意回调里不要做耗时操作尽快返回。void on_ble_write(uint8_t *data, uint16_t len) { for (uint16_t i 0; i len; i) { uart_tx_put(data[i]); // 塞进发送环形缓冲 } uart_start_tx(); // 触发发送 }3.4 连接参数与吞吐量调优BLE 的吞吐量受连接参数影响很大。默认连接间隔可能是 30ms 甚至更长意味着每 30ms 才能发一次数据透传延迟会很明显。关键参数Connection Interval连接间隔越小延迟越低但功耗越高。透传场景我一般设15ms 到 30ms。MTU最大传输单元。默认 23协商到 247 后单包能发 244 字节吞吐量提升近 10 倍。Data Length ExtensionBLE 4.2 以上的特性把单包有效载荷从 27 字节提到 251 字节。实测下来MTU 协商到 247、连接间隔 15ms 的情况下PHY6252 的透传吞吐能做到几十 KB/s足够大多数传感器和控制场景。注意连接参数是手机端主导的模块只能建议。iOS 对连接间隔有严格限制最小 15msAndroid 相对宽松。做产品时要按最严格的平台来设计。4. 调试、抓包与常见问题排查4.1 用 Keil 调试透传逻辑Keil 的调试器是排查问题的利器。几个实用技巧看结构体变量在 Watch 窗口里输入变量名展开就能看成员。如果显示cannot evaluate检查优化等级——调试时把优化设为 -O0否则变量可能被优化掉。看堆栈是否溢出在调试模式下打开 Call Stack 窗口或者看 SP 寄存器的值是否接近 RAM 起始地址。堆栈溢出是 M0 上很隐蔽的 bug表现是随机死机。断点别打在中断里在 UART 中断里打断点会导致中断频繁触发时程序卡死。要看中断数据用变量记录 主循环里观察。4.2 抓包分析 BLE 交互光看代码不够BLE 的问题很多时候在空口。用支持 BLE 的抓包工具配合专用嗅探硬件抓一次完整交互能看到广播包内容对不对名字、UUID连接建立后手机有没有写 CCCDNotify 有没有真正发出去连接参数协商成了多少我遇到过一个经典问题手机能连上但收不到数据。抓包一看手机压根没写 CCCDNotify 自然发不出去。这种问题看代码看不出来抓包一眼就明白。4.3 常见问题速查表现象可能原因排查方向手机搜不到设备广播没开 / 广播数据错检查广播配置和天线能连上但收不到数据CCCD 没处理 / Notify 没使能抓包看 CCCD 写操作数据丢包缓冲太小 / 速率不匹配加大环形缓冲降速连接频繁断开连接参数不合理 / 供电不稳调连接间隔查电源编译报错编译器版本 / 宏没开切 AC6检查宏定义程序随机死机RAM 溢出 / 堆栈溢出看 map 文件调大堆栈4.4 几个我踩过的坑坑一UART 波特率太高导致丢包。一开始我用 921600结果丢包严重。后来发现是中断处理太慢改成 DMA 收发才稳。如果主频不高波特率别贪高115200 是稳妥选择。坑二Notify 发太快被协议栈拒绝。BLE 协议栈的发送缓冲有限连续快速调用 Notify 会返回缓冲满。正确做法是等上一个 Notify 的完成回调再发下一个或者用流控。坑三断线后没重新广播。透传设备断线后必须重新开始广播否则手机再也连不上。这个逻辑要写在断开连接的回调里。坑四低功耗模式下 UART 收不到数据。如果开了睡眠UART 的时钟可能被关掉。要么用 UART 唤醒要么在透传期间保持唤醒。5. 进阶优化与量产考虑5.1 低功耗优化如果设备是电池供电功耗就是命门。几个方向拉长广播间隔从 100ms 拉到 500ms 甚至 1s广播功耗大幅下降。连接间隔按需调整空闲时用大间隔有数据传输时临时请求小间隔。UART 空闲时关时钟没有数据时把 UART 外设关掉有起始位再唤醒。PHY6252 的睡眠电流能做到微安级但前提是所有外设都正确进入低功耗状态。这个要结合具体硬件测别只看手册数字。5.2 量产烧录与固件升级量产阶段烧录效率和一致性很重要。PHY6252 支持批量烧录工具可以一次烧多颗。固件版本管理建议每版固件打上版本号存在 Flash 固定地址。手机 App 连接后先读版本号方便售后排查。如果要做 OTASDK 里一般有参考实现但 OTA 会占用额外 Flash要提前规划分区。5.3 稳定性压测产品出厂前透传一定要做压测长时间连接测试连续跑 24 小时以上看会不会断线。大数据量测试持续高速传输看丢包率和缓冲表现。异常场景测试传输中突然断电、突然远离、手机杀进程看恢复能力。我见过太多实验室里好好的现场就出问题的案例压测这一步省不得。5.4 后续可以扩展的方向透传跑通只是起点。基于这套框架还能做很多事在透传数据里加自定义协议头实现多通道复用结合 IAP 做固件升级把透传和本地传感器采集结合做成一个完整的采集节点。PHY6252 的资源和外设支撑这些扩展都没问题。我个人在实际项目里的体会是透传这种看起来简单的需求真正决定成败的往往不是 BLE 协议本身而是缓冲管理、异常恢复和功耗控制这些工程细节。把这几块打磨好产品才站得住。
返回列表