E104-BT02蓝牙模块深度开发:从透传Demo到GATT与低功耗量产实战
2026/9/6 6:16:19 网站建设 项目流程

E104-BT02这块模块在圈子里不算冷门,很多做物联网、工控、智能家居的工程师都摸过。但大多数人的印象还停留在“它是一块能透传的蓝牙模块”,拿串口一连、AT指令一配就开始跑数据。说实话,这用法也没错,但有点浪费这块板子。E104-BT02用的是国产BLE SoC,芯片型号我就不绕弯子了,是PHY6212,Cortex-M0内核,BLE 5.2协议栈,最关键的是它把射频匹配、晶振这些外围电路都集成好了,你不需要懂射频也能做出通信距离稳定、功耗可控的产品。这次我把完整的开源电路和驱动代码思路梳理一遍,从硬件连接到GATT服务搭建,再到广播参数调优和绑定(Bond)机制处理,尽量让你照着做就能跑起来,而不是停留在调通Demo的层面。

1. E104-BT02到底解决什么问题:从选型逻辑说起

1.1 为什么不是ESP32-C3,也不是NRF52832

先聊点选型的心路历程。很多新手一上来就想用ESP32-C3,毕竟资料多、社区活跃,Arduino生态也成熟。但在实际量产项目里,ESP32-C3有几个问题比较扎手:第一是功耗,WiFi蓝牙双模的底子摆在那,深度睡眠做到几个微安是没问题,但射频收发时的峰值电流还是偏高,对电池供电的传感器类产品不够友好;第二是体积,ESP32-C3模组再小也要做天线匹配区,PCB面积省不下来;第三是成本,虽然ESP32已经很便宜了,但在一些大批量、功能极其单一的场景(比如只传一个温度值),用C3还是显得“杀鸡用牛刀”。

NRF52832是好东西,协议栈成熟、文档完善,开发体验在BLE芯片里属于第一梯队。但它的价格和供货稳定性在近两年波动比较大,而且对于只需要串口透传或简单GATT服务的项目,NRF的开发门槛和授权成本会让小团队犹豫。

E104-BT02这种模组的定位恰恰卡在中间:它把PHY6212这颗芯片的射频前端、晶振、天线匹配全部封装好了,用户只管供电和串口。PHY6212的公开资料相比Nordic少很多,但E104把AT指令固件和二次开发SDK都开放出来了,等于帮你把最麻烦的射频和协议栈部分先趟平了。这也是我选择它的核心原因:不是因为它最强,而是因为它在“够用、便宜、省事”这个三角上做到了一个很舒服的平衡。

1.2 模块硬件资源盘点:哪些引脚真正用得上

E104-BT02的引脚不多,但每个引脚都有讲究。我直接画一下实际项目的典型接法:

  • VCC:1.8V-3.6V,典型3.3V,注意纹波要控制在100mV以内。BLE射频对电源噪声比较敏感,电源脏了直接表现就是通信距离缩短、连接不稳定,甚至广播包发不出去。
  • GND:不用多说,但我建议模块下方铺完整地平面,不要走线割裂。
  • TXD/RXD:串口透传用的UART引脚,接MCU的RXD/TXD,注意交叉连接。电平是3.3V,如果需要和5V单片机通信,要加电平转换,直接连会烧引脚。
  • P00/P01/P02/P03:这4个是GPIO,可以做普通输入输出,也可以复用为I2C、SPI、ADC。实际项目里我一般用两个脚做状态指示(连接状态、广播状态),一个脚做按键唤醒。
  • SWS:烧录引脚,接PHY6212的SWD调试口,开发阶段会用到,量产时可以空着。

有个细节容易踩坑:模块的RXD引脚内部有上拉,但TXD是推挽输出,配置外部MCU串口时不要两边都开内部上拉,否则空闲电平可能出现异常,导致乱码。另外,模块上电后默认是AT指令模式,串口波特率115200,8N1。如果你在PCB上还挂了别的外设,要注意这个串口不能再复用给其他功能,不然调试的时候会互相抢数据。

1.3 开源电路的价值:把你的底板图纸补齐

标题里说“开源电路”,实际指的是E104-BT02模组的参考设计和底板电路可以一并拿到。对于新手来说,这个价值非常大,因为你不需要自己去算天线阻抗、不需要去copy射频走线,照着模块手册的推荐电路把底板画出来就行。

