E104-BT02蓝牙5.0透传模块实战:从硬件设计到低功耗BLE开发全攻略
2026/9/5 1:46:08 网站建设 项目流程

1. 从选型到点亮:为什么E104-BT02值得花5分钟试一次

去年做一款低功耗数据采集终端时,我在蓝牙选型上折腾了快两周。起初用的是某国产透传模块,AT指令倒是简单,但广播间隔调到20ms之后功耗怎么都压不下来,而且有一次在客户现场出现频繁断连,用手机抓包一看,连接参数协商一塌糊涂。后来换成E104-BT02这颗基于Nordic nRF52832的BLE 5.0模块,差不多一个下午就把广播、连接、串口透传全部跑通,功耗曲线也干净了很多。这玩意儿最大的价值在于:它把nRF52832这颗高性能芯片的绝大部分精力花在了RF前端和天线匹配上,你只需要关心自己的应用层代码,不用去调那些玄学的射频参数。

如果你还不知道E104-BT02是什么,简单交代一下:这是亿佰特出的一款蓝牙5.0透传模块,主控是Nordic nRF52832,支持主从一体、iBeacon、串口透传,硬件接口是UART,供电1.8V到3.6V,板载PCB天线,理论通信距离能到60米。和同门师兄E104-BT51(nRF52840方案)比,它更适合对尺寸和成本敏感的场景;和那些CH9140、KT6368A之类的国产透传芯片比,它的协议栈完整度、连接稳定性和功耗表现完全是另一个档次。

这篇文章不会只讲怎么把模块的TX、RX、VCC、GND接上然后跑一个出厂Demo——那些你翻数据手册就能搞定。我想做的是把选型思路、硬件电路、驱动代码、调试工具串成一条完整链路,让你拿到模块之后的第一天就知道:广播参数该配多少、GATT服务怎么建、MTU大小对透传速率意味着什么、为什么手机偶尔能连上但一断就再也扫不到。这些东西是我在项目里一个个坑踩过来之后才理清的,看完你至少能少走一半弯路。

适合谁来读?正在做低功耗传感器节点、便携式医疗设备、智能家居网关、考勤定位终端,或者单纯想用nRF52832但不想上来就啃SDK的开发者。你不需要有很深的蓝牙协议栈基础,但要懂一点STM32或GD32的HAL库开发,知道UART中断怎么收数据。如果你是个纯App开发者想快速搞一个硬件配合联调,这篇文章也能帮你理解硬件工程师嘴里说的"MTU不够大所以传不了长包"到底是什么意思。

2. 硬件设计的关键取舍:参考电路、天线净空和那颗容易被忽略的复位引脚

很多开发者拿到模块的第一反应是找数据手册里的参考电路,然后照着画个最小系统板。这个思路没错,但有几个细节是数据手册不会专门拿出来吓唬你的,实际栽过跟头才知道疼。

2.1 模块封装选型:贴片版和IPEX版的应用差异

E104-BT02有贴片天线版本和IPEX座子版本两种封装。在选型阶段你最好一次定对,因为这两者的PCB封装不兼容,后期想换版本就得改板子。

  • 贴片天线版:整板面积最小,天线直接做在PCB上,适合手环、胸牌、传感器标签这类对外观尺寸有极致要求的场景。缺点是天线的辐射方向图和净空区要求比较苛刻,如果外壳是金属的或者附近有大面积铺铜,谐振会被拉偏,实测距离可能缩水一半以上。
  • IPEX版:外接2.4G弹簧天线或胶棒天线,天线可以远离主板、放到塑料外壳的顶部,信号一致性明显更好。缺点是成本和BOM多了天线和馈线,而且IPEX座子焊接时要特别小心虚焊,我见过不少"模块发烫但搜不到信号"的返修板,拆开一看就是IPEX座的中间针和外壳地短路了。

另外,无论哪个版本,模块下方尽量不要走任何高速信号线或电源走线。nRF52832的射频前端对地平面很敏感,模块底层的参考地必须连续、完整,不要在模块正下方挖空或开槽。

2.2 最小系统电路:除了VCC和GND,你还得关心这三根脚

