当前位置: 首页 > backend >正文

蓝牙通讯协议学习

1. 传统蓝牙 (RFCOMM) VS BLE (低功耗蓝牙)

传统蓝牙 (RFCOMM) 和 BLE (低功耗蓝牙) 使用不同协议
BLE设备需要知道服务UUID和特征UUID才能正确通信

在主板(如树莓派、STM32等)通过 串口(UART) 连接蓝牙模块(如HC-05、JDY-31等)的场景中,UUID 仅适用于BLE(低功耗蓝牙),而传统蓝牙串口模块(基于SPP/RFCOMM协议)不需要UUID。以下是具体分析和解决方案:


1.1 明确蓝牙模块类型

情况1:传统蓝牙模块(如HC-05)

  • 协议:使用 RFCOMM/SPP(串口端口协议),直接透传串口数据。
  • UUID无关:数据通过固定的 通道(Channel) 传输,而非UUID。
  • 通信流程
    UART TX
    RFCOMM Channel 1
    主板
    蓝牙模块
    手机/PC

情况2:BLE模块(如HM-10)

  • 协议:基于 GATT(通用属性协议),需通过UUID标识服务/特征。
  • 关键UUID
    • 串口数据服务:通常为 0000FFE0-0000-1000-8000-00805F9B34FB
    • 写入特征(TX)0000FFE1-...(主板→蓝牙)
    • 通知特征(RX)0000FFE2-...(蓝牙→主板)

1.2 如何确定数据传输方式

步骤1:确认模块型号及协议

  • 查看模块手册或标签(如HC-05是传统蓝牙,CC2541是BLE)。
  • 传统蓝牙:无需UUID,直接配对后映射为虚拟串口(如 /dev/rfcomm0)。
  • BLE模块:需查找UUID(常见于手册或AT指令响应)。

步骤2:获取BLE模块的UUID

  • 方法1:AT指令查询(连接模块的UART,发送指令):

    AT+UUID?     # 查询服务UUID
    AT+CHAR?     # 查询特征UUID
    

    响应示例

    +UUID=FFE0
    +CHAR=FFE1
    
  • 方法2:使用BLE扫描工具(如nRF Connect):

    • 扫描设备 → 查看服务列表 → 找到串口相关服务(如 FFE0)。

步骤3:传统蓝牙的通道确认

  • 固定为 RFCOMM Channel 1(多数模块默认值),无需配置UUID。

1.3 代码实现示例

传统蓝牙(如HC-05)通信

# 主板通过UART发送数据(Python示例)
import serialuart = serial.Serial("/dev/ttyS0", baudrate=9600)  # 替换为实际串口
uart.write(b"Hello Bluetooth\n")  # 数据直接透传到蓝牙模块

BLE模块(如HM-10)通信

# 通过UUID读写数据(需bleak库)
from bleak import BleakClientUART_SERVICE = "0000FFE0-0000-1000-8000-00805F9B34FB"
TX_CHAR = "0000FFE1-0000-1000-8000-00805F9B34FB"  # 主板写入特征async def send_data(address, message):async with BleakClient(address) as client:await client.write_gatt_char(TX_CHAR, message.encode())print("数据已发送")# 使用
address = "80:6F:B0:12:34:56"  # 模块蓝牙地址
asyncio.run(send_data(address, "Hello BLE"))

蓝牙设备的 MAC 地址,格式为 6组十六进制数,用冒号 : 或连字符 - 分隔。地址字母不区分大小写:(00:1A:7D 和 00:1a:7d 等效)

在这里插入图片描述

可以手动从手机/电脑蓝牙设置中查看:
在手机蓝牙设置中点击搜索到的蓝牙名称 → 查看详情 → 找到 MAC 地址(格式如 00:11:22:33:44:55)。


1.4 关键区别总结

特性传统蓝牙(如HC-05)BLE模块(如HM-10)
协议RFCOMM/SPPGATT
是否需要UUID
数据传输方式直接串口透传通过特征(Characteristic)读写
典型应用音频、文件传输传感器数据、IoT设备

1.5 常见问题解决

Q1:如何确认数据是否通过蓝牙发出?
  • 传统蓝牙:用手机APP(如"蓝牙串口")查看接收的数据。
  • BLE:使用nRF Connect监听特征值变化。

Q2:发送后对方未收到数据?

  • 检查波特率(确保主板与蓝牙模块的UART波特率一致)。
  • 确认BLE模块的写特征UUID是否正确。
  • 检查硬件连接
    确认 TX/RX 线序正确(主机 TX → 模块 RX,主机 RX → 模块 TX)
  • 检查供电是否稳定(避免电压不足导致数据丢失)