参考设计里几个关键点:

  • 退耦电容:VCC引脚旁边放两个电容,一个10uF钽电容(或陶瓷)滤低频,一个100nF陶瓷电容滤高频,尽量靠近引脚。
  • 天线净空区:模块自带板载天线,底板在对应区域要掏空铜皮,天线下方投影区域不能走地线、不能铺铜,否则天线被拉偏,谐振频率跑掉,通信距离直接砍半。
  • 复位电路:模块没有专门的复位引脚,上电复位是靠内部POR实现的,所以你只要保证上电时间满足要求就行。有些工程师习惯用MCU GPIO控制模块电源来实现软复位,这个方案可行,但注意模块电源切换瞬间的毛刺可能导致偶发死机。

这块参考资料我建议你直接去E104-BT02的官方wiki下载,里面有原理图PDF和PCB封装库,省掉自己画封装的时间。实际打板回来的经验是:严格按照参考设计画,一次就能通,别自己发挥改天线区域走线。

2. 上手最快的路径:串口透传模式下的Demo搭建

2.1 硬件连接与AT指令初始化

拿到模块后,最快跑通的方案就是透传模式,不需要写任何嵌入式代码,只需要一个USB转TTL工具和PC端的串口助手。

连接方式:

  • 模块VCC接3.3V,GND接GND
  • 模块RXD接USB转TTL的TXD
  • 模块TXD接USB转TTL的RXD

打开串口助手,波特率115200,发送AT,如果模块返回OK,说明通信正常。这里有个小坑:市面上很多USB转TTL模块的TXD/RXD电平是5V的,E104-BT02的引脚不兼容5V,会烧模块。最好是找支持3.3V电平的转换器,比如CP2102、CH340的3.3V版本,或者串一个1K电阻限流求个平安。

接下来的AT指令按这个顺序走一遍:

AT+RST // 软复位模块 AT+NAME=MyDevice // 设置广播名称,最长不超过20字节 AT+MAC=112233445566 // 自定义MAC地址(可选,部分版本支持) AT+UART=115200,8,1,0 // 配置串口参数:波特率、数据位、停止位、校验位 AT+ROLE=0 // 0表示从机(Peripheral),1表示主机(Central) AT+ADVINTER=50 // 广播间隔,单位0.625ms,50=31.25ms AT+PWR=0 // 发射功率,0为最高档 AT+RESET // 保存参数并重启

配置完这组参数后,模块会以你设定的广播名开始广播。用手机上的BLE调试助手(比如nRF Connect或者LightBlue)扫描,能看到一个叫"MyDevice"的设备,直接连接,然后启用Notify和Write特征值,就能实现手机和模块之间的双向透传。

2.2 手机端透传测试:一个完整的收发闭环

BLE调试助手连上模块后,界面里会列出服务列表。E104-BT02的默认透传服务UUID通常是FFF0,其中写特征值UUID是FFF1,通知特征值UUID是FFF2(不同固件版本可能有差异,以实际扫描到的为准)。

测试步骤:

  1. 订阅通知:点击FFF2后面的Notify图标,让手机开始接收模块上行数据。
  2. 手机发送:在FFF1里写入字符串(比如"hello"),模块的串口TXD会立刻输出这5个字节。
  3. 模块上行:在串口助手里发送任意数据,手机端FFF2会实时收到。

这里有个容易踩的坑:模块默认可能有透传分包机制,一次写入超过MTU大小的数据会被拆分成多包发送。如果你想验证实时性,建议先用短数据测试。后面我会专门讲MTU协商的问题。

2.3 为什么说透传模式是“够用就好”的起点

很多工程师把透传模式当成最终方案一直用下去,这在多数场景下没问题——数据量小、实时性要求不那么极端、不需要复杂的安全机制。但透传模式有两个先天短板:

第一,数据格式没有约束。透传就是管道,你往里面灌什么对方就收到什么。如果产品需要对接不同的手机App、不同的上位机协议,管道的灵活性反而变成负担,因为协议解析全得自己在应用层做。

第二,连接参数是固件里写死的。比如连接间隔、从机延迟、超时时间,这些参数直接影响功耗和实时性的平衡。透传固件给你的是“通用配置”,但如果你的产品是低功耗传感器,希望连接间隔拉长到100ms以上来省电,透传固件就很难满足。