从最简角度来说,模块只要接VCC、GND、TXD、RXD就能工作,也就是数据手册上那个"经典四线接法"。但实际做产品(不是跑Demo)时,有三个引脚必须认真对待:

  • SET引脚(硬件复位和模式切换):E104-BT02的SET引脚是低电平有效,拉低超过200ms模块会进入配置模式(AT指令模式)。很多人的板子上SET引脚直接悬空,这在出厂默认(透传模式)下没问题,但如果你需要通过AT指令改广播名、调发射功率或者切主从模式,就只能在硬件上飞线短接了。建议从主控MCU拉一个GPIO过去,哪怕只是单纯做复位控制,也比硬复位(断VCC)来得优雅。
  • AUX引脚(状态指示):这个引脚用来判断模块是否处于"可连接"状态。模块初始化完成、开始广播时,AUX输出高电平;数据发送过程中AUX会翻转。如果你的主控和模块之间有"查询是否忙"的需求,AUX一定要接,否则你可能会在模块还没准备好的时候就给它灌串口数据,导致数据丢失。不过我实测发现E104-BT02内部有128字节的串口缓存,不算太脆,但依赖缓存总归不是好习惯。
  • PIO引脚(唤醒/事件):在低功耗场景下,想让模块从睡眠模式醒来或者接收来自蓝牙远端的唤醒指令,PIO引脚可以接到主控的外部中断GPIO上。如果只是做最简单的透传,PIO可以不管。

下面是具体的参考连接(以GD32F103作为主控为例):

模块引脚主控MCU引脚说明
VCC3.3V模块供电,纹波尽量小于50mV
GNDGND共地必须接
TXDPA10(USART1_RX)模块发送,主控接收
RXDPA9(USART1_TX)模块接收,主控发送
SETPB0(推挽输出)拉低进入AT配置模式,默认高阻/拉高
AUXPB1(输入模式)查询模块状态,可配合外部中断

注意:模块的TXD和RXD是TTL电平,不是RS232,也不是RS485,绝对不能直接怼到电脑的DB9串口上去。调试时请务必通过USB转TTL工具连接,电平不匹配轻则通信乱码,重则烧模块。

2.3 供电和滤波:为什么跑着跑着就重启

E104-BT02的峰值电流出现在广播发射瞬间,大约在25mA左右,听起来不大,但如果你的供电链路有压降,或者滤波电容放得太远,会在广播瞬间把VCC拉低到2.0V以下——nRF52832的brown-out检测就会触发,模块直接软复位。表现就是:模块上电后能工作,但每隔几秒就重新广播一次,手机端看到的名字频繁"消失又出现"。

我用的稳妥方案是:主电源输出端串联一个10Ω电阻,电阻后端并联一颗100μF钽电容和一颗0.1μF陶瓷电容,然后才接到模块VCC。钽电容负责提供瞬态电流,陶瓷电容负责滤高频纹波。如果主控和模块共用一颗LDO,建议LDO的输出电流能力不低于150mA,否则电台发射时把显示屏的背光电流抢走,液晶屏会肉眼可见地变暗一下。

3. 驱动代码怎么组织:HAL库框架下把透传做到"一条条消息完整到达"

这里我不会去重复放整个工程的代码,那样篇幅太长反而模糊焦点。我把驱动代码的架构思路和关键片段整理出来,你在自己项目里照着搭就行。核心目标有三个:串口数据不丢、收包能分包、远端设备写过来的数据能实时转发到MCU。

3.1 串口初始化:波特率匹配和DMA的取舍

E104-BT02默认波特率是115200,8N1。如果你的MCU主频是72MHz的GD32F103或者STM32F103,115200这个波特率的误差完全没问题,但尽量不要用256000以上的高速率,因为模块内部的UART外设精度有限,高速率下偶尔会出现断帧现象。

我习惯用中断接收+环形缓冲区的方式,而不是DMA。原因有两个:第一,DMA在半满中断和全满中断的逻辑处理上比较绕,对于不定长数据包的切割不友好;第二,BLE透传模块的串口数据流往往是"小包高频"而不是"大包连续",中断方式的CPU占用其实非常低,没必要用DMA给自己找麻烦。

下面是HAL库风格的UART初始化关键代码(基于GD32F103,STM32直接换头文件即可):

