【转载】BLE蓝牙知识---GATT Profile

本文详细介绍了低功耗蓝牙(BLE)的工作原理,包括GAP和GATT两大核心协议。GAP负责设备发现与连接初始化,定义了外围设备与中心设备的角色及广播机制;GATT则规定了数据交换的具体方式,涉及服务、特征值等概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载自简书:https://www.jianshu.com/p/2b09498b84f2

一. 引言

现在低功耗蓝牙(BLE)连接都是建立在GATT(Generic Attribute Profile)协议之上。GATT是一个在蓝牙连接之上的发送和接收很短的数据段的通用规范,这些很短的数据段被称为属性(Attribute)。

二. GAP

详细介绍GATT之前,需要了解GAP(Generic Access Profile),它在用来控制设备和广播。GAP使你的设备被其他设备可见,并决定了你的设备是否可以或者怎样与合同设备进行交互。例如Beacon设备就只是向外广播,不支持连接,小米手环就等设备就可以与中心设备连接。

1. 设备角色

GAP给设备定义了若干角色,其中主要的两个是:外围设备(Peripheral)和中心设备(Central)。

外围设备:这一般就是非常小或者简单的低功耗设备,用来提供数据,并连接到一个更加相对强大的中心设备。例如小米手环。
中心设备:中心设备相对比较强大,用来连接其他外围设备。例如手机等。

2. 广播数据

在GAP中外围设备通过两种方式向外广播数据:Advertising Data Payload(广播数据)和Scan Response Data(扫描回复),这里包含一些设备额外的信息,例如设备的名字。

3. 广播流程

GAP的广播工作流程如下图所示。

在这里插入图片描述

从图中我们可以清晰看出广播数据和扫描回复数据是怎么工作的。外围设备会设定一个广播间隔,每个广播间隔中,它会重新发送自己的广播数据。广播间隔越长,越省电,同时也不太容易扫描到。

4. 广播的网络拓扑结构

大部分情况下,外设通过广播自己来让中心设备发现自己,并建立GATT连接,从而进行更多的数据交换。也有些情况是不需要连接的,只要外设广播自己的数据即可。用这种方式主要目的是让外围设备,把自己的信息发送给多个中心设备。因为基于GATT连接的方式的,只能是一个外设连接一个中心设备。使用广播这种方式最典型的应用就是苹果的iBeacon。广播工作模式下的网络拓扑图如下:
在这里插入图片描述

三. GATT

GATT的全名是Generic Attribute Profile,他定义两个BLE设备通过叫做Service和Characteristic的东西进行通信。GATT就是使用了ATT(Attribute Protocol)协议,ATT协议把Service,Characteristic遗迹对应的数据保存在一个查找表中,次查找表使用16bit ID作为每一项的索引。
一旦两个设备建立起了连接,GATT就开始起作用了,这也 意味着,你必需完成前面的GAP协议。这里需要说明的是,GATT连接,必须先经过GAP协议。实际上,我们在Android开发中,可以直接使用设备的MAC地址,发起连接,可以不经过扫描的步骤。这并不意味不需要经过GAP,实际上在芯片级别已经给你做好了,蓝牙芯片发起连接,总是先扫描设备,扫描到了才会发起连接。
GATT连接需要特别注意的是:GATT连接是独占的。也就是一个BLE外设同时只能被一个中心设备连接。一旦外设被连接,它就会马上停止广播,这样它就是一个BLE外设同时只能被一个中心设备连接。一旦外设被连接,它就会马上停止广播,这样它就对其他设备不可见了。当设备断开,它又开始广播。
中心设备和外设需要双向通信的话,唯一的方式就是建立GATT连接。

1. GATT连接的网络拓扑

下图展示了GTT连接网络拓扑结构。这里很清楚的显示,一个外设只能连接一个中心设备,而一个中心设备可以连接多个外设。

在这里插入图片描述

一旦建立了连接,通信就是双向的了,对比前面的GAP广播的网络塔扑,GAP通信是单向的。如果你要让两个设备外设能通信,就只能通过中心设备中转。

2. GATT通信事务