所以我的建议是:透传模式用来验证硬件、验证通信链路,非常合适,但产品化阶段最好还是基于SDK做二次开发。这样你才能真正控制GATT服务结构、连接参数、功耗策略,才能做出差异化,也才能应对客户的各种定制需求。

3. 进阶前必须搞懂的核心概念:广播、连接、GATT与MTU、绑定

3.1 广播和扫描:设备被发现的第一秒发生了什么

BLE设备的“被发现”依赖广播(Advertising)机制。广播包在三个广播信道(37/38/39)上周期性地发送,包体由两部分组成:广播数据(Advertising Data)和扫描响应数据(Scan Response Data)。广播数据最多31字节,扫描响应最多也是31字节。

E104-BT02的AT指令可以配置广播数据里的关键字段,比如设备名称、服务UUID、厂商自定义数据。实际项目中,广播数据的设计直接影响手机端的扫描识别速度和用户体验,这个点很容易被忽视。

我测试过一个参数组合,广播间隔31.25ms,广播数据只包含设备名称和服务UUID,iPhone上的nRF Connect基本是秒出设备。但如果广播数据里塞满厂商自定义数据(超过25字节),扫描到的概率会下降,因为部分手机系统对广播包长度比较敏感,特别是Android的某些机型,在后台扫描时会丢掉长包。

这里给出广播间隔的选取逻辑:

  • 31.25ms(AT+ADVINTER=50):连接建立最快,扫描发现最快,但平均功耗偏高。
  • 100ms(AT+ADVINTER=160):均衡模式,适合大多数互动类设备。
  • 500ms-1s(AT+ADVINTER=800/1600):低功耗信标类应用,扫描到设备需要等更久。

还有一个关键字段是广播类型(Advertising Type),E104-BT02支持可连接非定向广播(Connectable Undirected)和不可连接广播(Non-connectable)。如果你做的是iBeacon类广播设备,只需要单向发数据,用不可连接广播能省不少功耗;但如果设备需要被手机连接交互,必须用可连接广播。

3.2 连接与广播的切换:连接间隔和延迟决定了什么

一旦手机和模块建立连接,双方就会按照协商好的连接参数进行周期性通信。连接参数有三个核心值:

  • 连接间隔(Connection Interval):又叫通信间隔,范围是7.5ms到4s,必须是1.25ms的整数倍。连接间隔越短,数据实时性越高,但收发双方都要更频繁地醒来,功耗直线上升。
  • 从机延迟(Slave Latency):允许从机跳过的连接事件次数。比如从机延迟是4,意味着从机最多可以连续跳过4个连接事件不监听,期间可以休眠,大幅省电。代价是数据延迟变大。
  • 超时时间(Supervision Timeout):双方互相失联多久后判定连接断开,范围100ms到32s。这个值必须大于从机延迟乘以连接间隔,否则可能出现“明明设备还在工作,手机却显示断连”的怪问题。

在E104-BT02的AT指令里,相关的配置项包括:

AT+CONNINT=50 // 连接间隔:50*1.25ms=62.5ms AT+SLAVELATENCY=4 // 从机延迟:跳过4个事件 AT+TIMEOUT=500 // 超时时间:500*10ms=5s

我实测过一组数据供参考:连接间隔62.5ms、从机延迟4、超时5s的组合,在静态场景下模块的平均电流能做到几十微安级别(不算广播阶段),数据延迟在600ms以内,非常适合温湿度传感器、门锁电量上报这类场景。如果你的产品需要快速响应(比如遥控器),连接间隔要压到15ms甚至7.5ms,功耗自然会上去。

3.3 GATT工作流:Service、Characteristic、Descriptor三段式理解

BLE通信的核心是GATT(Generic Attribute Profile),它规定数据以“属性(Attribute)”的方式组织。很多刚接触BLE的工程师会把GATT和串口搞混,觉得就是“往一个管道里写数据”。实际上GATT是一棵属性树:

  • Service(服务):一组相关数据的集合,比如“电池服务”“设备信息服务”“自定义透传服务”。每个服务有唯一的UUID(16位或128位)。
  • Characteristic(特征值):服务下面挂的具体数据点,是真正产生数据的地方。每个特征值有属性(可读、可写、可通知、可指示),还有对应的Value(值)。
  • Descriptor(描述符):描述特征值的元数据,比如“用户描述”“客户端特性配置(CCCD)”。CCCD特别重要,手机订阅通知,实际上就是往CCCD里写0x0001或0x0002。