/* 串口1初始化:PA9-TX, PA10-RX */ void uart1_init(uint32_t baud) { GPIO_InitTypeDef gpio_init = {0}; USART_InitTypeDef usart_init = {0}; NVIC_InitTypeDef nvic_init = {0}; // 使能时钟 rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_USART1); // PA9 TXD,复用推挽输出 gpio_init.pin = GPIO_PIN_9; gpio_init.mode = GPIO_MODE_AF_PP; gpio_init.speed = GPIO_SPEED_50MHZ; gpio_init.alt_func = GPIO_AF_7; gpio_init(GPIOA, &gpio_init); // PA10 RXD,浮空输入 gpio_init.pin = GPIO_PIN_10; gpio_init.mode = GPIO_MODE_IN_FLOATING; gpio_init(GPIOA, &gpio_init); // 串口参数 usart_init.baud_rate = baud; usart_init.data_bits = USART_DATA_8BITS; usart_init.stop_bits = USART_STOP_1BIT; usart_init.parity = USART_PARITY_NONE; usart_init.flow_ctrl = USART_FLOWCTRL_NONE; usart_init(USART1, &usart_init); USART1->CTL0 |= USART_CTL0_REN | USART_CTL0_TEN; // 使能收发 USART1->CTL0 |= USART_CTL0_RWU; // 使能接收中断(GD32命名差异) // 中断优先级 nvic_init.nvic_irq = USART1_IRQn; nvic_init.nvic_irq_priority = 1; nvic_init.nvic_irq_enable = ENABLE; nvic_init(&nvic_init); }

补充说明:如果你用的是标准STM32 HAL库,上面的GD32 API换成HAL_UART_Init(&huart1)就行,思路完全一样,就是寄存器操作和库函数名有差异。千万不要直接在中断回调里做消息解析或业务处理,中断里只做"把字节丢进环形缓冲区"这一件事,别的都在主循环里干。

3.2 环形缓冲区:解决不定长数据包的基础设施

串口中断每收到一个字节,就把它压入环形缓冲区;主循环里我们不断查看缓冲区有没有数据,有就尝试按帧切割。这里的关键问题是:BLE透传模块的串口数据是流式的,没有帧头帧尾,怎么切包?

答案很直接:透传模式下切不了,也不需要切。E104-BT02的串口透传行为是——远端BLE设备发来一个Write请求,模块会把这包数据完整地从UART口发出来,两个包之间有一个小的空闲间隔。因此,我们可以利用"串口空闲超过N个字节时间"来断帧。最常见的是用USART_IDLE空闲中断,或者简单粗暴一点:在主循环里检测到超过3~5个字节时间的静默期就认为一包数据接收完成。

我实测下来的经验值是:115200波特率下,一个字节时间约86.8μs,两个包之间的静默期一般在1ms以上,所以设"超过500μs没有新字节就算一包收完"是比较稳的。下面是一个简化的断帧逻辑:

#define FRAME_GAP_TICKS 500 // 单位us uint8_t ring_buf[256]; volatile uint16_t head = 0, tail = 0; void USART1_IRQHandler(void) { if (usart_interrupt_flag_get(USART1, USART_INT_FLAG_RBNE) != RESET) { uint8_t ch = usart_data_receive(USART1); ring_buf[head] = ch; head = (head + 1) % sizeof(ring_buf); } } /* 主循环调用:尝试从缓冲区取出一整包 */ int ble_get_packet(uint8_t *out, uint16_t max_len, uint32_t gap_us) { static uint32_t last_rx_tick = 0; if (head == tail) { last_rx_tick = 0; return 0; } // 判断静默期 if (last_rx_tick != 0 && (get_tick_us() - last_rx_tick) < gap_us) { last_rx_tick = get_tick_us(); return 0; } uint16_t len = 0; while (tail != head && len < max_len) { out[len++] = ring_buf[tail]; tail = (tail + 1) % sizeof(ring_buf); } last_rx_tick = get_tick_us(); return len; }

这个逻辑很土,但极其有效。注意last_rx_tick的更新时机——在head != tail的情况下每次进入都要更新,这样即使模块在一包数据发送过程中字节间隔超过了gap_us,也不会被中途切断(因为只要有数据到达,静默期计时就归零了)。

3.3 发数据给模块:要不要等待AUX引脚

往模块的串口发数据时,有个细节值得注意:发送太快、太猛,模块的串口缓存会满。E104-BT02的串口FIFO我记得大约128字节,如果MCU一次性往模块灌了几百字节,超出部分就直接丢了,而不会像有些模块那样自动流控。

我提供的解决办法有两个:

  1. 用AUX引脚做硬件握手:发送前先检查AUX是否为高电平(空闲),发送过程中如果AUX拉低,说明模块内部正在通过射频往远端推数据,此时暂停发送。这个方案最可靠。
  2. 每包数据之间强制加延时:简单粗暴,适合对速率要求不高的场景。实测115200波特率下,每发20字节之后等2ms,基本不会丢数据。如果主控串口中断里发得太快,建议还是用方案1。
void ble_send(uint8_t *data, uint16_t len) { // 等待AUX为高:模块空闲 while (gpio_input_bit_get(GPIOB, GPIO_PIN_1) == RESET); for (uint16_t i = 0; i < len; i++) { while (usart_flag_get(USART1, USART_FLAG_TBE) == RESET); usart_data_transmit(USART1, data[i]); } }

这样每发送一包数据之前,都会确认模块的AUX引脚已经处于空闲状态,避免因为射频阻塞导致FIFO溢出。

4. 广播、连接和MTU:这三个概念没搞懂,调无线就像盲人摸象

这部分是给那些想深入一点的开发者准备的。你会发现,一旦把自己的主控MCU接入E104-BT02的透传链路之后,"能通"只是第一步,接下来你会面临一连串问题:为什么手机App连不上?为什么连上之后传大文件失败?为什么广播名字一会有一会无?这些问题的根子都在BLE协议栈的几个核心概念上。

4.1 广播类型和广播间隔:不是所有广播手机都能扫到

E104-BT02的AT指令里,AT+BROADCAST相关配置可以设置广播类型和广播间隔。常见的广播类型有:

  • ADV_IND(可连接非定向广播):最常用,手机能扫到并且可以主动连接。
  • ADV_DIRECT_IND(直接定向广播):指定只让某个特定设备连接,广播包里有目标设备的地址,其他设备扫不到或者扫到也连不上。
  • ADV_NONCONN_IND(不可连接广播):纯广播,适合iBeacon这种不需要连接的应用。
  • ADV_SCAN_IND(可扫描但不可连接广播):支持主动扫描请求,但不支持发起连接。

最常见的坑是把广播类型配成了ADV_NONCONN_IND,然后拿着手机折腾半天说"模块连不上"。用AT指令配置时一定要确认自己选的是ADV_IND。另外,广播间隔越大,手机扫描到模块的延迟越大。出厂默认一般是100ms,如果你希望手机一打开App就能秒连,建议配到50ms甚至20ms,代价是功耗略有上升。

从功耗角度算笔账:假设广播间隔是100ms,广播包时长约1ms,平均广播电流约20mA,那广播平均电流就是20mA × 1/100 = 0.2mA。如果改成20ms间隔,平均电流上升到1mA。如果你的设备是靠纽扣电池供电、需要广播数月,100ms是保守的选择;如果用户对连接速度很敏感,20ms到50ms更合理。没有绝对正确的值,只有适合你场景的值

4.2 BLE连接过程:从广播到GATT服务发现的完整链路

手机和E104-BT02建立连接的过程,很多人以为只是"扫到名字、点一下",但从协议栈层面看要经历四步:

  1. 手机(Central)扫描到模块(Peripheral)发出的广播包。
  2. 手机发送连接请求(Connection Request),两端建立连接事件。
  3. 连接建立后,手机启动服务发现流程,读取模块的GATT服务表,找到可用的服务(Service)和特征(Characteristic)。
  4. 手机根据特征属性决定是读(Read)、写(Write)还是订阅通知(Notify/Indicate)。

透传模式下,模块被预先烧录了一个自定义GATT服务,里面包含收数据和发数据两个特征。你在写上位机/App时,必须知道收数据特征的UUID和发数据特征的UUID,否则无法通信。不同的固件版本UUID可能不同,用手机上的BLE调试工具(后面会讲)可以扫描出来,或者直接看模块出厂AT指令表里记录的UUID。

连接参数协商也是个常见坑:手机希望用更长的连接间隔来省电,模块希望用更短的间隔来提升吞吐。如果协商不一致,会出现以下现象——模块和手机明明连上了,但数据发不过去,或者延迟高达几百毫秒。E104-BT02允许你在配置模式下手动指定连接间隔,建议开发和调试阶段设为15ms到30ms,能明显感觉响应变快。

4.3 MTU大小:透传速度的天花板

MTU(Maximum Transmission Unit)是BLE链路层单包能传输的最大应用数据长度。老版本BLE 4.0/4.1的MTU固定为23字节,其中协议头占3字节,实际一次只能传20字节。BLE 4.2以后支持通过MTU协商扩展到最大247字节,E104-BT02的nRF52832方案最高支持到247。

MTU不生效的典型症状:模块串口收了一大包数据(比如200字节),转成BLE包发出去时被拆成10个小包,接收方App端看到的现象是数据乱序、延迟翻倍,或者干脆丢包。解决方法是让手机App在连接建立后发起MTU协商请求(例如请求到247),这样模块才会把大包合并发送。

在驱动代码层面能做的不多,因为MTU协商是BLE协议栈自动处理的,但你在设计应用协议时要避免设计一个"必须靠单包传完"的帧格式——万一对方设备不支持大MTU,你的业务逻辑就得兼容分包。我的建议是:应用层帧用固定包头+长度字段+CRC,接收端做组装和校验,永远假设底层会分包。

5. 串口透传之外的高阶玩法:把模块当成一颗低功耗协处理器

前面讲的都是透传模式——主控通过串口和模块交互。但其实E104-BT02用的是nRF52832,这颗芯片本身有64MHz的Cortex-M4F内核、512KB Flash和64KB RAM,算力远超一个普通串口转蓝牙芯片。所以你完全可以不用主控MCU的串口,而是直接把这颗模块当成整个产品的主处理器,这就是"SDK二次开发"玩法。

5.1 芯片方案和模块方案怎么选:一颗nRF52832裸片到底值不值得

如果你确定要深度定制BLE逻辑、跑私有协议、或者干脆让模块自己采集传感器数据,你可以选两条路:

  • 芯片方案:直接买nRF52832裸片,自己设计射频前端和天线。优点是成本最低(单芯片不到20块),缺点是射频性能取决于你的PCB设计水平,没有模块厂帮你调匹配网络,滤波器、电感、天线的选型坑很多。除非你是资深RF工程师,或者产品量级达到万套以上,否则不建议。
  • 模块方案:用E104-BT02的贴片版,然后基于nRF5 SDK开发自己的固件。模块厂已经把射频调试好了,你只需要用Nordic的SDK写应用代码就行。成本和裸片方案比贵十几块,但把RF风险完全规避了。

5.2 BLE和传统蓝牙BR/EDR:为什么你的方案必须用BLE

我在做蓝牙选型时经常被问到:BLE和传统蓝牙(BR/EDR)到底有什么区别?简单说,BR/EDR(就是大家常说的"经典蓝牙")是为传输音频和较高速率数据设计的,功耗天然偏高,连接建立也需要更长时间,适合蓝牙耳机、音箱。BLE则从协议栈层面就为低功耗设计,广播通道和连接通道分离,连接事件是"按需唤醒"的,所以才能做到纽扣电池供电跑数月甚至数年。

E104-BT02只支持BLE,不支持BR/EDR。如果你想做的是音频传输或者和老的蓝牙2.0设备兼容,这颗模块就不合适。但如果你的需求是传感器采集、控制指令、状态上报这类小数据量通信,BLE就是标准答案。

5.3 低功耗策略:从广播参数到睡眠模式的联动

把E104-BT02当成协处理器之后,你可以让MCU大部分时间睡眠,模块保持低功耗广播或连接状态,只在有数据时才唤醒MCU。nRF52832提供了三种睡眠模式:

  • SYSTEM_ON:内部时钟停止,RAM保留,唤醒时间最短。
  • SYSTEM_OFF:除了唤醒引脚和复位,整个芯片几乎全部断电,RAM不保留,唤醒时间约几百微秒。
  • 连接事件待机:模块连接期间,每次连接事件结束后迅速回到睡眠,这是BLE低功耗的精华——平均电流可以做到5μA到20μA级别

实际调低功耗时,除了模块本身,还要注意主控MCU和模块之间的电平转换电路不能倒灌电流。很多人在这个环节翻车:主控的TX/RX引脚在模块睡眠时保持高电平,通过模块内部的钳位二极管倒灌电流,导致整体功耗多出几百微安。解决办法是在主控和模块之间加一个MOSFET电源开关,或者用I2C电平转换芯片(如TXS0108)来隔离。

6. 调试工具和方法:Bond绑定、抓包分析和常见故障速查

说实话,驱动代码写好了,硬件电路确认了,但真正的问题往往出现在你拿着手机第一次去连接模块的时候。接下来这部分是我调试BLE设备以来积累的方法论,每一个场景我都实际遇到过,照着排查能省很多时间。

6.1 手机端必备工具:LightBlue 和 nRF Connect 的正确用法

调试E104-BT02最常用的两个手机App是LightBlue(iOS/Android)和nRF Connect(iOS/Android)。它们的作用不只是"看看能不能扫描到模块",更重要的是它们能帮你:

  • 查看完整广播包内容:广播名字(Local Name)、服务UUID、厂商自定义数据都能解析出来。
  • 发起连接并查看GATT服务列表:确认模块的收/发特征UUID。
  • 直接写入数据测试透传:不用写App就能验证模块的串口透传链路是否通畅。
  • 发起MTU协商:测试模块在247字节MTU下的表现。

有一个经常被忽略的功能是绑定(Bond)。如果你在nRF Connect里连接模块时点了"Pair"或者"Bond",手机会和模块交换密钥,并把绑定信息存储在系统蓝牙栈里。下次连接时会自动带上绑定信息。

但这里有个坑:当你调试完,手机和模块之间的绑定关系还在,你把模块烧录了新固件或者恢复了出厂设置,手机再次连接时可能会失败——因为手机侧的密钥信息和模块侧的认证信息对不上。症状是"能扫描到模块、能发起连接,但连接后立刻断开,或者一直弹配对窗口"。解决办法是在手机蓝牙设置里忽略/删除这个设备,然后再重新扫描连接。如果你的产品要量产,模块出厂时必须禁用绑定功能,否则每个用户换了手机都会遇到这个坑

6.2 抓包和分析:没有Sniffer时怎么定位问题

理想情况下,你手里应该有一台nRF52832 DK开发板刷成BLE Sniffer,然后配合Wireshark抓空中的广播包和连接包。但没有Sniffer时,你依然可以用以下手段定位问题:

  1. 用手机App看广播内容:如果手机能扫到模块,但广播名是一串乱码,排查模块串口是否误收到了AT指令,或者配置参数被改乱了。
  2. 用串口监听日志:将主控和模块之间的串口数据同时接入一个USB转TTL工具,通过串口终端软件观察数据流,确认是主控没发数据,还是模块没转发。
  3. 用AUX引脚做状态指示:在调试板上把AUX引脚接LED,观察LED闪烁频率和广播间隔是否同步,进而判断模块是否处于死循环/复位状态。

多嘴一句,如果你连模块都扫不到,首先要检查的不是天线,而是模块是否处于配置模式——SET引脚如果被拉低超过200ms,模块会进入AT指令模式而不进行广播,这在我接手过的项目里出现过不下三次。

6.3 常见故障现象速查表

症状可能原因排查方向
手机完全扫不到模块模块处于AT配置模式;广播间隔太大;模块未上电确认SET引脚电平;检查AUX引脚电平;测量VCC电压
能扫到但连接失败广播类型配成了不可连接广播;手机端有旧绑定信息检查AT+BROADCAST配置;删除手机蓝牙绑定设备
连接后立刻断开绑定密钥不匹配;连接参数协商失败忽略设备重新配对;重置模块参数
能连接但数据发不过去GATT服务UUID错;特征属性没找对用nRF Connect查看服务列表和特征权限
数据发过去但延迟很大连接间隔太长;MTU太小还没做协商调整连接间隔;在App端手动发起MTU协商
发送大数据丢包串口FIFO溢出;应用层没有分包/组装机制使用AUX握手;设计应用层帧格式时带长度和序号
模块偶发复位供电不足;广播瞬间电压跌落增加VCC滤波电容;检查LDO输出能力
传输距离短天线净空不够;外壳金属屏蔽调整天线区铺铜;检查外壳材质;改用IPEX外接天线

6.4 让OLED屏显示模块状态:HAL库驱动的参考实现

有不少用户在做带屏显设备(如智能手表、室内定位工牌)时,会在主控上挂一块小OLED屏来显示蓝牙连接状态。这里顺便给一个基于HAL库的OLED驱动小例子——当然这不是E104-BT02的必需内容,只是帮你在调试过程中让状态更直观。

OLED I2C的HAL库驱动核心是初始化SSD1306控制器、开启显示和设置坐标。关键代码片段如下(STM32 HAL库风格):

void OLED_Init(void) { uint8_t cmds[] = { 0xAE, // display off 0xD5, 0x80, // clock div 0xA8, 0x3F, // multiplex ratio 0xD3, 0x00, // display offset 0x40, // start line 0x8D, 0x14, // charge pump on 0x20, 0x00, // horizontal addressing mode 0xA1, // segment remap 0xC8, // COM scan direction 0xDA, 0x12, // COM pins 0x81, 0xCF, // contrast 0xD9, 0xF1, // pre-charge period 0xDB, 0x40, // VCOMH deselect 0xA4, // resume to RAM content 0xA6, // normal display mode 0xAF // display on }; HAL_I2C_Mem_Write(&hi2c1, 0x3C << 1, 0x00, I2C_MEMADD_SIZE_8BIT, cmds, sizeof(cmds), 100); }

代码本身没什么玄机,重点是I2C地址——大部分0.96寸OLED的I2C从机地址是0x3C,但也有少数是0x3D,如果你写0x3C没反应,先量一下有没有ACK信号,别急着怀疑线序

7. 确定模块用于实际产品前,先测试避坑

很多硬件方案在开发板上调通了,但转到小批量样机阶段却翻车不断。结合我用过的多款BLE模块,针对E104-BT02梳理几个值得提前验证的点。

7.1 复位时序:上电初始化需要多久才能发AT指令

E104-BT02上电后,内部固件初始化需要时间,典型值大约在100ms到300ms之间。如果你的主控在模块完全启动前就给它发送AT指令,指令会被当成透传数据丢掉。所以主控代码里,一般在初始化时做个200ms到300ms的延时,再开始往模块发送配置指令。更稳妥的做法是:通过模块的AUX引脚判断——AUX从低变高说明模块初始化完成,此时再发AT指令。

7.2 环境干扰和共存测试

BLE工作在2.4GHz频段,和Wi-Fi、ZigBee、私有2.4G协议共用同一个频段。如果你在产品里同时放了Wi-Fi模组和BLE模组,建议把Wi-Fi的发射通道和BLE的广播通道错开,或者至少预留天线空间隔离。实测在一个金属外壳里同时点亮Wi-Fi和BLE,BLE的广播丢包率可能从1%飙升到10%以上,这属于物理层面的共存问题,单靠软件重试很难根治。

7.3 量产固件配置的自动化

如果你的产品量级超过千台,逐台用串口工具发AT指令配置模块显然不现实。我的做法是:在产测阶段写一个PC端小工具,通过USB转串口批量下发配置指令,每台设备测试三项:能不能进AT模式、广播名是否唯一、RF发射功率是否达到预期。如果你的产品支持OTA,也可以把配置参数做成出厂默认,通过蓝牙远程修改,避免产线耗时。

8. 一个典型的实际项目:E104-BT02在"低功耗室内定位标签"中的完整应用

最后,用我之前做过的室内定位标签项目来把前面所有知识点串起来。这个项目的要求非常典型:标签体积尽量小,纽扣电池供电,需要每秒广播一次位置数据给附近的网关,并且支持手机App临时连接修改参数。整个链路就是E104-BT02最擅长的场景。

8.1 整体架构:传感器采集、MCU睡眠、BLE广播

标签整体架构是这样的:

  • 主控:STM32L051(超低功耗MCU,负责读取传感器数据并控制模块)。
  • 传感器:一个加速度计(检测标签是否在移动)和一个温湿度传感器。
  • 通信:E104-BT02模块,配置为广播模式,广播内容里包含设备ID和温湿度数据。
  • 供电:一颗CR2032纽扣电池(220mAh)。

工作流程:主控大部分时间处于STOP模式,每5秒醒来一次,读取温湿度、判断加速度计有没有触发运动事件,然后把数据打包成16字节的广播负载,通过E104-BT02发出去。如果网关检测到标签的数据异常(比如温湿度越限),会通过另一个通道(比如手机App或网关的蓝牙连接)远程唤醒标签,让标签进入连续的透传模式做实时调试。

8.2 数据协议:16字节能塞下多少信息

BLE广播包的有效载荷最多31字节,其中还要扣掉Flags(2字节)、Local Name(若干字节)和UUID(若干字节),真正留给厂商自定义数据的空间在16字节左右。我们的标签广播包设计如下:

字节偏移字段长度说明
0帧头1字节固定0xA5
1~2设备ID2字节每个标签唯一
3~4温度2字节编码值,有符号数×100
5~6湿度2字节编码值,无符号数×100
7电池电压1字节精度0.01V
8RSSI参考值1字节校准用的偏移
9广播计数值1字节0~255翻转
10~15预留6字节扩展用

设备ID的分配规则:前1个字节是产品批次,后1个字节是流水号,这样管理起来非常方便。网关扫描到广播包后,通过设备ID快速判断该标签属于哪个区域,省去了连接过程,功耗自然就低了。

8.3 功耗实测:这套设计到底能跑多久

简单估算一下:CR2032容量约220mAh。广播间隔5秒,每5秒中只有约1ms的广播发射时间,发射电流约20mA,平均下来广播耗电约20 × 1/5000 = 0.004mA。主控STOP模式电流约2μA,模块睡眠电流约3μA,传感器待机电流约1μA,叠加起来整机平均电流约10μA。理论续航220mAh / 0.01mA ≈ 22000小时,约两年半。

但如果把广播间隔从5秒改成200ms,平均广播电流变成20 × 1/200 = 0.1mA,整机平均电流翻了十倍,续航骤降到几个月。这就是为什么广播间隔参数的设置直接决定了产品的电池寿命。开发阶段你也许感觉不到差异,但产品上市之后消费者会因为"三天两头换电池"而退货。

8.4 踩过的坑:模块固件版本差异导致广播名乱码

在项目联调时,我们有一批模块的广播名在手机端显示乱码。排查了很久,后来发现这批模块是较早的固件版本,AT指令中的UTF-8编码处理和当前固件不一致。解决方法是统一固件版本,并在量产产测中增加一项"广播名解析检查"——产测电脑通过USB蓝牙适配器扫描广播名,和数据库里的预期值比对,不一致的直接判定为不良品。这类问题在原理图和代码层面都看不出来,只能在产线上防。

9. 从E104-BT02到更复杂的BLE系统设计:下一步你可以怎么走

写到这里,E104-BT02的5分钟上手应该不只是"点亮一个透传模块",而是帮你打通了从硬件选型、电路设计、驱动开发到调试方法论的全链路。当你把这颗模块吃得足够透之后,自然会发现BLE世界还有更大空间可以探索。

如果你后续要做更复杂的系统,有两条进阶路径可以走:

  • 往深度走:把E104-BT02里的nRF52832当成真正的MCU来用,学习Nordic的nRF5 SDK,直接在主控上操作GATT、EFR32、Flash管理和OTA升级。官方SDK里有很多现成的示例,比如UART服务、BLE UART中转、DFU升级等。到了这个阶段,你手头这块模块就能变成一个完整的可穿戴设备主控。
  • 往广度走:研究BLE Mesh。如果你需要组网控制几十上百个节点,E104-BT02这类单点透传模块就不够了,需要选择支持Mesh方案的芯片(比如Nordic的nRF52840系列),或者学习Zephyr RTOS的BLE Mesh框架。组网之后的管理模型、消息洪水控制、节点配网这些都是全新的课题。

说回开头那个低功耗数据采集项目,现在那块板子已经跑了一年多,中间因为现场布局调整改过一次固件——通过OTA把传感器采样间隔从30秒改成5秒,其他什么都没动。稳定运行的前提,无非就是当初在选型阶段没贪便宜、电路设计阶段认真做了电源滤波、代码里尊重了AUX握手、量产时统一了固件和产测标准。这几条说起来朴素,但每一条都是踩坑换来的。

如果你正在用或者准备用E104-BT02,我的建议是:不要满足于出厂透传Demo,把本篇讲的广播配置、MTU协商、断帧逻辑、产测方法都亲自过一遍,哪怕只是在开发板上多花一天时间。对于BLE这类"无线+协议栈+外设"耦合成度极高的技术,唯有把底层机制摸到肌肉记忆的程度,才能在出问题时快速定位,而不是靠玄学重启解决。希望这篇内容能帮你把最开始的5分钟,真正变成后续无数个顺心顺手的5分钟。

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

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

立即咨询