E104-BT02 BLE串口透传模块实战:电路、驱动与避坑指南
先说结论E104-BT02这类BLE串口透传模块是现阶段快速落地蓝牙应用性价比最高的方案之一。芯片原厂和模组厂商把射频匹配、协议栈、天线都给你封装好了你不需要懂蓝牙底层的跳频、重传、功耗管理只需把它当成一个“无线串口”用就行。但如果你想让它真正跑得稳、功耗低、不被调试折腾到怀疑人生光会发AT指令是不够的。这篇文章我会把从选型思路、电路设计、驱动代码到实际联调踩坑的完整过程拆开讲开源资料放文末建议收藏后跟着一步步做。1. 项目到底要解决什么问题1.1 为什么选E104-BT02而不是其他BLE方案做嵌入式产品的人应该都有体会蓝牙方案选型是个大坑。用ESP32自带的BLE功能很强大但射频天线的阻抗匹配、协议栈配置、低功耗策略这些全都得自己调调不好就是信号差、功耗高还很占主控的Flash和RAM资源。用一颗独立的BLE SoC比如nRF52832灵活是灵活但对于很多团队来说学习成本和研发周期根本兜不住。E104-BT02这颗模块用的是国产的BLE 5.0芯片走的路线和Nordic不太一样它更接近TI的CC2541那种经典透传方案但成本和功耗表现更好。模组厂商亿佰特把它做成标准封装内置了完整的BLE协议栈对外暴露UART串口和几个GPIO引脚。你只需要通过串口发AT指令模块就会自动完成广播、连接、数据收发这些操作。对于只需要在传感器数据采集、设备参数配置、手机App控制这类场景里加一个蓝牙通道的需求来说它可能是最快能跑通方案的模块了。我最早接触这款模块是被同事拉去评估一个穿戴设备的通信方案当时对比了JDY-23、CC2541、E104-BT02三款最后选E104-BT02的原因很简单一是模块自带PCB天线增益曲线在2.4GHz频段比较平坦做产品不需要额外做天线匹配二是它支持主从一体也就是说一个模块既能当主机也能当从机做手机直连和做设备互连都可以覆盖三是最重要的——它的串口透传模式用起来真的像操作一个串口设备一样简单。1.2 这个项目适合谁能省下什么事情如果你正在做下面任意一类项目这篇文章应该比较契合手头有一个MCU项目想增加手机App控制功能但不想把主控换成带蓝牙的SoC想做一个穿戴式传感器节点对功耗有要求需要在几年纽扣电池续航的范围内实现低功耗蓝牙连接需要一个能实现手机和设备双向数据透传的硬件模块做调试工具、数据采集器、智能家居设备想搞懂BLE到底怎么工作希望有一个上手快速、资料透明的模块作为学习对象。这篇文章能帮你省下最花时间的三件事第一不用自己啃协议栈开发文档第二不用调试射频匹配和天线阻抗第三不用花大价钱买开发板。开源电路和驱动代码直接可以用剩下的精力可以全部集中在应用层逻辑上。2. 5分钟快速体验串口透传模式2.1 硬件连接和准备工作第一件事是拿到模块后怎么给它通电。E104-BT02的引脚不多核心引脚就这几个VCC1.8V~3.6V推荐3.3VGND地TXD/RXD串口发送接收3.3V电平逻辑SET配置模式的使能引脚AUX/IO口状态指示和数据流控制我习惯用ST-Link或者CH340的USB转串口模块给它供电并接到电脑串口。注意模块是3.3V电平如果你的USB转串口是5V输出的务必先确认有没有电平转换能力否则大概率烧模块。接线表可以先对照着操作模块引脚接USB转串口或MCUVCC3.3V注意电流需求GNDGNDTXDRXDRXDTXDSET悬空或接高电平接线完成后在电脑上打开串口调试助手波特率和模块默认一致一般是115200数据格式8N1也就是8位数据、无校验、1位停止位。2.2 透传测试让数据飞起来给模块上电后串口调试助手里发送任意十六进制或ASCII数据只要手机连上模块的蓝牙数据就会实时出现在BLE调试App上。这里有一个容易踩的坑刚开始测试的时候我在串口助手输入字符串hello手机App上收到的却是乱码或者缺字节。后来检查发现串口助手和模块之间需要先把模块的发包延迟参数调好。E104-BT02默认的串口分包时间大约是10ms如果连续发送的数据超过缓冲区就会强制打包发出。当你发送较长的数据时建议把“串口分包字节数”调到最大比如200字节这样模块就会等缓冲区满或者空闲超时之后一次性发给手机而不是发一个字节就发一个包导致手机端数据看起来断断续续。测试通过后一个最简单的BLE串口透传链路就通了。整个过程不超过5分钟这也是这个模块最核心的价值所在不需要写一行蓝牙代码就能把数据从MCU搬运到手机。3. 原理拆解它到底是怎么工作的3.1 广播、扫描、连接——BLE通信的三步曲BLEBluetooth Low Energy的工作模式和经典蓝牙BR有本质区别。经典蓝牙从连接开始就是持续占用射频资源而BLE采用的是“广播-扫描-连接-休眠-唤醒”的间歇式工作模式这也是它低功耗的关键所在。当模块上电后第一件事是进入广播状态。它会周期性地在3个广播信道上发送数据包这些数据包内容包含设备名称、MAC地址、服务UUID等信息。手机在扫描模式下会在同样的信道上监听这些广播包看到后把设备加入扫描列表。之后手机主动发起连接请求模块回应后双方就建立了连接。连接建立后双方约定好连接间隔Connection Interval比如每20ms跳一次空闲时芯片进入休眠状态到时间点自动醒来收发数据。这样可以做到平均电流只有几十微安到几百微安。E104-BT02把这一整套流程封装好了。你开机后它会自动广播手机连上后它自动进入连接态数据通过GATT服务的Write/Notify特征通道进行传输。整个过程不需要你去配置广播类型或者连接参数但如果你想深度优化它同样支持AT指令修改。3.2 GATT、服务和特征值——数据通道的底层逻辑BLE的数据通道不是一个简单的管道它用的是GATTGeneric Attribute Profile这套抽象模型。你可以把它理解为一个数据库设备上的数据都组织成一个个服务Service每个服务下面又包含若干特征值Characteristic特征值就是真正承载数据的变量。E104-BT02默认暴露了一个服务UUID通常是FFE0或者其他厂家自定义的UUID服务下面包含一个写特征Characteristic0xFFE1手机发数据其实是往这个特征值写数据还有通知特征Characteristic模块发数据给手机是通过这个特征值发Notify通知。你在BLE调试助手里看到的收发数据实际就是读写这两个特征值的过程。了解这点很重要因为当你需要写App或者上位机的时候就要扫描到这两个特征值然后分别建立写和订阅的通道。很多开发者在用BLE调试助手里能正常收发但自己写App却连不上基本都是因为UUID匹配错误或者没有正确订阅Notify。3.3 绑定Bond和加密——安全机制的取舍热词里提到了“绑定Bond”这个在BLE开发里是个绕不开的机制。没有绑定的时候手机和设备每次连接都是“陌生人”数据以明文方式传输而且连接很容易被其他中心设备截获。绑定机制是BLE协议栈提供的一把钥匙——配对成功后两个设备会交换并保存一组长期密钥LTK之后每次连接双方通过快速验证这组密钥来确认身份通信数据使用密钥进行加密和解密。E104-BT02支持通过AT指令开启或禁止绑定。在默认不绑定模式下手机连上就能使用连接速度也更快开启绑定模式后首次连接时手机会弹出配对请求输入配对码或确认后完成绑定之后只有绑定的这台手机能访问数据安全性显著提高。具体的取舍建议是做低功耗传感器、广播类应用数据本身敏感性不高时可以不开启绑定省去配对步骤做数字钥匙、门锁、支付或医疗数据设备必须开启绑定和加密如果设备需要同时连接多个手机绑定机制会有限制需要评估业务模型。我有个项目因为疏忽没开绑定结果两台手机都能连上并控制设备最后出现了一次误操作。所以安全机制不要等出了事才重视。4. 开源电路与驱动代码的实战解析4.1 硬件电路设计要点既然标题里提到开源电路那这部分是重点。模块本身很皮实但要把电路画好、做进产品里还是有几个细节需要注意。电源设计是首要的。BLE模块在发射射频数据的瞬间电流尖峰会达到几十甚至上百毫安虽然时间只有几微秒但如果供电电路扛不住这个瞬态跌落模块就会复位或者射频误码。我在自己的项目里用的方案是LDO后面放一个100μF的钽电容并联一个0.1μF的陶瓷电容同时尽量把电容放置在模块VCC引脚旁边。对于电池供电的设备还要考虑电池的等效内阻如果内阻偏大发射瞬间电压跌落会更明显。天线净空区是另一个常见坑。E104-BT02板载PCB天线天线走线区域需要保持“净空”也就是说模块装在PCB上时天线正下方的区域不要铺铜、不要走高速信号线、周边也不要放置金属外壳或者大面积的接地金属。否则天线辐射效率骤降实际通讯距离可能从20米掉到5米。这点看起来简单但很多工程师第一次画板都会在这里栽跟头。串口电平匹配要注意。E104-BT02是3.3V电平如果你的主控是5V系统要么选5V兼容的引脚要么加电平转换芯片。直接串电阻分压不是不行但收发双向都得处理容易出问题建议直接用TXS0102这类电平转换芯片稳定省心。4.2 串口驱动状态机的设计开源驱动代码里核心部分是一个串口AT指令解析状态机和数据收发缓冲区管理。别看BLE模块负责了无线部分主控端的串口驱动质量直接决定了数据流的稳定性。我用STM32 HAL库写的驱动整体分为三层第一层是硬件抽象层负责初始化UART、配置DMA接收、注册中断回调。这里我强烈建议用DMA空闲中断的方式来接收模块返回的数据而不是用逐字节中断接收。逐字节中断在波特率115200时CPU占用率很高而且容易遗漏字节。DMA空闲中断可以把一整包数据自动收进缓冲区收完再触发回调处理效率高很多。第二层是协议解析层处理AT指令的响应。E104-BT02的AT指令集响应有两种类型一种是无参数响应OK一种带返回参数如NAME: E104-BT02。解析时要注意状态机的超时管理防止模块无响应时程序卡死。一般可以设定200~500ms的超时时间超时就重新发送或者报错。第三层是数据分发层负责把接收到的数据转发给用户应用程序。这里有一个设计模式上的建议使用环形缓冲区。串口中断时只管往环形缓冲区里写数据主循环或其他任务再从中按照FIFO顺序读取并处理这样即使短时间内数据量很大也不会丢数据。4.3 HAL库下驱动OLED与BLE融合的实战经验热词里出现了“hal库驱动oled代码”这说明相当一部分人实际做项目时BLE和OLED显示是绑定的。确实一个调试设备或者手持仪器几乎都有屏幕显示实时数据的需求。我们在STM32F103上同时跑BLE驱动和OLED驱动时要注意一件事OLED一般用I2C或SPI接口两者都可能和串口共用中断资源或者DMA通道。如果你用HAL库的CubeMX生成代码初始化顺序要保证UART先初始化再初始化OLED不然OLED初始化时如果触发了串口中断可能会产生不可预期的错误。驱动OLED的小技巧如果用I2C接口单次传输数据长度限制在32字节以内否则某些型号的OLED控制器会丢数据。显示中文需要先做字库取模取模方式可以选横向扫描或者纵向扫描要和OLED控制器的扫描方式匹配否则显示出来的文字会是错位的。我后来做的调试器产品就是把BLE收到的数据解析后直接在OLED上画波形用了双缓冲机制——一帧画在后台缓冲区画完之后一次性刷新到OLED防止画面撕裂和闪烁。4.4 无线数据与存储的配合以SST25VF080B为例驱动代码的开放范围里如果有Flash芯片操作代码那通常会搭配SST25VF080B这类SPI NOR Flash做数据记录。这个芯片容量是8Mbit即1MBSPI接口非常适合做传感器日志和升级文件的存储。SPI Flash驱动要注意的坑是写前必须擦除。NOR Flash的物理特性决定了只能把1写成0要把0写回1就必须先执行擦除操作而且擦除的最小单位是扇区常见的是4KB。所以如果你的代码是直接往某一地址写数据而没有提前擦除就会出现写入数据和读取数据对不上的情况。还有一个经验是在Flash里做数据管理时要设计一个简单的文件系统或记录结构。最简单的方式是使用“日志式”追加写每次写一条带时间戳的记录写到扇区末尾后就切到下一个扇区写满所有扇区后再从第一个扇区开始擦除重写。这样虽然做不到磨损均衡但胜在代码量小、逻辑简单、调试容易。5. 驱动代码核心模块的实现细节5.1 STM32 HAL库下的串口初始化和DMA配置我这里用STM32F103为例演示一个可用的驱动模板。硬件初始化最关键的是UART的DMA通道配置。使用CubeMX生成基础配置时需要注意把UART的全局中断打开同时配置对应DMA通道为循环模式因为这样DMA才能在收到任意长度数据后持续工作而不会因为缓冲区满了而停止接收。一个经常被人忽视的点是DMA的buffer size设置。如果你设置的是256字节但模块发来的数据包超过了256字节那么DMA会先装满256字节然后触发一次中断但这时可能有数据已经丢失了。解决办法是设置缓冲区大小大于模块单包最大长度。E104-BT02的透传缓冲区是200字节所以DMA缓冲区设为256字节就够用了。配置好DMA接收还要在UART空闲中断里判断一包数据的结束。UART的空闲中断触发时机是总线空闲也就是一个字节和下一个字节之间超过了一个字符的时间。DMA接收加空闲中断的组合是串口数据包最可靠的处理方式。5.2 环形缓冲区避免数据丢失的关键设计直接给一个精简的环形缓冲区实现会很有用。核心数据结构是两个索引读索引read_index和写索引write_index。每次DMA空闲中断发生时把DMA当前接收到的数据长度和读索引之间的差值计算出来这个差值就是有效数据长度然后把它写入环形缓冲区。主程序循环不断从环形缓冲区中取出数据解析这样即使主循环有短暂阻塞串口数据也不会丢因为DMA还在后台持续接收。实现环形缓冲区时要注意一个巧妙的点缓冲区大小必须是2的幂次方这样可以用位运算index (size - 1)代替取模运算效率高很多。缓冲区处理函数里不需要加锁因为单生产者单消费者的场景下只要读索引和写索引各自只有一个线程修改就不会发生竞争。5.3 AT指令交互与状态机解析E104-BT02有若干组常用AT指令设置设备名称、设置广播间隔、设置串口波特率、查询MAC地址、设置绑定开关等。指令交互的流程一般是主控发送一条AT指令模块执行后返回OK或者错误码。驱动代码里状态机的好处在异步交互场景下就会体现出来。比如你发送一条AT指令后不能立刻发送下一条必须等待模块的响应。如果不做状态机用简单的延时函数死等程序跑起来会很不流畅——尤其是在初始化时需要连续配置多项参数时。状态机只需要三个状态空闲、等待回复、完成。每次发指令时把状态置为等待回复同时开启一个超时定时器收到匹配的响应后状态切回空闲并通知上层。我实际项目里踩过一个坑初始化时发送AT指令太密集模块反应不过来导致某条指令的响应和上一条指令的响应混在一起解析出错。解决方案是每条指令发完后至少等50ms再发下一条同时状态机加入“清空输入缓冲区”这个动作确保上一包的残留数据不会影响后续解析。6. 常见问题与排查技巧实录6.1 连不上、配对失败、数据乱码的排查方向这里把调试中常见的现象、原因和解决办法整理成一个速查表方便你遇到问题时按图索骥现象可能原因解决与验证方法手机扫描不到模块广播模块可能未进入广播态广播间隔设置过长供电异常用串口发送ATRST重启模块检查电源电流是否正常缩短广播间隔到30~50ms能搜索到但连接失败连接参数不一致模块已绑定其他手机信号过于微弱检查是否开启了绑定模式恢复出厂设置靠近模块再连接连接后数据无法接收未订阅Notify特征服务UUID不匹配连接间隔太大导致数据延迟确认使用FFE0/FFE1 UUID在调试助手里手动点击订阅适当缩短连接间隔串口发送乱码或丢字节波特率不匹配发送节奏太快缓冲区溢出确认模块实际波特率发送间隔大于20ms增大串口缓冲区数据传输极不稳定偶尔断连天线附近有金属遮挡供电跌落射频干扰检查天线净空区域加电容强化电源尽量远离WiFi路由器和USB 3.0接口6.2 功耗异常的排查低功耗是BLE的卖点但很多人测下来发现电流居高不下。常见原因有三个第一模块没有实际进入睡眠状态。E104-BT02在连接状态下会按照连接间隔周期唤醒如果连接间隔设得太短比如7.5ms功耗自然高。对于实时性要求不高的传感器上报场景把连接间隔调到100ms以上平均电流会有数量级的下降。第二MCU的外设没有关完。很多项目只注意模块的功耗却忘了主控MCU的GPIO上拉电阻、传感器、LDO的静态功耗。一个简单的测量方法把MCU程序烧成sleep模式用万用表测整板电流如果电流还是偏高就一块块断开外设排查。第三广播时间太长。模块上电开始广播到连接建立的时间段内广播功耗远高于连接状态的功耗。如果设备是长时间待机、按键唤醒后临时广播建议把广播超时时间设置得短一点比如30秒超过就自动进入深度睡眠。6.3 BLE和经典蓝牙BR的区别为什么选择BLE热词里专门提到了“蓝牙BR BLE区别”这里一句讲透BR/EDR经典蓝牙适合持续大流量传输比如蓝牙耳机听歌、蓝牙音箱放音乐BLE适合小数据量、低功耗、偶发通信的场景比如传感器读数、设备控制、广播信标。E104-BT02这类模块走的就是BLE这条路不要指望拿它传音频流。在实际项目选型时如果应用场景是每秒钟传好几KB的连续数据那么BLE的吞吐量会成为一个瓶颈E104-BT02这类透传模块不太适合如果只是每秒几十个字节的控制指令或者状态信息BLE就是最优解。7. 从模块到产品开源设计可以怎么改开源电路和驱动代码的价值在于你可以站在别人的肩膀上做二次开发。但要从demo变成产品有几个改动点值得重点关注。第一把模块和主控集成到一块PCB上。开发板上模块是独立焊在底板上的产品设计时可以直接把模块的引脚和主控画在同一块板上。这时注意热设计如果产品有金属外壳天线附近不要放螺丝柱和地平面。第二增加供电管理电路。开发阶段直接用USB供电没关系产品阶段要设计电池充放电管理、低电量报警、电源路径切换。推荐用Torex或TI的低静态功耗LDO待机电流能控制在微安级别。第三驱动代码做状态机强化。开发板的驱动代码往往是单线程循环结构产品上如果有多个外设和通信协议同时工作建议引入RTOS或者事件驱动的状态机框架。把BLE驱动封装成独立任务通过消息队列和其他任务通信这样可以避免中断竞争和软件死锁。有一个项目跑在FreeRTOS上BLE数据接收用的就是队列加信号量的方式。串口DMA中断接收数据后判断一包完整数据然后通过信号量通知BLE任务去读取数据BLE任务处理完数据后再通过队列把结果转发给显示任务或者存储任务。这样设计的好处是每个任务职责单一出问题时定位也容易。8. 写在最后的经验分享E104-BT02是我用过的BLE模块里上手曲线最平滑的一个。它把最难的无线部分藏起来了让你能集中精力解决业务问题。但“藏起来”不等于“不存在”理解背后的GATT、连接间隔、广播机制、绑定原理才能真正把它用好出问题时也知道往哪个方向查。根据我个人的开发习惯拿到这类模块后不要急着写完整产品代码先花10分钟做一次裸机的AT指令配置和透传测试确认模块本身工作正常。然后逐步加入MCU主控、OLED屏幕、传感器等外设每加入一个外设就做一次验证这样即使出了Bug也能快速定位到是哪一个环节的问题。另外再分享一个调试小技巧手机端的BLE调试助手不要只用一个。建议同时装两个一个用于连接和收发数据另一个用来扫描和观察广播报文。当连接遇到问题时用扫描工具看模块的广播UUID和MAC是否正常这能帮你快速判断是模块没有正常工作还是手机连接参数配置有误。开源资料里还有针对SST25VF080B的驱动和OLED驱动这部分代码可以直接移植到其他项目里。核心代码写了详尽的注释遇到看不懂的宏定义或者回调函数对照本文的流程过一遍基本就能看通了。最后还是那句话不要被“开源”两个字迷惑开源给你的是一条快速的起点线不是终点。真正让项目变得稳定可靠的是你自己在调试中踩过的坑和不断完善的驱动代码。