以E104-BT02默认透传服务为例:

层级名称UUID属性
Service自定义透传服务0xFFF0
Characteristic写入通道0xFFF1Write
Characteristic通知通道0xFFF2Notify
DescriptorCCCD0x2902Read/Write

理解这三个层级后,你就知道“订阅通知”的本质是什么——不是手机自己会魔法,而是手机往0xFFF2的CCCD描述符里写入了0x0001,模块检测到CCCD发生了变化,才在上行数据到达时主动给手机推通知。

3.4 MTU协商:决定一次能传多少字节的关键

MTU(Maximum Transmission Unit)是BLE链路层(或ATT层)能承载的最大单包数据长度。BLE 4.0/4.1时代,默认MTU是23字节,减去3字节的ATT头(1字节操作码+2字节句柄),实际单包最多只能传20字节用户数据。这就是你经常听说的“一次只能发20字节”的由来。

到了BLE 4.2+,支持MTU协商,E104-BT02的PHY6212也支持。连接建立后,手机可以发起MTU交换请求,把MTU从23升到247甚至更高。MTU协商成功后,单包能传的实际数据就变成MTU-3字节。

测试方法很简单:用nRF Connect连接模块后,在GATT界面里会看到MTU值,手动改成185或247,再往0xFFF1写一段100字节的数据,观察模块串口是否一次性收到100字节。如果数据被拆包了,说明MTU协商没生效。

这里有个隐藏问题:MTU大小会影响底层封包数量,但无线传输的物理层速率(PHY)同样决定数据吞吐量。E104-BT02支持BLE 5.2,理论上支持2M PHY,实际吞吐量能比1M PHY高近一倍。如果你的应用需要传音频流或者大量传感器数据,MTU、2M PHY、适当缩短连接间隔这三者要配合起来调,单改一个参数效果有限。

3.5 绑定(Bond)机制:配对以后怎么记住对方

热词里出现了“ble调试助手绑定(bond)”,说明很多人在实际测试时被绑定这个概念绕晕了。绑定和配对是两码事:

  • 配对(Pairing):一次性的安全验证过程,验证通过后双方交换密钥,建立加密连接。
  • 绑定(Bonding):配对完成后,双方把密钥保存在本地。下次重连时,可以直接用保存的密钥恢复加密关系,不需要重新配对。

在E104-BT02上,默认开启一定的安全能力,手机连接后如果是加密连接,会在手机端弹出配对请求。选择“配对并绑定”后,手机会存储模块的地址和密钥。之后模块即使断电重启,再次连上时手机端不会再询问,因为双方已经信任了。

实际产品设计中有个细节:如果你的设备是防丢器或门锁,绑定关系非常重要。设备只知道“配对过的手机”才能下发控制指令,其他手机扫到也连不上、控制不了。如果不做绑定,任何手机都能连上设备,在安全性要求高的场景就是灾难。

E104-BT02的AT指令里,我建议至少关注AT+BOND相关的配置项,开启绑定功能后,测试时要专门验证“解绑-重绑”链路是否顺畅。我遇到过一种情况:测试手机解绑后,模块侧还存着旧的绑定信息,导致新手机始终配对失败。解决办法是给模块做一次恢复出厂设置(AT+RESTORE),把模块侧的绑定记录全部清掉。这在量产测试阶段是一个必须覆盖的测试项。

4. 驱动代码怎么写:不只是点灯,而是搭一个带状态机的BLE应用框架

4.1 硬件抽象层:UART初始化与环形缓冲区

写驱动不能上来就怼协议栈API,先把最底层的UART驱动和缓冲区处理好,后面的逻辑才能稳稳跑。PHY6212的SDK里已经给了硬件驱动例程,但默认的串口接收方式是中断单字节回调,如果你在回调里直接处理数据,很容易被高频数据打爆。

我的做法是维护一个环形缓冲区(Ring Buffer),中断里只把数据塞进缓冲区,主循环里再统一消费。这样串口接收不丢数据,也不会阻塞中断上下文。代码如下:

#define RBUF_SIZE 512 typedef struct { uint8_t buffer[RBUF_SIZE]; uint16_t head; uint16_t tail; } ring_buffer_t; ring_buffer_t rx_rb; void rb_init(ring_buffer_t *rb) { rb->head = 0; rb->tail = 0; } bool rb_write(ring_buffer_t *rb, uint8_t data) { uint16_t next = (rb->head + 1) % RBUF_SIZE; if (next == rb->tail) { return false; // buffer full } rb->buffer[rb->head] = data; rb->head = next; return true; } bool rb_read(ring_buffer_t *rb, uint8_t *data) { if (rb->head == rb->tail) { return false; // buffer empty } *data = rb->buffer[rb->tail]; rb->tail = (rb->tail + 1) % RBUF_SIZE; return true; } // 串口中断回调 void uart_rx_isr_handler(uint8_t data) { rb_write(&rx_rb, data); }

主循环里解析数据时,可以按包处理,也可以按行处理:

while (rb_read(&rx_rb, &ch)) { if (ch == '\n') { process_line(recv_buf, recv_len); recv_len = 0; } else { recv_buf[recv_len++] = ch; } }

这个环形缓冲区的实现是最基础的版本,有两点要注意:第一,缓冲区大小要按你项目里最大一包数据的2倍以上来设,太小会丢包,太大浪费RAM(PHY6212的RAM本身有限);第二,如果业务上需要处理二进制帧,不要按\n做分包,要按帧头帧尾或长度字来解析,否则容易误判。

4.2 GATT服务与特征值的回调机制

在SDK里创建自定义Service和Characteristic的流程大致是:

  1. 定义UUID(16位或128位)。
  2. 配置特征值属性(可读、可写、可通知等)。
  3. 注册读写回调。
  4. 在回调里处理数据收发。

以PHY6212的SDK为例,伪代码逻辑如下:

// 定义UUID uint16_t service_uuid = 0xFFF0; uint16_t write_uuid = 0xFFF1; uint16_t notify_uuid = 0xFFF2; // 服务结构体 att_service_t custom_service; att_characteristic_t write_char; att_characteristic_t notify_char; void custom_service_add(void) { custom_service.uuid = service_uuid; custom_service.start_hdl = 0x0001; custom_service.end_hdl = 0x0004; att_register_service(&custom_service); write_char.uuid = write_uuid; write_char.properties = ATT_PROP_WRITE; write_char.value_len = MAX_DATA_LEN; att_register_characteristic(&write_char, write_callback); notify_char.uuid = notify_uuid; notify_char.properties = ATT_PROP_NOTIFY; att_register_characteristic(&notify_char, notify_callback); } // 写回调:手机写入数据时会进入这里 uint8_t write_callback(uint16_t conn_handle, uint16_t attr_handle, uint8_t *data, uint8_t len) { // 把收到的数据转发到串口 uart_send(data, len); return 0; }

回调机制的背后是协议栈的ATT层分发逻辑,当手机下发Write Request时,协议栈根据属性句柄找到对应的特征值,触发我们注册的写回调。这里的attr_handle是协议栈分配的唯一标识,调试时很有用,可以打印出来核对。

4.3 主循环框架:事件驱动而不是轮询加delay

BLE应用最忌讳的写法是主循环里用delay()等待,然后轮询标志位。一旦协议栈事件来了,主循环还在睡觉,数据就积压了。推荐的做法是搭建一个简单的事件驱动框架:

// 事件枚举 typedef enum { EVT_UART_RX, EVT_BLE_CONNECTED, EVT_BLE_DISCONNECTED, EVT_BLE_DATA_RX, EVT_BUTTON_PRESS, EVT_TIMER_TICK, } app_event_t; // 事件处理主入口 void app_event_handler(app_event_t evt, void *data) { switch (evt) { case EVT_UART_RX: handle_uart_rx(data); break; case EVT_BLE_DATA_RX: handle_ble_rx(data); break; case EVT_BLE_CONNECTED: handle_conn_established(); break; case EVT_BLE_DISCONNECTED: handle_conn_lost(); break; default: break; } } // 主循环 int main(void) { hw_init(); ble_init(); app_timer_init(); while (1) { app_event_t evt = dequeue_event(); if (evt != EVT_NONE) { app_event_handler(evt, NULL); } // 协议栈轮询处理 ble_stack_poll(); // 低功耗处理 if (system_idle) { enter_sleep_mode(); } } }

