扫码加入

  • 正文
  • 相关推荐
申请入驻 产业图谱

嵌入式工程师必看:蓝牙基础知识

20小时前
284
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

大家好,我是杂烩君。

嵌入式开发中,蓝牙是一块很独立的内容,常常需要专人专岗来对接。

但有时候我们也需要对接蓝牙相关功能,了解一些基础知识,既方便跟蓝牙同事沟通协作,也能对项目中各个模块保持一定的敏感度。

1. 经典蓝牙与低功耗蓝牙

蓝牙不是一个单一协议,它是一个庞大的协议族。我们平时说的"蓝牙",其实包含两大分支:经典蓝牙(BR/EDR)和低功耗蓝牙(BLE)。

这两者差别很大,下面这张表格帮你快速区分:

对比维度 经典蓝牙(BR/EDR) 低功耗蓝牙(BLE)
传输速率 1-3 Mbps,带宽大 1 Mbps(BLE 5.0可达 2 Mbps)
功耗水平 高,持续传输耗电明显 极低,纽扣电池能撑一两年
典型场景 蓝牙音箱、耳机、车载音频 智能手环、传感器、物联网终端
协议复杂度 复杂,涉及音频编解码、高速数据流 精简,专为短数据、低频交互设计
嵌入式对接频率 偶尔碰到(音频类项目) 非常高频,绝大多数IoT项目都用它

说白了,你要是在做物联网、穿戴设备、传感器这类项目,日常打交道的基本都是BLE。手机APP读设备的温湿度数据、下发控制指令、OTA升级——这些全是BLE的活儿。所以接下来所有内容,我们都围绕BLE展开。

2. BLE协议栈分层

蓝牙的协议栈架构图,从物理层应用层内容很多,非必要我们不用陷进去。

只需要知道一点:底层的PHY(物理层)、LL(链路层)、L2CAP(逻辑链路控制与适配层),芯片厂商(Nordic、Dialog、TI、瑞昱……)全都封装SDK了,我们碰都碰不到,也不需要碰。我们真正要关心的就三层半——GAP、GATT、HCI,再加上我们自己写的应用层代码。

用一个生活化的类比把这几层讲清楚——假设你在相亲:

GAP层 = 相亲的认识流程:你在什么平台上展示资料(广播)、对方怎么找到你(扫描发现)、双方怎么加微信(连接配对)、聊不来怎么删好友(断开)。GAP管的就是设备间"能不能认识、怎么认识"。

GATT层 = 相亲后的信息交换规则:加了微信之后,你的朋友圈有什么内容(服务和特征值)、对方能看哪些(读权限)、能给你留言吗(写权限)、你会主动发朋友圈通知对方吗(通知推送)。GATT管的就是"连上之后传什么数据、怎么传"。

HCI层 = 你和手机之间的操作接口:你想发消息,得在手机上点按钮,手机把你的操作翻译成底层的网络请求。HCI就是应用层和底层芯片之间的命令接口,我们调SDK的API,底层走的就是HCI指令。

应用层 = 你本人:决定发什么内容、怎么回复、出了问题怎么处理,这部分逻辑是你自己写的。

搞清楚这个分工,对接的时候就不会迷路了。记住一句口诀:GAP管连接,GATT管数据,HCI管通信。先配GAP让手机搜得到、连得上,再配GATT让数据传得了,中间出了问题看HCI的状态反馈。

3. 5个关键概念

协议栈分层搞明白了,接下来看几个对接应用层时绑不开的核心概念。

3.1 广播(Advertising)——设备的"存在感"

BLE设备想被手机发现,必须主动往外发"广播包"。你可以理解成,设备在不停地往四周喊:"我叫温湿度传感器_01,我的地址是XX:XX:XX:XX:XX:XX,想跟我聊天的来连我!"

手机打开蓝牙扫描,就是在"听"周围有没有人在喊。

我们在代码里要做的就是配好广播参数然后启动广播,核心参数有三个:

广播名称

    • :手机扫描列表里显示的设备名,取个好认的名字;

广播间隔

    • :多久发一次广播包,一般设100ms-500ms。间隔越短手机越容易搜到,但功耗越高,需要在搜索速度和续航之间取个平衡;

广播内容

    :除了名称和地址,还可以塞一些自定义数据(广播包最大31字节),比如设备电量、固件版本。

通常我们只需要调用厂商SDK提供的接口、传入对应的参数就行,底层怎么把广播包调制成射频信号发出去,完全不用操心。

3.2 UUID——数据接口的"门牌号"

