13. ESP32-S3R8N8 BLE蓝牙低功耗通信实战:从广播配置到数据收发

📅 发布时间:2026/7/8 3:17:49 👁️ 浏览次数:
13. ESP32-S3R8N8 BLE蓝牙低功耗通信实战:从广播配置到数据收发
13. ESP32-S3R8N8 BLE蓝牙低功耗通信实战从广播配置到数据收发很多刚开始玩ESP32-S3的朋友想用蓝牙和手机通信但一看到BLE那些服务、特性、UUID的概念就头大。别担心今天我就带你手把手走一遍用MicroPython在ESP32-S3R8N8上实现一个最简单的BLE通信。学完这篇你就能让开发板和手机互相发消息了。咱们的目标很明确让手机上的“e调试”APP能搜到并连接上我们的ESP32-S3然后我们发个字母“A”过去板子收到后回我们一个字母“B”。麻雀虽小五脏俱全这个流程涵盖了BLE从创建、广播、连接到数据收发的核心步骤。1. 先唠两句BLE是个啥蓝牙低功耗BLE你可以把它理解成蓝牙的“节能版”。它生来就是为了省电适合那些靠电池供电、需要长时间待机、偶尔传点小数据的设备比如智能手环、温湿度传感器、智能门锁这些物联网IoT设备。和传统蓝牙比如连音箱的那种比BLE连接速度更快功耗极低设备用一颗纽扣电池可能就能撑一年。ESP32-S3芯片只支持BLE不支持经典蓝牙所以咱们的手机蓝牙直接去搜是搜不到的得用支持BLE的APP比如咱们教程里用的“e调试”。2. 搭建BLE的“骨架”服务与特性BLE设备对外提供功能是靠一套“服务-特性”的模型。你可以把一个BLE设备想象成一个提供多种服务的商店。服务Service就是商店里的一个柜台比如“数据收发柜台”。特性Characteristic就是柜台里具体能买卖的东西比如“接收数据”和“发送数据”这两个商品。每个特性都有唯一的“身份证号”叫UUID。数据真正的读写操作都是针对特性来进行的。下面我们就来用代码把这个“商店”开起来。2.1 初始化BLE并创建服务首先把蓝牙功能的核心库引进来然后激活蓝牙模块。from bluetooth import BLE import bluetooth bt BLE() # 创建一个蓝牙对象这是所有操作的起点 bt.active(1) # 参数为1打开蓝牙功能接下来我们要定义服务的UUID和特性的UUID。UUID通常是一串16位或128位的数字这里我们用简单的16位数字来举例。# 定义一个服务的UUID。0x9011是十六进制数相当于十进制的36881这就是我们“数据收发柜台”的ID。 SERVER_1_UUID bluetooth.UUID(0x9011) # 定义两个特性的UUID。一个用来收数据CHAR_A一个用来发数据CHAR_B。 CHAR_A_UUID bluetooth.UUID(0x9012) # 特性A的ID CHAR_B_UUID bluetooth.UUID(0x9013) # 特性B的ID光有ID还不够我们得规定这些特性能干什么。比如特性A我们允许手机“读”它的值并且允许它主动“通知”手机也就是主动发数据给手机。特性B则允许手机“读”和“写”。# 设置特性A的权限可读(FLAG_READ) 可通知(FLAG_NOTIFY) CHAR_A (CHAR_A_UUID, bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,) # 设置特性B的权限可读(FLAG_READ) 可写(FLAG_WRITE) CHAR_B (CHAR_B_UUID, bluetooth.FLAG_READ | bluetooth.FLAG_WRITE,)现在把这两个特性打包放进我们之前定义的服务里。# 把特性A和特性B放入服务1 SERVER_1 (SERVER_1_UUID, (CHAR_A, CHAR_B),) # 目前我们只有一个服务把它放到一个服务元组里 SERVICES (SERVER_1,)最后也是最关键的一步把这个服务“注册”到BLE协议栈中。注册成功后我们会得到这两个特性对应的“句柄”可以理解为内部操作编号后面收发数据全靠它们。# 注册服务。返回值是一个嵌套的元组这里用((char_a, char_b),)来接收两个特性的句柄。 ((char_a, char_b),) bt.gatts_register_services(SERVICES)注意char_a和char_b这两个变量现在保存的就是特性A和特性B的句柄后面用bt.gatts_notify发数据、用bt.gatts_read读数据时都需要用到它们。3. 让手机能找到我广播配置商店开好了但藏在深巷没人知道。BLE设备通过“广播”来告诉周围的设备“我在这儿我叫XXX快来连接我”广播包里就装着设备名等信息。我们来写一个函数专门生成包含设备名的广播数据包。def create_adv_data(name): # BLE广播数据有固定格式[长度1, 类型1, 数据1, 长度2, 类型2, 数据2, ...] # 第一部分广播标志(Flags)。0x02表示这部分数据总长2字节0x01表示类型是“Flags”0x06是数据通用可发现模式。 flags_part bytearray([0x02, 0x01, 0x06]) # 第二部分完整的设备本地名称。0x09是“Complete Local Name”的类型码。 name_encoded name.encode(utf-8) # 把字符串转换成字节 name_length len(name_encoded) name_part bytearray([name_length 1, 0x09]) name_encoded # 长度要加上类型码自身占的1字节 # 把两部分拼接起来 adv_data flags_part name_part return adv_data # 设置我们的设备广播名手机搜到的就是这个名字 adv_data create_adv_data(ESP32S3R8N8_BLE) # 开始广播100是广播间隔单位是0.625ms100约等于62.5msadv_data就是广播内容 bt.gap_advertise(100, adv_data)执行完bt.gap_advertise你的ESP32-S3就开始对外喊话了“我是ESP32S3R8N8_BLE”4. 处理连接与数据中断事件回调BLE是事件驱动的。手机连接、断开、发数据过来这些对我们设备来说都是“事件”。我们需要写一个中断处理函数就像设置一个“管家”当这些事件发生时由“管家”来负责处理。def ble_irq(event, data): if event 1: # 事件1蓝牙已连接 print(蓝牙已连接) # 连接后可以停止广播以省电这里我们先不处理 pass elif event 2: # 事件2蓝牙断开连接 print(蓝牙断开连接) # 断开后重新开始广播等待下一次连接 bt.gap_advertise(100, adv_data) elif event 3: # 事件3写入事件即手机向我们发送了数据 print(写入事件发生) # 事件3的data是一个元组包含连接句柄和特性值句柄 conn_handle, value_handle data # 通过value_handle读取手机写过来的数据 buffer bt.gatts_read(value_handle) print(收到数据, buffer) # 判断收到的数据 if buffer bA: # 如果收到单个字符A print(向手机发送字符 B) # 通过char_a这个特性句柄以“通知”的方式向手机发送字符B # 参数1是连接句柄char_a是目标特性句柄 bt.gatts_notify(conn_handle, char_a, bB) # 将这个“管家”函数设置给蓝牙对象 bt.irq(ble_irq)这个函数是整个BLE通信的逻辑核心。它清晰地展示了连接管理连接和断开时打印信息断开后自动重启广播。数据接收当事件3写入发生时从正确的value_handle读取数据。数据发送判断收到的是否是‘A’如果是则通过bt.gatts_notify从char_a特性向手机发送‘B’。提示bt.gatts_notify是BLE中一种高效的、由服务器我们的ESP32主动向客户端手机推送数据的方式不需要手机反复来“问”。5. 实战测试与手机“e调试”APP通信代码都写好了把整个脚本上传到ESP32-S3R8N8开发板并运行。然后拿出你的手机安装APP在手机应用商店搜索并下载“e调试”APP一个常用的BLE调试工具。搜索设备打开“e调试”它会自动扫描周围的BLE设备。你应该能看到一个名叫“ESP32S3R8N8_BLE”的设备。连接设备点击这个设备名称进行连接。发现服务连接成功后APP会列出设备的所有服务。找到那个UUID为0x9011的服务可能显示为Unknown Service点进去。操作特性你会看到两个特性分别对应我们代码里的char_a(UUID: 0x9012) 和char_b(UUID: 0x9013)。找到具有“写”权限的特性通常是0x9013那个点击进入其操作界面。在发送框输入大写字母A点击“发送”。观察结果在ESP32的串口终端比如Thonny的Shell窗口你应该会看到打印出“写入事件发生”、“收到数据 b‘A’”、“向手机发送字符 B”。同时在“e调试”APP上你应该能看到从设备UUID: 0x9012的特性发来的通知数据B。恭喜你你已经完成了一个完整的BLE双向通信。手机发A设备回B。你可以修改ble_irq函数里的判断逻辑和发送的数据来实现你自己的控制逻辑比如收到‘1’开灯收到‘0’关灯。6. 几个容易踩的坑UUID冲突如果你有多个ESP32设备或者和其他BLE设备一起用尽量使用独特的UUID避免用0x9011这种简单值可以用在线生成器生成128位的UUID。广播名不显示确保广播数据包格式正确特别是长度字段。len(name)1那个1千万别漏它计算的是“类型码名称数据”的总长度。收不到数据或发不出数据首先检查特性句柄char_a、char_b是否正确获取并在ble_irq和bt.gatts_notify中被正确使用。其次确认手机操作的是正确的、具有相应权限的特性写数据要找FLAG_WRITE的特性收通知要订阅FLAG_NOTIFY的特性。连接断开后不广播检查ble_irq函数中事件2断开的处理逻辑确保调用了bt.gap_advertise重新广播。这个例程虽然简单但已经搭建起了ESP32-S3 BLE开发的基本框架。下次你想做个BLE温湿度计或者遥控小车只需要在这个框架里修改服务/特性的定义并在中断函数里填充你的业务逻辑就行了。