这个框架虽然简单,但把业务逻辑和协议栈解耦了。后面要加定时上报、按键唤醒、OTA升级之类的新功能,只需要新增事件类型和处理分支,不会动到协议栈的核心代码。这也是SDK工程能否从Demo走向产品化的关键一步。

5. 从Demo到量产:功耗、认证、配对策略和调试技巧

5.1 功耗调优:从广播到连接的全链路电流实测

功耗是BLE产品的生命线,尤其是电池供电的。E104-BT02的休眠电流能做到微安级别,但实际系统能不能低功耗,取决于你的外围电路设计和软件调度。我测试过一组电流数据,供参考:

阶段平均电流说明
深度睡眠(无广播)2-5uA关闭所有外设,仅保留RTC唤醒
广播状态(31.25ms间隔)80-200uA电流波动剧烈,取决于发射功率和包长度
广播状态(1s间隔)20-40uA适合低频信标
连接状态(7.5ms连接间隔)2-8mA高频收发,功耗大
连接状态(100ms连接间隔+从机延迟4)十几uA-几百uA低功耗连接主流区间

想榨干每一微安,有个细节:PHY6212的广播功耗和连接功耗是分开调节的,广播间隔可以长一点,但连接后的连接间隔要按实时性需求单独配。很多工程师图省事,把广播间隔和连接间隔设成同一个值,结果设备连接后功耗始终降不下来。

另外一个容易忽略的点:UART外设的漏电。模块和其他MCU通过UART互联时,MCU侧的TXD引脚在休眠时如果是高电平,会通过上拉或内部保护二极管向模块的RXD引脚漏电,导致系统整体待机电流偏高。解决方法是休眠前把MCU的TXD引脚拉低或配置为高阻输入。

5.2 蓝牙BR/EDR与BLE的区别:为什么手机能同时连两种设备

热词里出现了“蓝牙br ble区别”,这其实是很多新人的知识盲区。简单说,蓝牙BR/EDR(Basic Rate / Enhanced Data Rate)就是我们常说的“传统蓝牙”,面向音频传输和中等速率数据业务,比如蓝牙耳机、蓝牙音箱、蓝牙键鼠。BLE(Bluetooth Low Energy)是低功耗蓝牙,面向小数据量、低功耗、间歇式传输的场景,比如手环、传感器、门锁。

两者在物理层、协议栈、应用生态上都有差异,E104-BT02只支持BLE,不支持传统蓝牙音频。所以如果你要做的产品是蓝牙耳机或蓝牙音箱,这块模块帮不上忙。但在手机端,iOS和Android都同时支持BR/EDR和BLE,所以手机能同时连接一个BLE设备和一个传统蓝牙耳机,互不干扰。

在调试时有几个坑:有些低端Android手机的蓝牙协议栈对BLE的兼容性一般,连接多个BLE设备时可能出现其中一个断连——这不是模块的错,是手机侧的资源调度问题。应对方法是让模块在连接稳定后“少说话”,减少无谓的通知推送,降低手机协议栈的负担。

5.3 常见调试工具与手段:不规则问题别靠猜

做BLE调试,单纯靠串口打印效率太低,建议把这几个工具备齐:

  • nRF Connect for Mobile:手机端最好用的BLE调试工具,能看广播包、看服务、看特征值、发起MTU协商、手动读写。
  • LightBlue:iOS端的老牌工具,界面简洁,适合快速验证。
  • Packet Sniffer:如果手上有支持BLE嗅探的硬件(比如nRF52840 Dongle),可以在PC上抓空中的BLE报文,看广播包、连接请求、ATT交互,定位问题最直观。
  • 逻辑分析仪:分析UART数据时序,验证模块和MCU之间的通信是否正常。
  • 频谱仪(可选):测射频指标时用,普通开发阶段不一定需要。

我的习惯是:先用手机上的nRF Connect做功能验证,确认广播、连接、读写都正常后,再接入自己的MCU程序。如果功能异常,先看串口日志有没有报错,再看协议栈返回的错误码;如果通信距离明显短,用嗅探器抓包看是不是广播参数或天线区域有问题。这样定位问题的速度远快于瞎试参数。