UUID(Universally Unique Identifier)是GATT层给每个数据接口分配的唯一标识。你可以把它理解成"门牌号"——手机APP要读温度数据,得知道温度数据的UUID是啥;设备要接收控制指令,也得定义好对应的UUID,双方对上号才能通信。

GATT层的数据组织方式是一个树形结构,关系很清晰:

一个设备可以有多个"服务"(Service),每个服务下面挂多个"特征值"(Characteristic),每一级都有自己的UUID。手机APP对接的时候,先按服务UUID找到对应服务,再按特征值UUID找到具体的数据接口。

关于UUID格式,有两种你需要知道的:

16位UUID:蓝牙SIG官方定义的标准UUID,比如 0x180A 代表设备信息服务,0x2A6E 代表温度特征值。如果你用的数据类型刚好有标准定义,直接用16位的就行。

128位UUID:自定义数据用这个,格式类似 0000FFE0-0000-1000-8000-00805F9B34FB。我建议凡是自定义服务和特征值,一律用128位,避免跟标准UUID撞车。

3.3 特征值属性——决定数据"能怎么用"

每个特征值都有"属性"标记,它决定了手机端能对这条数据做什么操作。这是对接时最容易出问题的地方,属性配错了,功能直接不通。

常用的四种属性:

一个特征值可以同时拥有多个属性。比如温度特征值,我一般设成"可读 + 通知"——手机既可以主动来问"现在多少度"(Read),设备也会定时主动推数据过去(Notify)。采集间隔特征值设成"可读 + 可写"——手机能查当前间隔是多少(Read),也能下发新的间隔值(Write)。

实际项目中,Notify(通知)用得最多。因为大部分IoT设备的工作模式是:传感器采集到数据就主动上报,不需要手机每次来轮询。这样通信效率高,功耗也低。

3.4 BLE连接与数据交互的完整过程

前面讲了广播、UUID、特征值属性,现在把它们串起来,看一次完整的BLE数据交互到底是怎么走的:

看完这张图,我们对整个BLE交互流程应该就有底了。手机先通过广播发现设备、发起连接,连上之后按UUID找到对应的服务和特征值,然后就可以读写数据、接收通知推送了。

3.5 主从角色——谁发起连接,谁等着被连

BLE把设备分成两种角色:

从设备(Slave / Peripheral):我们做的传感器、手环、门锁,绝大多数都是从设备。从设备的工作就是广播自己、等别人来连、连上之后提供数据服务。嵌入式IoT项目里,90%以上你碰到的都是从设备的开发。

主设备(Master / Central):手机、平板、蓝牙网关,这些是主设备。主设备负责主动扫描、主动连接、主动发起数据请求。如果你做的是蓝牙网关(需要同时连好几个传感器汇总数据),那你得做主设备开发,难度会高一些。

4. 应用层代码的核心工作流程

还是以"BLE温湿度采集设备"为例,应用层代码的整体流程长这样:

图里的流程已经很清晰了,补充几个图上体现不出来的点:

GAP配置决定能不能被搜到,GATT配置决定"连上后能交换什么数据",两者缺一不可,顺序也不能反。

异常处理别偷懒

      • ——连接断开要重新广播、数据发送失败要重试、指令解析出错要返回错误码,这些直接关系到产品稳定性。我们不用碰底层蓝牙驱动,芯片SDK把射频收发、链路管理都封装好了,我们的活儿就是

    配参数 + 写交互逻辑 + 做异常兜底

5. 写在最后

蓝牙协议栈看着庞大,但嵌入式工程师要抓的就三条线:GAP管连接、GATT管数据、HCI管通信。把广播配置、UUID定义、特征值属性、数据交互流程、异常处理这几件事搞清楚,日常的BLE应用层对接就不会有大问题。

我自己的经验是:刚接触BLE的时候,别急着从零写代码,先把芯片SDK的demo跑起来,改几个参数让手机连上设备、收发数据。在demo的基础上一点一点加自己的逻辑,比从零搭建快得多,也不容易出错。

碰到问题别闷头查协议文档,先拿nRF Connect或者LightBlue这类蓝牙调试APP抓一下,看看广播包对不对、UUID对不对、特征值属性对不对,80%的问题靠工具就能定位。

相关推荐

登录即可解锁
  • 海量技术文章
  • 设计资源下载
  • 产业链客户资源
  • 写文章/发需求
立即登录

本公众号专注于嵌入式技术,包括但不限于C/C++、嵌入式、物联网、Linux等编程学习笔记,同时,公众号内包含大量的学习资源。欢迎关注,一同交流学习,共同进步!