广播与扫描机制:BLE设备如何“打招呼”

广播和扫描,是BLE通信的第一步。说白了,就是设备怎么让别人发现自己,以及怎么发现别人。

我刚接触BLE时,总觉得广播就是简单发个包。后来做多设备连接项目,才发现广播类型选错、数据格式写错,设备之间根本“聊”不起来。今天咱们就把这块彻底理清楚。

广播类型:四种“打招呼”方式

BLE广播有四种类型。每种类型决定了设备能不能被连接、能不能响应扫描。我习惯把它们分成两组来看:

广播类型 可连接 可扫描 典型场景
可连接不可扫描广播 ✅ ❌ 传统蓝牙配对
可连接可扫描广播 ✅ ✅ BLE外设(心率计、温度计)
不可连接可扫描广播 ❌ ✅ 信标(Beacon)
不可连接不可扫描广播 ❌ ❌ 单向广播(如广告推送)

关键点:可连接广播必须同时支持扫描响应。这是BLE协议规定的,不是你想改就能改。

我在项目中遇到过一个问题:设备明明在广播,手机就是扫不到。查了半天,发现广播类型配成了“不可连接不可扫描”。嗯,这种低级错误,犯过一次就记住了。

广播数据格式:AD Structure 详解

广播数据不是随便塞的。它遵循AD Structure格式。每个AD Structure由三部分组成:

  • Length(1字节):表示AD Type + AD Data的总长度
  • AD Type(1字节):标识数据类型(如设备名、UUID、Tx Power等)
  • AD Data(N字节):具体数据内容

举个例子,一个包含设备名和UUID的广播包,结构是这样的:

// 广播数据示例(十六进制)
// 设备名:"BLE_Dev"
// 服务UUID:0x180D(心率服务)

0x08 0x09 42 4C 45 5F 44 65 76    // AD Structure 1: 设备名
  ↑    ↑   ↑
Length Type Data("BLE_Dev")

0x03 0x02 0x0D 0x18               // AD Structure 2: 16位UUID
  ↑    ↑   ↑
Length Type Data(0x180D小端序)

小技巧:我习惯用nRF Connect或LightBlue抓包看广播数据。看到原始十六进制,对照AD Type表,很快就能定位问题。

常见的AD Type值:

AD Type值 含义 数据长度
0x01 Flags(广播标志) 1字节
0x02/0x03 16位服务UUID(完整/部分) 2字节
0x06/0x07 128位服务UUID(完整/部分) 16字节
0x08/0x09 设备名(缩短/完整) 可变
0x0A Tx Power Level 1字节
0xFF 制造商自定义数据 可变

注意:广播包最大31字节。你塞的数据越多,留给扫描响应的空间就越少。我一般把核心信息放广播包,扩展信息放扫描响应。

扫描请求与扫描响应:一问一答

扫描请求(Scan Request)和扫描响应(Scan Response),是BLE里一个很巧妙的设计。

你想想看:广播包只有31字节,不够用怎么办?扫描响应就是解决方案。

  • 扫描请求:扫描设备发给广播设备,说“嘿,你还有更多信息吗?”
  • 扫描响应:广播设备回复,把额外数据发过去

这个过程只在主动扫描模式下发生。被动扫描不会发扫描请求,也就拿不到扫描响应数据。

我曾经调试一个多设备连接项目,发现某些设备扫描响应数据总是不完整。后来定位到是广播设备处理扫描请求太慢,导致响应超时。解决办法是优化广播间隔,给扫描响应留足时间窗口。

主动扫描 vs 被动扫描

这两种扫描方式,区别在于扫描设备是否主动“搭话”。

特性 主动扫描 被动扫描
发送扫描请求 ✅ 是 ❌ 否
获取扫描响应 ✅ 可以 ❌ 不能
功耗 较高 较低
数据完整性 更完整 仅广播包
典型场景 设备发现、连接建立 信标检测、低功耗监听

说白了,主动扫描就是“主动问”,被动扫描就是“只听不说”。

我建议:做多设备连接时,用主动扫描。因为你需要完整的设备信息(设备名、服务UUID等)来做连接决策。如果只是做信标检测,被动扫描就够了,省电。

知识体系总览

下面这张图,把广播与扫描的核心逻辑串起来了。我画图时习惯把流程和关键参数都标清楚,方便你对照理解。

BLE广播与扫描核心流程 广播设备 (外设/信标) 扫描设备 (手机/网关) 广播包(31字节) 扫描请求(主动扫描时) 扫描响应(额外数据) 广播类型 可连接可扫描 可连接不可扫描 不可连接可扫描 不可连接不可扫描 扫描方式 主动扫描 发扫描请求 + 收扫描响应 被动扫描 只收广播包,不发请求

我的经验:画这种流程图时,把广播类型和扫描方式放在一起看,能帮你快速理解设备之间的交互逻辑。我每次做新项目,都会先画一张类似的图,确认流程没问题再写代码。

避坑指南

做广播和扫描开发,有几个坑我踩过,分享给你:

  • 广播间隔别设太短:我曾经为了快速发现设备,把广播间隔设到20ms。结果功耗飙升,设备发热。后来改成100ms,效果一样好。
  • 扫描窗口和扫描间隔要匹配:扫描窗口设得比扫描间隔还大,会导致扫描周期错乱。我一般设扫描窗口为扫描间隔的50%。
  • 广播数据别超31字节:这个限制是硬性的。超了协议栈会直接报错,或者静默截断。我习惯先算好长度再填充。
  • 扫描响应数据也要算在31字节内:广播包和扫描响应各自独立,但每个都是31字节上限。别搞混了。

重要提醒:广播和扫描的参数配置,直接影响连接成功率。我建议你在开发初期就用抓包工具验证广播数据格式,别等到联调时才发现问题。

好了,广播与扫描机制就讲到这里。记住:广播是设备“说话”的方式,扫描是设备“听”的方式。选对类型、配好数据、理解流程,多设备连接的第一步就走稳了。