5.4 量产阶段的测试清单和固件升级考虑

量产阶段不能只测功能,还要测一致性。我建议至少包含如下测试项:

  • 模块地址(MAC)是否唯一且可读。
  • 广播名称、广播间隔是否符合规格书。
  • 手机能正常连接并保持长时间不掉线(至少24小时)。
  • 绑定关系建立后,设备重启/手机蓝牙重启后能否恢复连接。
  • 低电量(比如3.0V)下通信距离和稳定性。
  • 高温高压环境下连续收发压力测试。
  • 恢复出厂设置后能否正常配网。

E104-BT02支持OTA固件升级,这在产品发布后修复问题、增加功能很关键。你的设计里最好预留一个OTA入口,比如通过特定按键组合触发进入升级模式,或者通过广播数据里加一个版本标志。量产阶段还有一点不可忽视:模块的固件版本要统一管理,不同版本可能有不同的AT指令集或协议栈行为,测试报告里一定要记录固件版本号。

6. 开源驱动代码的架构建议:别写一次性代码

6.1 可移植的分层结构

我见过太多工程师把BLE相关的代码和业务逻辑揉在一起,后面要换个模块、改个芯片,就相当于重写一遍。放在E104-BT02这个场景里的建议分层方式:

  • hal层:封装MCU的UART、GPIO、定时器、休眠接口。换芯片时只需重写这一层。
  • bt_layer层:封装BLE协议栈的初始化、广播配置、GATT服务注册、连接事件回调。
  • app层:业务逻辑,比如传感器数据采集、协议打包解析、状态机处理。

大致的头文件对外暴露:

// ble_app.h void ble_app_init(void); void ble_app_start_advertising(void); void ble_app_stop_advertising(void); void ble_app_send(uint8_t *data, uint16_t len); bool ble_app_is_connected(void); void ble_app_disconnect(void);

有了这层封装,即使后面把E104-BT02换成其他BLE模组,app层几乎不用动,只是把bt_layer层的实现替换一下。这种架构看起来前期投入多一点,但项目迭代到第二版、第三版时,你会感谢当时的自己。

6.2 状态机设计:广播中、已连接、掉线重连

BLE模块的状态不是一个二维的“连接/未连接”,实际运行时有几个关键状态:

  • IDLE:上电完成,尚未开始广播。
  • ADVERTISING:广播中,等待手机连接。
  • CONNECTING:正在建立连接(主机模式时用到)。
  • CONNECTED:连接已建立,可以收发数据。
  • BONDED:绑定关系已确认(可以与CONNECTED并存,也可以单独作为一个标志位)。

状态机的设计核心是事件驱动,比如:

  • 上电 -> 进入ADVERTISING
  • 手机连接 -> 从ADVERTISING切到CONNECTED
  • 断开 -> 从CONNECTED回到ADVERTISING(或进入SLEEP)
  • 超时未连接 -> 从ADVERTISING切到SLEEP,定时唤醒后再广播

写状态机时,有几个常见错误:

  • 重连风暴:模块断开后立刻重新广播,如果手机不在附近,模块会一直以高功耗广播,电池很快耗干。正确做法是采用“逐渐延长广播间隔”的策略,比如前30次用100ms广播,之后切到1s广播,再之后进入深睡。
  • 连接事件丢失:手机App被系统杀掉后,模块侧可能还认为连接是正常的,直到超时。所以产品逻辑里要有“心跳检测”机制,比如模块定期给手机发心跳包,手机超时未响应就主动断开重连。

驱动代码里加入状态机后,可以很方便地在日志里打印状态迁移记录,排查问题时能快速定位是在哪个环节出的岔子。

6.3 从AT指令到SDK的切换:哪些坑值得提前规避

最后聊一下从AT指令模式切换到SDK模式的实操经验。E104-BT02出厂自带AT固件,用串口就能配置。但如果你想做更灵活的GATT服务、更复杂的业务逻辑,就得用PHY6212的SDK重新烧录固件。

切换有几个坑:

第一个坑是引脚复用冲突。AT固件里,P00-P03是空的,你可以随便接外设。但烧了自己的固件后,某些引脚可能被协议栈占用作为调试口或时钟输出口,复用前一定要查勘SDK手册里的引脚分配表。