Q3:如何自定义BLE模块的UUID?

  • 通过AT指令修改(依模块型号而定):
    AT+UUID=ABCD1234  # 设置自定义服务UUID
    AT+CHAR=5678      # 设置特征UUID
    

总结

  • 传统蓝牙串口模块:数据直接透传,无需UUID,只需确保UART配置正确。
  • BLE模块:需通过 服务/特征UUID 读写数据,UUID通常为 FFE0/FFE1 或由厂商指定。

2. 蓝牙模块的广播功能

蓝牙模块的广播功能是其核心特性之一,主要用于无连接的数据传输和设备发现。

广播的本质:单向主动发射
蓝牙模块(广播者):像“广播电台”一样,主动、周期性发送广播包(无需等待其他设备请求)。

其他设备(观察者/扫描者):如手机、网关等,只需开启扫描(Scan)功能,即可被动接收这些广播数据,无需提前配对或建立连接。

在这里插入图片描述

3. python建立BLE蓝牙通讯的示例代码

  1. 直接根据蓝牙模块的MAC建立通讯连接
from bleak import BleakClient
import asyncioasync def connect_ble(device_address):"""连接BLE设备"""try:async with BleakClient(device_address) as client:print(f"已连接到 {device_address}")# 获取服务services = await client.get_services()for service in services:print(f"服务: {service.uuid}")for char in service.characteristics:print(f"  特征: {char.uuid}")# 示例: 读取特征值 (需要替换为实际的特征UUID)# value = await client.read_gatt_char("00002a00-0000-1000-8000-00805f9b34fb")# print(f"读取的值: {value}")except Exception as e:print(f"错误: {e}")# 要运行的BLE设备地址
DEVICE_ADDRESS = "XX:XX:XX:XX:XX:XX"  # 替换为你的设备地址if __name__ == "__main__":asyncio.run(connect_ble(DEVICE_ADDRESS))
  1. 通过扫描确定蓝牙模块的MAC建立通讯连接
from bleak import BleakScanner, BleakClient
import asyncioasync def scan_ble_devices():print("扫描BLE设备...")devices = await BleakScanner.discover()for d in devices:print(f"{d.name}: {d.address}")return devicesasync def connect_to_device(address):async with BleakClient(address) as client:print(f"已连接到 {address}")# 这里可以添加你的通信代码# 使用示例
async def main():devices = await scan_ble_devices()if devices:await connect_to_device(devices[0].address)asyncio.run(main())
http://www.xdnf.cn/news/7060.html

相关文章:

  • 内容社区系统开发文档(中)
  • 继MCP、A2A之上的“AG-UI”协议横空出世,人机交互迈入新纪元
  • windows环境下c语言链接sql数据库
  • Kubernetes控制平面组件:Kubelet详解(六):pod sandbox(pause)容器
  • JSON Schema 高效校验 JSON 数据格式
  • 微服务项目->在线oj系统(Java版 - 2)
  • c++编写中遇见的错误
  • 【AWS入门】Amazon SageMaker简介
  • 4:OpenCV—保存图像
  • 解决 Tailwind CSS 代码冗余问题
  • 机器学习(12)——LGBM(1)
  • Python爬虫基础
  • 选择合适的AI模型:解析Trae编辑器中的多款模型及其应用场景
  • Go 语言中的一等公民(First-Class Citizens)
  • Flutter与Kotlin Multiplatform(KMP)深度对比及鸿蒙生态适配解析
  • STM32单片机开发环境搭建 keil/proteus仿真/STM32CubeMX
  • 【OpenGL学习】(三)元素缓冲对象(EBO)的使用
  • Limesurvay系统“48核心92GB服务器”优化方案
  • uniapp的适配方式
  • PDF批量合并拆分+加水印转换 编辑 加密 OCR 识别
  • 软件架构之-论软件系统架构评估以及应用
  • Zookeeper入门(三)
  • 《Vite 报错》ReferenceError: module is not defined in ES module scope
  • 影刀处理 Excel:智能工具带来的高效变革
  • 广域网学习
  • 数据结构与算法——栈和队列
  • Python字符串格式化(一):三种经典格式化方法
  • 从零开始实现大语言模型(十六):加载开源大语言模型参数
  • 《Python星球日记》 第87天:什么是大语言模型 LLM?
  • 1_Spring 【IOC容器的创建】