
简介这份PDF文档围绕蓝牙技术在数据采集系统中的应用展开归纳面向测控、传感器网络与物联网方向的工程技术人员及高校学生帮助读者理解如何用短距离无线通信替代传统有线连接解决布线不便、设备移动频繁等场景下的数据采集难题。资源包内含1个PDF文件大小约539KB以图文并茂的文档形式系统梳理蓝牙的射频特性、TDMA结构、跳频技术、微微网与分散网组网方式及软件层次架构并结合IEEE1451.2标准给出无线网络化传感器的结构模型。内容进一步延伸到环境监测、工业自动化、健康医疗、建筑监控与交通管理等具体应用场景读者可从中获取蓝牙数据采集方案的设计思路、协议要点与组网参考适合作为课程学习、项目选型或技术调研的案头资料。目前已有80人学习关注。1. 蓝牙数据采集到底解决了什么现场问题车间里一台老式注塑机没有网口只有 RS232 串口但你想把它的温度、压力曲线接到 MES 里做实时看板。拉网线要穿墙打孔走 Wi-Fi 又怕和产线 AP 抢信道这时候蓝牙数据采集方案就成了一个被低估的选项。蓝牙技术在数据采集系统中的应用核心不是替代工业以太网而是解决三类场景移动设备短距回传、电池供电的传感器节点、以及串口设备无线化改造。它适合做低频次、小批量、对功耗敏感的数据采集比如每小时上报一次的温湿度、手持终端扫码后的即时上传、或者设备点检仪的数据同步。如果你指望用蓝牙跑 1kHz 振动采样那方向就错了。这篇笔记按“选型—组网—落地—避坑”的顺序把蓝牙数据采集从概念到可复现步骤讲透新手能照着搭最小系统熟手能看到参数边界和翻车点。2. 蓝牙数据采集的协议选型与组网方式2.1 经典蓝牙与 BLE 在采集场景下的分工蓝牙技术分两条线经典蓝牙BR/EDR和低功耗蓝牙BLE。数据采集系统里选哪个取决于你的采样频率和供电方式。经典蓝牙适合连续流式传输比如音频采集或高频串口透传单连接速率能到 2Mbps 左右但功耗高电池节点撑不过一天。BLE 则是为间歇性小数据包设计的连接间隔可以设到 7.5ms 到 4s广播模式下甚至不用建立连接就能发数据一颗纽扣电池跑几个月很常见。我一般这样判断如果采集节点是市电供电、数据连续且单次包大于 512 字节走经典蓝牙的 SPP串口协议最省事上位机当串口用就行。如果是电池供电、每分钟上报一次、单包几十字节BLE 的 GATT 通知模式是首选。注意 BLE 的实际吞吐受连接间隔和 MTU 限制默认 MTU 23 字节时有效载荷只有 20 字节想传大包必须协商 MTUAndroid 上可以到 517iOS 上一般 185 左右。2.2 组网拓扑点对点、星型与广播模式怎么选数据采集系统的拓扑决定了你后续的代码结构。点对点最简单一个采集端对一个接收端适合手持设备对接单台仪器。星型是一个主机连多个从机BLE 里叫 Central 连多个 Peripheral但要注意多数手机作为 Central 同时连 7 个左右就接近极限了工业网关用 nRF52840 这类芯片可以做到 20 个连接但连接间隔会拉长实时性下降。广播模式是 BLE 特有的采集端只发广播包接收端不建立连接直接扫。这种方式最省电采集端发完就睡适合温湿度、门磁这类极低频场景。缺点是广播包有效载荷只有 31 字节且不可靠丢包是常态你得在应用层做冗余或补传。我见过有人用广播模式传 GPS 坐标结果丢包率 30%后来改成连接模式才稳定。2.3 用 Python 和 Bleak 搭一个最小 BLE 采集端下面这段代码用 Python 的 Bleak 库扫描并连接一个 BLE 温湿度采集器读取 GATT 特征值。Bleak 跨平台Windows、Linux、macOS 都能跑适合做上位机快速验证。import asyncio from bleak import BleakScanner, BleakClient # 采集器的广播名称实际用扫描结果替换 TARGET_NAME TH-Sensor-01 # 温湿度特征值的 UUID需根据设备手册填写 CHAR_UUID 00002a6e-0000-1000-8000-00805f9b34fb async def main(): # 扫描 5 秒找到目标设备 devices await BleakScanner.discover(timeout5.0) target None for d in devices: if d.name and TARGET_NAME in d.name: target d break if not target: print(未找到采集器检查设备是否在广播) return async with BleakClient(target.address) as client: print(f已连接 {target.address}) # 读取一次特征值 value await client.read_gatt_char(CHAR_UUID) # 假设返回 4 字节前两字节温度整数后两字节湿度整数 temp int.from_bytes(value[0:2], byteorderlittle) / 100.0 humi int.from_bytes(value[2:4], byteorderlittle) / 100.0 print(f温度 {temp} C湿度 {humi} %RH) asyncio.run(main())逻辑说明先扫描广播找到目标设备再建立 GATT 连接然后读取指定 UUID 的特征值。参数说明timeout控制扫描时长车间设备多时建议设 10 秒CHAR_UUID必须查设备手册不同厂商不一样字节解析方式取决于采集端固件的打包格式常见的是小端序、温度乘 100 存整数。如果读不到数据先确认特征值是否支持 read 属性很多 BLE 采集器只支持 notify那就得改成订阅通知。3. 从串口到蓝牙采集端固件与数据打包3.1 串口采集器怎么接蓝牙透传模块大量数据采集系统前端是 RS485 或 RS232 的传感器改造思路是加一个蓝牙透传模块比如 HC-05经典蓝牙或 JDY-31BLE。接线就三根模块 TX 接采集器 RX模块 RX 接采集器 TX共地。注意电平匹配3.3V 模块不能直接接 5V 串口中间加电平转换或电阻分压。配置环节用 AT 指令。以 HC-05 为例上电前按住按键进入 AT 模式串口发ATNAMECollector01改设备名ATPSWD1234改配对码ATUART9600,0,0设波特率。这些参数要和采集器串口一致否则收到乱码。BLE 模块的 AT 指令集不同JDY-31 用ATNAME和ATBAUD但广播间隔用ATADVIN设单位是 10ms设成 100 就是 1 秒广播一次。3.2 数据打包格式与校验别让丢包变成脏数据蓝牙链路本身有 CRC 校验但应用层还是得自己加一层包结构因为采集端可能因为缓冲区溢出丢整包。我常用的格式是帧头 2 字节0xAA 0x55 长度 1 字节 载荷 N 字节 CRC16 校验 2 字节。载荷里再按传感器通道编号、时间戳、数值依次排列。// 采集端打包示例假设两个通道每个通道 2 字节 typedef struct { uint8_t header[2]; // 0xAA 0x55 uint8_t len; // 载荷长度 uint16_t ch1; // 通道1原始值 uint16_t ch2; // 通道2原始值 uint16_t crc; // 前 len3 字节的 CRC16 } SamplePacket; void pack_and_send(uint16_t v1, uint16_t v2) { SamplePacket pkt; pkt.header[0] 0xAA; pkt.header[1] 0x55; pkt.len 4; // ch1ch2 共 4 字节 pkt.ch1 v1; pkt.ch2 v2; pkt.crc crc16((uint8_t*)pkt, 3 pkt.len); uart_send((uint8_t*)pkt, sizeof(pkt)); }逻辑说明先填帧头和长度再填通道数据最后算 CRC 追加到包尾。参数说明len只算载荷长度不算帧头和校验本身CRC16 多项式用 0x1021 或 0xA001 都行关键是收发两端一致。接收端解析时先找帧头再读长度然后收够字节数后校验 CRC校验失败直接丢包并计数。这个计数在上位机看板里显示出来丢包率超过 5% 就得查天线或降低上报频率。3.3 采集频率与连接间隔的匹配计算BLE 连接模式下采集端的数据不是想发就发得等连接事件。连接间隔设 100ms那最快也就 10 次/秒。如果你采集频率是 50Hz就必须在采集端做缓冲攒够 5 个样本再打包发一次。缓冲深度取决于 RAMnRF52832 有 64KB RAM开 1KB 缓冲能存 100 多个包够用。计算公式有效上报率 1 / 连接间隔 × 每包样本数。比如连接间隔 50ms每包 10 个样本有效上报率就是 200 样本/秒。但实际受 MTU 限制每包不能无限大BLE 4.2 以上单包最多 244 字节扣掉协议头载荷 200 字节左右。按每个样本 4 字节算一包最多 50 个样本。所以连接间隔 50ms、每包 50 样本时理论上限 1000 样本/秒但实际因为重传和调度打七折比较稳妥。4. 蓝牙数据采集系统避坑与排查4.1 连接频繁断开日志显示超时现象采集端和接收端每隔几十秒断一次重连后不久又断。原因BLE 连接参数里的 supervision timeout 设得太小或者从机在连接事件间隙进入了深度睡眠没及时唤醒。解决把 supervision timeout 从默认的 2 秒调到 6 秒以上同时检查从机固件的低功耗模式确保射频唤醒中断优先级最高。另外Wi-Fi 和蓝牙共用 2.4GHz 频段车间 AP 密集时干扰严重把 BLE 的广播信道固定在 37、38、39 中干扰最小的一个或者改用经典蓝牙的跳频模式。4.2 读到的数据全是 0 或固定值现象GATT 读取成功但值一直是 0x0000 或某个不变的数字。原因特征值 UUID 选错了读到了电池电量或设备信息这类静态特征或者采集端固件根本没往这个特征值写数据写的是另一个 notify 特征。解决用 nRF Connect 这类调试 App 把设备所有服务列出来逐个读找到那个数值会变的。如果只有 notify 属性就订阅通知而不是主动读。还有一种情况是采集端传感器初始化失败固件里没做错误处理直接发了默认零值这时候得看采集端的串口日志。4.3 多设备同时采集时数据串包现象星型组网下主机收到的数据包偶尔混入了其他从机的数据。原因从机地址没做区分或者主机在解析时没按连接句柄隔离缓冲区。解决在应用层包结构里加 1 字节设备 ID主机收到后先查 ID 再入库。另外BLE 协议栈本身按连接句柄分发数据但如果你用了透传模块的“多连接”模式模块可能把不同连接的数据混在一个串口流里输出这时候必须靠包里的 ID 区分。我一般会在采集端固件里把设备 MAC 后两字节写进包头的保留字段。4.4 电池节点续航远低于预期现象标称能用半年的 BLE 温湿度节点实际两周就没电。原因广播间隔设太短或者连接参数里的 slave latency 没启用。解决广播间隔从 100ms 改成 1s 甚至 2s续航能翻十倍。连接模式下启用 slave latency比如 latency4从机可以跳过 4 个连接事件不响应只在第 5 个事件醒来。另外检查采集端传感器的供电很多温湿度芯片连续测量模式功耗是单次测量的几十倍改成主机发命令才测一次。4.5 上位机扫描不到设备现象手机能搜到蓝牙采集器但电脑用 Bleak 或 Windows API 搜不到。原因Windows 蓝牙栈对 BLE 广播的过滤策略不同或者电脑蓝牙适配器太老不支持 BLE 4.0 以上。解决先确认适配器支持 BLEWindows 设备管理器里看蓝牙版本。如果支持把扫描超时从 5 秒加到 15 秒Windows 上首次扫描往往慢。还不行就换 Linux 主机BlueZ 栈对 BLE 支持更透明。另外有些采集器广播包里不含设备名Bleak 的discover返回的 name 是 None得靠 MAC 地址前缀过滤。5. 把蓝牙采集数据接进时序库的进阶技巧5.1 用 Telegraf 做 BLE 到 InfluxDB 的桥接上位机收到数据后别直接写文件接时序库才能做看板和告警。Telegraf 有 BLE 输入插件吗官方没有但可以用 exec 插件调 Python 脚本或者用 MQTT 中转。我一般这样Python 脚本订阅 BLE 通知解析后转成 JSON 发到本地 MQTT brokerTelegraf 的 MQTT 消费者插件再写 InfluxDB。这样解耦BLE 脚本崩了不影响入库。import paho.mqtt.publish as publish import json def on_notify(sender, data): temp int.from_bytes(data[0:2], little) / 100.0 humi int.from_bytes(data[2:4], little) / 100.0 payload json.dumps({temp: temp, humi: humi}) publish.single(sensor/th01, payload, hostnamelocalhost)逻辑说明在 BLE 通知回调里解析数据转 JSON 后发到 MQTT 主题。参数说明主题按设备编号分层方便 Telegraf 用通配符订阅hostname填本机或 broker 地址。Telegraf 配置里data_format jsontopic_tag topic这样 InfluxDB 里能按设备查。5.2 时间戳对齐采集端时间不准怎么办BLE 采集端为了省电往往不带 RTC上报的数据没有时间戳。上位机收到时才打时间戳但链路延迟和缓冲会导致时间偏移。我的做法是采集端在包里的保留字段放一个 16 位的相对 tick上位机收到后用自己的时间减去一个标定好的固定延迟。标定方法让采集端每秒发一个包连续收 100 个算平均延迟。这个延迟包括连接间隔、传输时间和上位机处理时间一般在 20ms 到 200ms 之间。对温湿度这种慢变量200ms 误差无所谓对振动采集就必须用采集端自己的 RTC 或 tick 做时间基准。5.3 一个具体技巧用广播模式做低功耗点检设备点检场景下点检员拿着手机走到设备旁手机自动扫到该设备的广播包弹出点检项。这种不需要连接采集端只发广播手机扫到就解析。实现要点采集端广播包里放设备 ID 和最近一次采集值广播间隔 500ms发射功率调到 0dBm 覆盖 3 米足够。手机端用BleakScanner的detection_callback实时回调扫到目标 ID 就震动提示。这个方案比连接模式省电得多采集端一颗 CR2032 能撑一年。我踩过的坑是广播包长度超 31 字节被截断后来把设备 ID 压缩到 4 字节数据只放 2 字节刚好塞进厂商自定义数据字段。这套方案我前后调了三个月最大的教训是别在采集端做复杂计算能原样传就原样传解析和校准放到上位机。蓝牙链路本身就不稳定采集端越简单出问题的环节越少。希望帮到你。本文还有配套的精品资源点击获取