GATT通信的双方是C/S关系。外设作为GATT服务端(Server),它维持了ATT的查找表以及service和characteristic的定义。中心设备是GATT客户端(Client),他向Server发起请求。需要注意的是,所有的通信事件,都是由客户端(也叫主设备,Master)发起,并且接收服务端(也叫从设备,Slava)的响应。
一旦连接建立,外设将会给中心设备建议一个连接间隔(Connection Interval),这样,中心设备就会在每个连接间隔尝试去重新连接,检查是否有新的数据。但是,这个连接间隔只是一个建议,你的中心设备可能并不会严格按照这个间隔来执行,例如你的中心设备正在忙于连接其他的外设,或者中心设备资源太忙。

下图展示一个外设(GATT服务端)和中心设备(GATT客户端)之间的数据交流流程,可以看到的是,每次都是主设备发起请求:

在这里插入图片描述

3. GATT结构

GATT事务是建立在嵌套的Profiles,Services和Characteristics之上的,如下如所示:

在这里插入图片描述

  • Profile Profile并不是实际存在于BLE外设上的,它只是一个被Bluetooth SIG或者外设设计者预先定义的Service的集合。例如心率Profile(Heart Rate Profile)就是结合了Heart Rate Service和Device Information Sercvice。所有官方通过GATT Profile的列表可以从这里找到。

  • Service Service是把数据分成一个个的独立逻辑项,它包含一个或者多个Characteristic。每个Service有一个UUID唯一标识。UUID有16bit的,或者128bit的。16bit的UUID是官方通过认证的,需要花钱购买,128bit是自定义的,这个就可以自己随便设置。
    官方通过了一些标准Service,完整列表在这里。以Heart Rate Service为例,可以看到它的官方通过16bitUUID是0x180D,包含3个Characteristic:Heart Rate Measurement,Body Sensor Location和Heart Control Point,并且定义了只有一个第一个必须的,它是可选实现的。

  • Characteristic 在GATT事务中的最低界别的是Characteristic,Characteristic是最小的逻辑数据单元,当然它可能包含一个组关联的数据,例如加速度计的X/Y/Z三轴值。
    与Service类似,每个Characteristic用16bit或者128bit的UUID唯一标识。你可以免费使用Bluetooth SIG官方定义的标准Characteristic,使用官方定义的,可以确保BLE的软件和硬件能相互理解。当然,你可以自定义Characteristic,这样的话,就只有你自己的软件和外设能够相互理解。

    举个例子,Heart Rate Measurement Characteristic,这是上面提到的Heart Rate Service必需实现的- Characteristic,它的UUID是0x2A37。它的数据结构是,开始8bit定义心率数据格式(是UINT8还是UINT16?),接下来就是对应格式的实际心率数据。
    实际上,和BLE外设打交道,主要是通过Characteristic。你可以从Characteristic读取数据,也可以往Characteristic写数据。这样就实现了双向的通信。所以你可以自己实现一个类似串口(UART)的service,这个Service中包含两个Characteristic,一个被配置只读的通道(RX),另一个配置为只写的通道(TX)。