第二个坑是串口引脚和烧录引脚的关系。PHY6212的SWS引脚在正常工作模式下可以当普通GPIO用,但在烧录时会占用。如果产品PCB空间紧张,把SWS引出来做GPIO控制继电器,结果后续想升级固件却发现引脚被占,就麻烦了。我的建议是:量产板最好留出烧录测试点,不用焊排针,但PCB上要有过孔或者测试焊盘,方便夹具接触。

第三个坑是协议栈版本兼容性。PHY6212的SDK更新比较频繁,官方可能修复了一些协议栈bug、增加新特性,但AT固件和自研固件对协议栈的依赖不一样。如果你在AT固件下调好的参数,切到自研固件后出现异常,先检查SDK版本和协议栈配置是不是一致。

自研固件的代码编写,我建议第一步不要写业务逻辑,而是先复刻一个“最小可通信”的程序:上电广播、手机连接、透传收发、串口打印连接状态。跑通这个闭环后,再往里加业务功能。这么做的好处是先把最复杂的协议栈部分验证掉,后面加功能时出问题,比较容易隔离到是协议栈还是业务代码出的错。

7. 从一块模块到一个产品:还有什么值得扩展

7.1 数据协议设计:透传之上要有自己的框架

用E104-BT02做产品,最忌讳的就是直接把传感器原始数据往透传管道里倒。建议在最开始就设计一个简单的应用层协议,比如帧头+长度+命令字+数据+校验和:

typedef struct { uint8_t header; // 0xAA uint8_t len; // 数据长度 uint8_t cmd; // 命令字 uint8_t payload[32]; // 数据区 uint8_t checksum; // 校验和 } app_frame_t;

校验和用最简单的高位累加就行,够用且快。有了这层封装,手机App和设备之间就能做指令应答、分包拼接、错误重传,不再是一锅粥。

7.2 和微信小程序/手机App的对接思路

很多做智能硬件的朋友关心E104-BT02怎么接微信小程序。小程序里已经有BLE的API接口(wx.openBluetoothAdapterwx.createBLEConnectionwx.writeBLECharacteristicValue等),连接流程和手机原生App类似。唯一的坑是:小程序的MTU协商机制可能受版本影响,Android端默认MTU可能只有23,需要在连接成功后主动调wx.setBLEMTU协商大MTU,否则传大包会被系统拆散,导致上层拼包逻辑混乱。

iOS端小程序对MTU的限制更严格,有些版本不允许App主动设置MTU,只能靠设备端配合,这时候就需要模块侧做好分包策略,保证在23字节MTU下也能正确传数据。这个坑我在实际项目里踩过——App端明明写对了代码,但Android能收到完整数据,iOS总是丢字节,排查到最后才发现是MTU协商没生效。

7.3 低功耗场景下的周期性上报与远程唤醒

最后提一个比较高级的玩法:产品大部分时间处于深睡状态,通过RTC定时唤醒,采集完传感器数据后上报给手机。E104-BT02在这种模式下的功耗表现相当不错,关键是设计好“上报窗口期”和“广播退避策略”。

一个可行的时序:

  1. 深睡1小时(RTC唤醒)。
  2. 被唤醒后,开启广播,持续30秒等待手机连接。
  3. 若30秒内没连上,进入下一轮深睡。
  4. 若连上,上报数据,等待手机下发配置或指令。
  5. 空闲5秒后主动断开连接,回到深睡。

这个场景下的广播间隔不用太短,500ms就可以,因为手机有30秒的窗口期,足够完成扫描和连接。我用这套策略做过一个温湿度传感器,两节AAA电池撑了接近一年,实时性也满足需求。

E104-BT02的潜力远不止透传那么简单。它最大的价值是给了你一块“射频部分已经趟平”的BLE平台,让你能把精力集中在应用层和功耗设计上。无论是做IoT传感器、智能门锁、健康设备,还是当MCU的无线调试通道,这个模块都有足够的灵活性。如果你正准备起步,建议按照先从透传Demo验硬件、然后切SDK搭框架、最后优化功耗和体验的路线推进。遇到问题多抓包、多看状态机打印、多测电流,BLE开发没有玄学,数据会告诉你答案。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询