E104-BT02这块模块在圈子里不算冷门很多做物联网、工控、智能家居的工程师都摸过。但大多数人的印象还停留在“它是一块能透传的蓝牙模块”拿串口一连、AT指令一配就开始跑数据。说实话这用法也没错但有点浪费这块板子。E104-BT02用的是国产BLE SoC芯片型号我就不绕弯子了是PHY6212Cortex-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的引脚不多但每个引脚都有讲究。我直接画一下实际项目的典型接法VCC1.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指令模式串口波特率1152008N1。如果你在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.3VGND接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指令按这个顺序走一遍ATRST // 软复位模块 ATNAMEMyDevice // 设置广播名称最长不超过20字节 ATMAC112233445566 // 自定义MAC地址可选部分版本支持 ATUART115200,8,1,0 // 配置串口参数波特率、数据位、停止位、校验位 ATROLE0 // 0表示从机Peripheral1表示主机Central ATADVINTER50 // 广播间隔单位0.625ms5031.25ms ATPWR0 // 发射功率0为最高档 ATRESET // 保存参数并重启配置完这组参数后模块会以你设定的广播名开始广播。用手机上的BLE调试助手比如nRF Connect或者LightBlue扫描能看到一个叫MyDevice的设备直接连接然后启用Notify和Write特征值就能实现手机和模块之间的双向透传。2.2 手机端透传测试一个完整的收发闭环BLE调试助手连上模块后界面里会列出服务列表。E104-BT02的默认透传服务UUID通常是FFF0其中写特征值UUID是FFF1通知特征值UUID是FFF2不同固件版本可能有差异以实际扫描到的为准。测试步骤订阅通知点击FFF2后面的Notify图标让手机开始接收模块上行数据。手机发送在FFF1里写入字符串比如hello模块的串口TXD会立刻输出这5个字节。模块上行在串口助手里发送任意数据手机端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广播数据只包含设备名称和服务UUIDiPhone上的nRF Connect基本是秒出设备。但如果广播数据里塞满厂商自定义数据超过25字节扫描到的概率会下降因为部分手机系统对广播包长度比较敏感特别是Android的某些机型在后台扫描时会丢掉长包。这里给出广播间隔的选取逻辑31.25msATADVINTER50连接建立最快扫描发现最快但平均功耗偏高。100msATADVINTER160均衡模式适合大多数互动类设备。500ms-1sATADVINTER800/1600低功耗信标类应用扫描到设备需要等更久。还有一个关键字段是广播类型Advertising TypeE104-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指令里相关的配置项包括ATCONNINT50 // 连接间隔50*1.25ms62.5ms ATSLAVELATENCY4 // 从机延迟跳过4个事件 ATTIMEOUT500 // 超时时间500*10ms5s我实测过一组数据供参考连接间隔62.5ms、从机延迟4、超时5s的组合在静态场景下模块的平均电流能做到几十微安级别不算广播阶段数据延迟在600ms以内非常适合温湿度传感器、门锁电量上报这类场景。如果你的产品需要快速响应比如遥控器连接间隔要压到15ms甚至7.5ms功耗自然会上去。3.3 GATT工作流Service、Characteristic、Descriptor三段式理解BLE通信的核心是GATTGeneric Attribute Profile它规定数据以“属性Attribute”的方式组织。很多刚接触BLE的工程师会把GATT和串口搞混觉得就是“往一个管道里写数据”。实际上GATT是一棵属性树Service服务一组相关数据的集合比如“电池服务”“设备信息服务”“自定义透传服务”。每个服务有唯一的UUID16位或128位。Characteristic特征值服务下面挂的具体数据点是真正产生数据的地方。每个特征值有属性可读、可写、可通知、可指示还有对应的Value值。Descriptor描述符描述特征值的元数据比如“用户描述”“客户端特性配置CCCD”。CCCD特别重要手机订阅通知实际上就是往CCCD里写0x0001或0x0002。以E104-BT02默认透传服务为例层级名称UUID属性Service自定义透传服务0xFFF0无Characteristic写入通道0xFFF1WriteCharacteristic通知通道0xFFF2NotifyDescriptorCCCD0x2902Read/Write理解这三个层级后你就知道“订阅通知”的本质是什么——不是手机自己会魔法而是手机往0xFFF2的CCCD描述符里写入了0x0001模块检测到CCCD发生了变化才在上行数据到达时主动给手机推通知。3.4 MTU协商决定一次能传多少字节的关键MTUMaximum 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指令里我建议至少关注ATBOND相关的配置项开启绑定功能后测试时要专门验证“解绑-重绑”链路是否顺畅。我遇到过一种情况测试手机解绑后模块侧还存着旧的绑定信息导致新手机始终配对失败。解决办法是给模块做一次恢复出厂设置ATRESTORE把模块侧的绑定记录全部清掉。这在量产测试阶段是一个必须覆盖的测试项。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倍以上来设太小会丢包太大浪费RAMPHY6212的RAM本身有限第二如果业务上需要处理二进制帧不要按\n做分包要按帧头帧尾或长度字来解析否则容易误判。4.2 GATT服务与特征值的回调机制在SDK里创建自定义Service和Characteristic的流程大致是定义UUID16位或128位。配置特征值属性可读、可写、可通知等。注册读写回调。在回调里处理数据收发。以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 主循环框架事件驱动而不是轮询加delayBLE应用最忌讳的写法是主循环里用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/EDRBasic Rate / Enhanced Data Rate就是我们常说的“传统蓝牙”面向音频传输和中等速率数据业务比如蓝牙耳机、蓝牙音箱、蓝牙键鼠。BLEBluetooth Low Energy是低功耗蓝牙面向小数据量、低功耗、间歇式传输的场景比如手环、传感器、门锁。两者在物理层、协议栈、应用生态上都有差异E104-BT02只支持BLE不支持传统蓝牙音频。所以如果你要做的产品是蓝牙耳机或蓝牙音箱这块模块帮不上忙。但在手机端iOS和Android都同时支持BR/EDR和BLE所以手机能同时连接一个BLE设备和一个传统蓝牙耳机互不干扰。在调试时有几个坑有些低端Android手机的蓝牙协议栈对BLE的兼容性一般连接多个BLE设备时可能出现其中一个断连——这不是模块的错是手机侧的资源调度问题。应对方法是让模块在连接稳定后“少说话”减少无谓的通知推送降低手机协议栈的负担。5.3 常见调试工具与手段不规则问题别靠猜做BLE调试单纯靠串口打印效率太低建议把这几个工具备齐nRF Connect for Mobile手机端最好用的BLE调试工具能看广播包、看服务、看特征值、发起MTU协商、手动读写。LightBlueiOS端的老牌工具界面简洁适合快速验证。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.openBluetoothAdapter、wx.createBLEConnection、wx.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小时RTC唤醒。被唤醒后开启广播持续30秒等待手机连接。若30秒内没连上进入下一轮深睡。若连上上报数据等待手机下发配置或指令。空闲5秒后主动断开连接回到深睡。这个场景下的广播间隔不用太短500ms就可以因为手机有30秒的窗口期足够完成扫描和连接。我用这套策略做过一个温湿度传感器两节AAA电池撑了接近一年实时性也满足需求。E104-BT02的潜力远不止透传那么简单。它最大的价值是给了你一块“射频部分已经趟平”的BLE平台让你能把精力集中在应用层和功耗设计上。无论是做IoT传感器、智能门锁、健康设备还是当MCU的无线调试通道这个模块都有足够的灵活性。如果你正准备起步建议按照先从透传Demo验硬件、然后切SDK搭框架、最后优化功耗和体验的路线推进。遇到问题多抓包、多看状态机打印、多测电流BLE开发没有玄学数据会告诉你答案。