<think>好的,我现在需要处理用户的问题,关于SBP_PERIODIC_EVT事件触发的performPeriodicTask函数如何从SimpleGATTProfile服务中读取第三个特征值并复制到第四个特征值。首先,我需要理解用户提到的上下文和技术背景。 用户提到GATT服务发现是通过GATT_ReadUsingCharUUID来查找特征句柄,参考了引用[1]。这可能意味着在相关代码中,使用该函数来定位特定UUID的特征句柄。接下来,用户想知道performPeriodicTask的功能和具体实现步骤。 首先,我应该分解问题。用户的问题有两个部分:1) performPeriodicTask的功能;2) 如何在这个函数中读取第三个特征值并复制到第四个。需要结合GATT操作和TMOS事件处理机制来分析。 首先,了解TMOS事件系统。TMOS(TI Mesh Operating System)是一个任务调度系统,用于处理事件和任务。SBP_PERIODIC_EVT是一个周期性事件,触发performPeriodiodicTask函数的执行。该函数可能需要处理定期任务,比如读取传感器数据或更新特征值。 接下来,考虑GATT服务的结构。SimpleGATTProfile可能包含多个特征,每个特征有对应的句柄(handle)。第三个和第四个特征值的句柄需要确定,通常这些句柄是在服务发现过程中通过GATT_ReadUsingCharUUID或其他方法获取的,存储在应用层的数据结构中。 读取第三个特征值可能需要使用GATT读取请求,如GATT_ReadCharValue函数,传入第三个特征的句柄。然后,在读取完成后,将获取的数据写入第四个特征,可能需要使用GATT写入请求,如GATT_WriteCharValue函数,指定第四个特征的句柄和数据。 需要注意的是,这些操作可能是异步的。在蓝牙协议栈中,读取和写入操作通常会触发回调函数,处理成功或失败的情况。因此,performPeriodicTask可能需要发起读取请求,然后在回调函数中处理数据,并将数据写入第四个特征。但具体实现是否在同一个函数中处理,还是分阶段,需要看代码结构。 另外,要确保特征的可写属性。第四个特征必须具有WRITE权限,否则写入会失败。同样,第三个特征必须具有READ权限。这些属性在GATT服务定义时确定,比如在SimpleGATTProfile的初始化代码中。 现在,整合这些步骤:当SBP_PERIODIC_EVT触发时,performPeriodicTask被调用。在该函数中,首先使用第三个特征的句柄发起读取请求。读取完成后,在回调函数中获取数据,然后使用第四个特征的句柄发起写入请求,将数据复制过去。 可能需要检查是否有现成的API或示例代码,比如TI的BLE协议栈中处理GATT读写的流程。例如,使用GATT_ReadCharValue和GATT_WriteCharValue函数,并处理对应的回调事件,如CHAR_READ_EVT或CHAR_WRITE_EVT。 此外,还需要考虑数据的存储位置。读取到的数据可能需要暂存在某个缓冲区,再传递给写入函数。同时,错误处理也很重要,比如处理读取失败或写入失败的情况,可能需要重试或记录错误日志。 总结实现步骤大致如下: 1. 在performPeriodicTask中,发起读取第三个特征的请求。 2. 在读取回调中,获取数据,发起写入第四个特征的请求。 3. 处理可能的错误情况。 需要注意的是,如果服务发现尚未完成,特征句柄可能不可用,因此需要确保在服务发现完成后才进行读写操作。用户提到的GATT_ReadUsingCharUUID可能用于服务发现阶段获取特征句柄,之后保存这些句柄供后续使用。 最后,生成相关问题需要考虑用户可能感兴趣的扩展内容,比如错误处理、权限设置、异步操作机制等。</think>### 功能与实现分析 **`performPeriodicTask` 的功能** 该函数由 `SBP_PERIODIC_EVT` 事件触发,用于执行周期性任务(如读取传感器数据、更新特征值等)。在蓝牙协议栈中,此类任务通常通过 GATT 接口完成数据读写。 --- ### 实现步骤 1. **获取特征句柄** 在 SimpleGATTProfile 中,特征值通过预定义的句柄(Handle)访问。假设第三个特征句柄为 `CHAR3_HDL`,第四个为 `CHAR4_HDL`。需在服务初始化时通过 `GATT_ReadUsingCharUUID` 获取并存储这些句柄[^1]。 2. **读取第三个特征值** 使用 `GATT_ReadCharValue` 函数读取数据: ```c uint8_t read_value[BUFFER_SIZE]; GATT_ReadCharValue(connHandle, CHAR3_HDL, read_value, BUFFER_SIZE); ``` 3. **写入第四个特征值** 将读取的数据写入第四个特征。需确保第四个特征具有可写权限: ```c GATT_WriteCharValue(connHandle, CHAR4_HDL, read_value, data_length); ``` 4. **异步回调处理** 若协议栈采用异步模型,需在回调函数中处理读写结果(例如 `CHAR_READ_EVT` 和 `CHAR_WRITE_EVT`)。 --- ### 代码示例(伪代码) ```c void performPeriodicTask() { // 触发读取第三个特征值 GATT_ReadCharValue(connHandle, CHAR3_HDL, NULL, 0); } // 读取回调函数 void CharReadCallback(uint8 *data, uint16 len) { // 将数据写入第四个特征 GATT_WriteCharValue(connHandle, CHAR4_HDL, data, len); } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值