BLE学习笔记(0.0) —— 基础概念(0)

前言

(1)本章节主要是对BLE技术进行简单的介绍,熟悉蓝牙技术的发展过程,了解相关术语方便后续的学习。
(2)为了防止单篇博客太长以至于看不下去,因此我基础概念章节分为两篇来写。
(3)叠甲一:本人刚接触BLE开发不久,文章尽可能的查询了各方面资料进行学习。如果依旧存在错误,愿各位大佬不吝赐教。
(4)叠加二:本文仅用于科普入门,因此讲解深度并不是很深,愿周知。

蓝牙与BLE关系

蓝牙的起源

(1)1994-1997年之间,包括爱立信,英特尔,诺基亚在内的一些科技公司,想要制定一种短距离无线通信协议,用于各种电子设备之间通讯,取代当时的有线通信形式。
(2)可是各个公司都推出了自己的通信协议,不同厂商的设备并不兼容。于是在1997年的一次通信会议上,各个厂商希望制定一种统一的通信协议,使的他们的设备相互兼容。在这场会议中,商定了“Bluetooth”作为通信协议的名称。

  • Bluetooth是由一位英特尔的工程师 Jim Kardach 推荐的。原因是他当时正在阅读有关维京人和哈拉尔国王的历史小说,由于哈拉尔国王以统一了因宗教战争和领土争议而分裂的挪威与丹麦而闻名于世,国王的成就与此次会议的的理念不谋而合,而且传说哈拉尔国王有一个坏死的牙齿,变成的蓝色,所以世人就给他起了个绰号“Bluetooth”,因此该工程师提议使用哈拉尔国王的绰号“Bluetooth”作为通信协议的名称。
  • 蓝牙的图标也是和这位哈拉尔国王有关。 哈拉尔国王真名拼写“Harald”,蓝牙组织将国王的真名“Harald”和绰号“Bluetooth”的首字母拼合在一起,配以蓝牙的底图,就形成了蓝牙图标。

>

(3)1998 年 2月,5个跨国大公司,包括爱立信诺基亚BM东芝Intel 组成了一个特殊兴趣小组(SIG),他们共同的目标是建立一个全球性的小范围无线通信技术,即现在的蓝牙。

蓝牙发展

(1)1999年,爱立信联合其他科技公司在制定了蓝牙1.0 协议版本。早期的协议版本在兼容性安全性传输速率等方面都有很多的不足,所以此本并未得到大量应用。此时的蓝牙称为基本码率Basic Rate,简称BR
(2)2004年,蓝牙2.0的协议版本发布,增加了增强速率模式(EDR:Enhanced DataRate),同传输速率提升至2-3Mbps.
(3)2009年,引入全新的交替射频技术(AMP:Alternate MACIPHY),推出蓝牙3.0+ HS(High Speed)高速蓝牙的功能。HS使得Bluetooth能利用Wi-Fi作为传输方式进行数据传输,允许蓝牙协议栈针对任一任务动态地选择正确射频,通过瞬间使用消费者设备中已存在的辅助无线电提供更快的吞吐量,使其支持的传输速度最高可达24Mbps
(4)2010年,推出蓝牙4.0标准,它是第一个综合性规范,其加入了全新的蓝牙低功耗技术,即蓝牙 4.0集三种规格于一体。最重要的特点就是省电,可以使一粒纽扣电池连续工作数年。三种规格如下:

  • 传统蓝牙(Classic Bluetooth):适用于高数据传输需求的应用,如音频和视频流。
  • 低功耗蓝牙(Bluetooth Low Energy, BLE):适用于低数据传输需求且需要长时间运行的设备,如传感器和可穿戴设备。
  • 高速蓝牙(High Speed Bluetooth)高速蓝牙并不是一种独立的蓝牙类型,而是经典蓝牙的一种增强模式。它利用了 Wi-Fi 技术来实现更高的数据传输速率。具体来说,高速蓝牙允许设备在需要传输大量数据时,切换到 Wi-Fi 连接,从而实现更快的数据传输速度。适用于需要快速传输大量数据的场景。

(5)2016年,推出蓝牙5.0标准。相比较蓝牙4.0,具有 2倍的数据速率、4 倍的覆盖范围和8倍的广播能力。新增高精度室内定位的功能,针对 loT 物联网进行底层优化,力求以更低的功耗和更高的性能为智能家居服务。

在这里插入图片描述

关于经典蓝牙和高速蓝牙的问题

在编程时,通常只会看到选择 BR/EDR(经典蓝牙)和 BLE(低功耗蓝牙)的选项,而看不到关于高速蓝牙(High Speed Bluetooth)的内容,主要有以下几个原因:

  1. 高速蓝牙的实现方式:高速蓝牙(High Speed Bluetooth)并不是一种独立的蓝牙模式,而是经典蓝牙的一种增强功能。它通过结合 Wi-Fi 技术来实现更高的数据传输速率。这意味着高速蓝牙的实现依赖于设备同时支持蓝牙Wi-Fi,并且需要在蓝牙协议栈之外进行额外的 Wi-Fi 配置和管理。但并不是所有的蓝牙设备同时支持蓝牙和 Wi-Fi 的硬件能力。
  2. 开发工具和库的支持:大多数蓝牙开发工具和库主要关注经典蓝牙(BR/EDR)和低功耗蓝牙(BLE),因为这两种模式是蓝牙技术的核心部分,应用最为广泛。高速蓝牙的实现涉及到跨协议的操作(蓝牙Wi-Fi),这增加了开发的复杂性,因此在标准的蓝牙开发工具和库中通常不会直接提供对高速蓝牙的支持。即使进行了相关支持,高速蓝牙在编程时通常被归类到经典蓝牙中,因为高速蓝牙本质上是经典蓝牙(BR/EDR)与Wi-Fi技术的结合。
  3. 应用场景的需求:高速蓝牙主要用于需要传输大量数据的特定应用场景,如大文件传输或视频流传输。然而,许多蓝牙应用并不需要如此高的数据传输速率,经典蓝牙和低功耗蓝牙已经能够满足大多数应用的需求。因此,开发者在编程时通常只需要选择 BR/EDRBLE 即可。

综上所述,在编程时通常只会看到选择 BR/EDRBLE 的选项,而看不到关于高速蓝牙的内容,是因为高速蓝牙的实现方式复杂,开发工具和库的支持有限,以及应用场景和硬件支持的限制。而且高速蓝牙并非独立的技术模式,而是经典蓝牙的一种特性,因此在编程时通常不会单独列出高速蓝牙的选项,而是集成在经典蓝牙(BR/EDR)中一同使用。

蓝牙的三种LOGO和设备类型

三种LOGO

(1)上面我们说了,蓝牙4.0是第一个综合性规范,它集三种规格于一体。但是这三种规格又有不同的应用场景,在某些特定的场景中,我们仅仅只需要一种规范即可满足任务。因此蓝牙兴趣小组(SIG)规定了如下三种LOGO用于标识版本之间的区别和兼容性。

在这里插入图片描述

(2)这三种LOGO的含义如下:

  • Bluetooth Smart Ready:同时支持经典蓝牙( BR/EDR)和低功耗(BLE)技术,设备可以与两种类型的蓝牙产品通信。如手机。
  • 传统 Bluetooth:仅支持经典蓝牙( BR/EDR)。如用于传输语音的蓝牙耳机。
  • Bluetooth Smart:仅支持低功耗蓝牙(BLE)技术的设备,主要用于低功耗和低复杂度的应用。如可穿戴设备、健身追踪器等。

单模与双模

(1)蓝牙4.0以后的版本分为两种模式,单模蓝牙双模蓝牙

  • 单模设备只支持低功耗蓝牙(BLE),如用 nRF51822 开发的蓝牙设备即为单模设备,单模设备对低功耗的要求很高
  • 双模设备:既支持经典蓝牙( BR/EDR)也支持低功耗蓝牙(BLE),这两种技术使用同一个射频前端和天线,双模设备一般都有足够的供电能力,对低功耗的要求不高。

在这里插入图片描述

(3)下图为单模设备和双模设备与传统蓝牙设备的兼容性:

  • 双模设备和双模设备:可以通过LE通信,也可以通过传统蓝牙通信。
  • 单模设备和单模设备:通过 LE 通信。
  • 传统蓝牙和传统蓝牙:通过传统蓝牙(经典蓝牙)通信。
  • 双模设备和单模设备:通过 LE 通信。
  • 双模设备和传统蓝牙:通过传统蓝牙(经典蓝牙)通信。
  • 单模设备和传统蓝牙:不能通信。

在这里插入图片描述

BLE的体系结构

BLE的三层结构

(1)BLE体系结构如下(新手百分百看不懂下面的内容,但是还是建议先过一遍,后续会再进一步进行介绍):
<1>控制层(Controller)

  • PHY 层(Physicallayer 物理层)PHY 层用来指定 BLE 所用的无线频段,调制解调方式和方法等。PHY 层还决定了传输数据的速度、整个 BLE 芯片的功耗、灵敏度以及 selectivity 等射频指标的配置。
  • LL层(Link Layer 链路层)LL层是整个BLE协议栈的核心,也是BLE协议栈的难点和重点。像NordicBLE协议栈能同时支持20个link(连接),就是LL层的功劳。LL层要做的事情非常多,比如具体选择哪个射频通道进行通信,怎么识别空中数据包,具体在哪个时间点把数据包发送出去,怎么保证数据的完整性,ACK如何接收,如何进行重传,负责广播、扫描、建立和维护连接,以及确保数据包按照正确的方式组织、正确地校验值和加密序列等等。LL层只负责把数据发出去或者收回来,对数据进行怎样的解析则交给上面的GAP或者GATT
  • 主机控制器接口 HCI(Host controller interface)这个是可选的,在主机(Host)和控制器(Controller) 之间提供一个标准化的接口。该层可以由应用程序接口 API实现或者使用硬件接口 UARTSPIUSB 来控制。控制器通过 HCI发送数据和事件给主机,主机通过 HCI发送命令和数据给控制器。

<2>主协议层(HOST)

  • GAP层(Generic access profile)GAP是对LLpayload(有效数据包)如何进行解析的两种方式中的一种,而且是最简单的那一种。GAP简单的对LL payload进行一些规范和定义,因此GAP能实现的功能极其有限。GAP目前主要用来进行广播,扫描和发起连接等
  • L2CAP 层(Logic link control and adaptation protocol)L2CAPLL 进行了一次简单封装,LL只关心传输的数据本身,L2CAP 就要区分是加密通道还是普通通道,同时还要对连接间隔进行调整。通俗来说L2CAP就是快递分拣工,快递来到中转站,分拣工需要根据快递的地址来判断运往哪里。
  • SMP(Secure manager protocol)SMP 用来管理 BLE 连接的加密和安全的,如何保证连接的安全性,同时不影响用户的体验,这些都是 SMP 要考虑的工作。
  • ATT(Attribute protocol):简单来说,ATT 层用来定义用户命令及命令操作的数据,比如读取某个数据或者写某个数据。BLE协议栈中,开发者接触最多的就是 ATTBLE 引入了属性Attribute)概念用来描述一条一条的数据。属性Attribute)除了定义数据,同时定义该数据可以使用的 ATT 命令,因此这一层被称为 ATT 层。
  • GATT(Generic attribute profile )GATT用来规范属性Attribute)中的数据内容,并运用group(分组)的概念对属性Attribute)进行分类管理。没有GATTBLE协议栈也能跑,但互联互通就会出问题,也正是因为有了GATT和各种各样的应用profileBLE摆脱了ZigBee等无线协议的兼容性困境,成了出货量最大的2.4G无线通信产品。

<3>应用层(Profiles):最上层的 Profiles 层里,包含的公共任务和私有任务。其中公共任务是蓝牙协议小组(SIG)定义的蓝牙任务,私有任务是用户或者企业自定义的蓝牙任务。

在这里插入图片描述

Controller层拓展解释

PHY层

(1)前面我们说了:“PHY 层用来指定 BLE 所用的无线频段,调制解调方式和方法等。PHY 层还决定了传输数据的速度、整个 BLE 芯片的功耗、灵敏度以及 selectivity 等射频指标的配置。”现在我选取其中三点将尽可能详细的解释PHY的作用:
<1> 无线频段:

  • PHY层决定了BLE工作在 2.4GHz ISM 频段,频率范围为2.400-2.4835 GHz
  • 再将2.4GHz频段划分为40个信道,可以有效利用频谱资源、减少干扰、优化连接建立过程,并提高信号传输质量和可靠性。
  • 其中广播信道固定373839,对应的中心频率是 2402MHz2426MHz2480MHz。广播信道之间至少相差24MHZ。每次广播,都会在3个信道上将广播数据发送一次,这能有效地避免干扰,即使1个信道存在干扰,另外的信道也可以很好地工作,而3个信道同时被干扰的情况极少。
  • 广播信道越多,各个信道同时受到干扰的几率越小,抗干扰性越强。但是广播信道越多发射数据占用的时间就越长,功耗也就越高。所以,在综合考虑抗干扰性和功耗的情况下SIG 将广播设定为3
  • 广播信道的选择主要是考虑到WI-FI接入点的干扰。通过正好避免了三个WI-FI常用接入点信道的覆盖,避免了他们的干扰。

在这里插入图片描述

<2> 调制解调方式:采用高斯频移键控(GFSK),带宽时间积BT=0.5,调制因子=[0.45-0.55],有效频率偏移为±185kHz。
<3>灵敏度:芯片的灵敏度是一个重要指标,能够能大程度上决定芯片传输的距离。从专业的术语来解释的话,接收灵敏度就是对应的芯片能解调的最小的信号能量大小。以人的视力举例说明:一个图案,距离人越远就越难看清楚细节(信号在空中传播会衰减)。张三能够在5米之外就能够看清楚图案的细节,李四要在3米才能看清细节。这表明张三的视力要比李四好(灵敏度更强)。

LL层

(1)前面说了LL层工作包括了具体选择哪个射频通道进行通信,这里就是让除3个广播信道以外的其余37个数据信道采用自适应跳频技术。自适应跳频技术会自动避开受干扰的信道,选择质量较好的信道进行数据传输,能够减少数据包的丢失和重传,从而提高通信的稳定性和效率。自适应跳频通常是基于跳频扩频(Frequency-Hopping Spread Spectrum, FHSS)技术,在多个频率间快速切换,以增加信号的抗干扰能力

在这里插入图片描述

(2)LL层要对链路进行管理和控制,负责广播、扫描、建立和维护连接,以及确保数据包按照正确的方式组织、正确地校验值和加密序列等。因此,在LL层的设备有如下5种状态:

  • 就绪态(Standby):上电后,链路层进入并保持就绪态,直到接收到主机的命令。状态机的中心状态,处于其它状态下都可以进入到此状态。
  • 广播态(Advertising):发送广播报文和扫描响应,用于回应主动扫描的设备。可被发现或者可被连接的设备需要处于广播态。向在一定区域内对其他设备进行广播数据,也需要处于广播态。为了成为广播者,设备必须有发射机,但也可以有接收机。只支持广播态的设备可以没有接收机,以降低芯片成本。但是,实际中,出货量大的收发机芯片往往比出货量小的单发射机芯片更便宜。广播态的设备停止广播后可进入就绪态。在收到发起者的连接请求之后,广播态的设备也可以进入连接态。
  • 扫描态(Scanning):接收广播信道的报文。扫描态有两个子状态:主动扫描被动扫描。被动扫描仅接收广播报文。主动扫描则发送扫描请求给广播态设备,并获取附加的扫描响应数据。扫描态的设备只能进入就绪态,转换的条件是停止扫描
  • 发起态(Initialing):发起态设备侦听自己试图连接的设备,如果收到了来自该设备的广播报文,链路层会向其发送连接请求并进入连接态,并假设广播者也进入连接态。如果发起者不再试图发起连接,也可以进入就绪态。
  • 连接态(Connection)唯一一个用到数据信道的状态,其他状态均使用广播信道,两个设备只有在连接态中才能互相传送数据。连接态只能通过断开连接转换为就绪态,连接态有两个子状态:主、从

在这里插入图片描述

(3)前面说了,扫描态(Scanning)有两个子状态:主动扫描被动扫描

  • 被动扫描设备只能被动地扫描,不能发送任何报文。因此,被动扫描可以在只有接收机的设备中实现。被动扫描主要适用于低功耗场景,因为只进行扫描,不会主动发送任何请求,因此能够节省电量。简单的设备发现和监控应用中,只需要获取设备的基本信息(如MAC地址和广播数据),被动扫描足以满足需求。
  • 主动扫描主机不仅监听广播信道的数据包,还会发送扫描请求(SCAN_REQ)给广播设备。广播设备接收到扫描请求后,会返回一个扫描响应包(SCAN_RSP),提供额外的信息。扫描请求和响应报文都在广播信道中传输。因为就能耗而言,扫描请求、响应这两个额外的报文使得能耗更高。但是,主动扫描可以获取更多数据,如设备名称、服务数据等,因为它能接收额外的扫描响应包。

(4)连接态也有两个子状态:主和从。下图为进入主、从两种状态的方法。

  • 主连接态主连接态只能从发起态进入。为了成为主设备,它必须发起连接请求,扫描周围的广播设备,并选择一个目标设备进行连接。一旦连接建立,主设备控制连接参数,如连接间隔、超时时间等,确保通信的稳定性。主设备必须定期向从设备发送报文。主设备通过发送数据包或空的PDU(协议数据单元)来维持连接,并可以请求从设备返回数据。
  • 从连接态从连接态只能从广播态进入。为了成为从设备,它必须进行广播,一旦接收到连接请求,要进行响应,最终建立连接。从设备没有主动发送数据的能力,只有当主机发送连接事件后,从机正确接收主设备的报文才能发送数据进行回应。如果从设备有更多的数据需要发送,必须等待主设备发送另外的报文再回复如果从机没有数据需要发送,也可以忽略主机的报文,以达到节能作用。但是这个忽略次数是有限制的,由开发人员决定。超过一定次数,即认为断开连接了,此时将从连接态转换为就绪态。

在这里插入图片描述

HCI层

(1)从上面我们可以知道,Controller只实现链路层的状态机,管理连接参数、信道更新、加密等链路控制。通俗来说,就是它只管数据收没收到,至于数据安不安全、有什么含义、不同的设备之间能否兼容都不是由它来管。如果只需要进行点对点的简单无线数据传输,不考虑安全性、兼容性等问题,理论上可以只要Controller层就可以了
(2)因为需要保证不同的设备之间具备兼容能力和安全性等问题,于是有了HOST层来确保BLE协议栈的上层协议和逻辑,包括设备发现、连接管理、数据传输和安全性等功能。
(3)如果HOST层和Controller层集成在同一款芯片上,理论上是可以不需要HCI层的。但是现实情况不是这样的,在手机这类复杂场景中,手机应用跑在AP芯片上,然后手机厂商想自己设计一个BLE协议栈(HOST层工作)已达到定制的功能,这样他们就只需要一个Controller层的芯片。为了降低工作量,手机厂商不可能再去找一个包含Controller层的AP芯片,于是就有了如下的设计方案。AP芯片跑HOST层,然后外置一个Controller层的芯片。
(4)但是这又诞生了一个问题,如果手机厂商认为,此时有一个更好的Controller层芯片了,我要进行替换怎么办呢?于是,为了降低替换的工作量,SIG规定了一个HCI层同一接口规范。

在这里插入图片描述

(5)上述方案是手机厂这类有一定蓝牙开发能力的公司采取的方案,如果有一些小公司,也想使用蓝牙功能,但是对蓝牙技术又不太了解怎么办呢?此时他们就可以买一些外置蓝牙模块,然后通过这些蓝牙模块的AT指令实现蓝牙传输功能。此时需要注意,外置的蓝牙模块内部包含Controller层和HOST层,这个外置的蓝牙模块可以没有HCI

在这里插入图片描述

(6) 最后一种方案大多用于消费类电子,集成度很高,调调部参数可以直接使用。这类一般是半导体厂商半开源协议栈,基于特定的编译器,把蓝牙协议栈直接烧写到蓝牙芯片中,例如乐鑫ESP32Nordic NRF51xxxTI CC2540。这类型芯片不但可以直接使用蓝牙功能,还能外接一些设备,例如LCD显示屏,音频播放器等。可以做出的产品有蓝牙手表,蓝牙音频等。这类型方案的芯片中也是内部包含Controller层和HOST层,可以没有HCI

在这里插入图片描述

举例理解BLE体系结构

(1)通过上面的讲解,相信依旧有很大一部分朋友依然搞不明白每一层到底做了什么,有什么意义。这很正常,这些概念和术语首次理解起来确实会很抽象,这里我将会举一个简单的例子再次讲解说明促进理解。
(2)现在,我们假设手上的蓝牙耳机把自己目前的电量状态83%(十六进制表示为0x53)发给手机,应该怎么做?作为应用层开发者,肯定希望越简单越好,最好可以只需要调用一个API接口即可完成任务,例如调用Battery_Capacity_Send(0x53)函数,蓝牙耳机就可以将自己当前电量发送给手机。实际上,BLE协议栈就是这样做的,上层应用只需要调用一个API,其余的BLE协议栈都会帮你处理好。但是呢,从物理层的角度来看,真的是如下图一样,只发送了一个0x53吗?

在这里插入图片描述

(3)我能进行反问,就说明肯定不是这样的。仔细想想,上面我们说了,BLE存在40个信道,那么现在我们发送数据,到底是将0x53发送到哪个信道里面呢?毫无疑问,肯定不可能把数据发送到40个信道里面,那样会造成信道的拥挤,并且能耗大大增加。为了解决这个问题,此时就需要引入LL层了。上层应用开发者调用Battery_Capacity_Send(0x53)函数,但是这个函数其实就是LL_Send(Battery_Capacity,2402M)函数的一次封装,这样标识电量数据固定在2402M信道频率上进行传输。

void Battery_Capacity_Send(int Battery_Capacity)
{//假设电量数据固定在2402M信道频率上/* Battery_Capacity : 电量信息* 2402M            : 数据发送信道*/LL_Send(Battery_Capacity,2402M);
}

(4)现在我们知道了电量数据应该发送在哪个信道上了,但是,又需要考虑一个问题。这个数据到底是发送给谁呢?你总不可能一个设备占用一个信道吧,上面也说了,BLE存在自适应跳频技术会不断调整信道以达到信号的抗干扰能力。于是这里又需要引入另外一个概念 —— 访问地址(access address)。访问地址(access address)用于表明数据是发送给谁的,其中,0x8E89BED6这个访问地址(access address)比较特殊,它表示要发给周边所有设备,即广播。如果想让蓝牙耳机数据只被自己的手机收到,自己手机的数据只被自己的蓝牙耳机收到,那么就需要生成一个独特的随机访问地址(access address),用于标识设备之间的连接。接下来,我将以广播和连接两种方式进行说明各层的作用。

广播方式

(1)在广播模式下,蓝牙耳机被称之为广播者(advertiser)手机被称为 扫描者(scanner) 或者 观察者(observer)。因为是广播,所以需要加上广播地址,因此蓝牙耳机的LL层的API实际上就应该是如下了:

void Battery_Capacity_Send(int Battery_Capacity)
{//假设电量数据固定在2402M信道频率上进行广播/* Battery_Capacity : 电量信息* 2402M            : 数据发送信道固定为2402M* 0x8E89BED6       : 表示进行广播*/LL_Send(Battery_Capacity,2402M,0x8E89BED6);
}

(2)但是,手机此时能够同时接收到多个设备的广播信息,为了确保收到的广播信息是源自于蓝牙耳机,此时还应当加上蓝牙耳机的访问地址(access address)。那么此刻LL层的API应当如下:

void Battery_Capacity_Send(int Battery_Capacity)
{//假设电量数据固定在2402M信道频率上进行广播/* Battery_Capacity : 电量信息* 2402M            : 数据发送信道固定为2402M* 0x8E89BED6       : 表示进行广播* 0xE1022AAB753B   : 蓝牙耳机的访问地址(access address)*/LL_Send(Battery_Capacity,2402M,0x8E89BED6,0xE1022AAB753B);
}

(3)数据发送似乎没有问题了,但是我们的LL层还需要考虑到数据在空中传播过程中没有被干扰,为此引入了CRC24对数据包进行检验 (假设为0xB2C78E) 。那么此刻LL层的API应当如下:

void Battery_Capacity_Send(int Battery_Capacity)
{//假设电量数据固定在2402M信道频率上进行广播/* Battery_Capacity : 电量信息* 2402M            : 数据发送信道固定为2402M* 0x8E89BED6       : 表示进行广播* 0xE1022AAB753B   : 蓝牙耳机的访问地址(access address)* 0xB2C78E         : CRC24校验*/LL_Send(Battery_Capacity,2402M,0x8E89BED6,0xE1022AAB753B,0xB2C78E);
}

(4)同时为了调制解调电路工作更高效,每一个数据包的最前面会加上1个字节的preamble(前导帧),preamble一般为0x55或者0xAA,这里取0xAA。那么此刻LL层的API应当如下:

void Battery_Capacity_Send(int Battery_Capacity)
{//假设电量数据固定在2402M信道频率上进行广播/* 0xAA             : 前导帧* Battery_Capacity : 电量信息* 2402M            : 数据发送信道固定为2402M* 0x8E89BED6       : 表示进行广播* 0xE1022AAB753B   : 蓝牙耳机的访问地址(access address)* 0xB2C78E         : CRC24校验*/LL_Send(0xAA,Battery_Capacity,2402M,0x8E89BED6,0xE1022AAB753B,0xB2C78E);
}

(5)通过上面的分析我们即可得出数据的空中包如下(空中包用小端模式表示!):

在这里插入图片描述

(6)通过上面的封装,似乎就万事大吉了。但是,如果实测之后会发现,还有很多问题。
<1>当手机收到AAD6BE898E3B75AB2A02E1538EC7B2这串数据的时候,它如何知道那个才是自己想要的电量数据呢?因此,我们这里需要在访问地址(access address)后面加入两个字段Advertising Header和长度字节。Advertising Header用来表示数据包的LL类型,包括可连接的无定向广告(ADV_IND)、可连接的定向广告(ADV_DIRECT_IND)、不可连接的无定向广告(ADV_NONCONN_IND)、可扫描的无定向广告(ADV_SCAN_IND)等。长度字节用来指明有效载荷(payload)的长度。
<2>为了保持低功耗,蓝牙设备不会一直打开射频窗口,因此手机应该什么时候开启设备窗口接收蓝牙耳机的数据呢?

  • Case1:当蓝牙耳机发送数据包的时候,手机将接收窗口关闭,那么此时将无法成功通讯。
  • Case2手机打开接收窗口,但是蓝牙耳机没有发送数据包,显然此时也将无法成功通讯。
  • Case3:只有当手机打开接收窗口,同时蓝牙耳机发送数据包,此时才能成功通讯。

综上所述:LL层还必须定义通信时序,并且加入Advertising Header和长度字节用于表示有效数据位置

在这里插入图片描述

(7)通过上面的封装,此时手机能够收到有效数据0x53了。但是,各位再思考思考,蓝牙耳机总不可能只给手机发送一个电量信息吧,还有其他信息,例如音频信息。LL层说了,它只负责收发数据,至于怎么处理,不归它来负责。因此,现在接力棒来到了GAP层了。
(8)GAP层引入了LTV(Length-Type-Value)结构来定义数据,比如02010502-长度,01-类型(强制字段,表示广播flag,广播包必须包含该字段),05-值。
(9)GAP层并没有定义电量信息类型数据,因此Type我们需要设置为0xFF,表示供应商自定义数据类型即04FF590053,其中04表示长度,FF表示数据类型(自定义数据),0x0059是供应商ID(自定义数据中的强制字段),0x53就是我们的数据(设备双方约定0x53就是表示电量)。
(10)因此,最终数据包变成了下图所示:
<1>AA – 前导帧(preamble)
<2>D6BE898E – 访问地址(access address),表示进行广播
<3>60 – LL帧头字段(LL header),表示非连接无向广告事件
<4>0E – 有效数据包长度(payload length)
<5>3B75AB2A02E1 – 广播者设备地址(advertiser address),即蓝牙耳机地址
<6>02010504FF590053 – 广播数据

  • 020105 : 强制字段,必须包含,表示设备处于LE Limited Discoverable Mode,并且不支持BR/EDR。
  • 04FF590053 : 04表示长度,FF表示自定义数据,0x0059是供应商ID(自定义数据中的强制字段),0x53就是我们的数据

<7>8EC7B2 – CRC24值

在这里插入图片描述

(10)以C代码方式理解如下:

void GAP_Send(int LTV1, int LTV2,int Battery_Capacity)
{/* 2402M            : 数据发送信道固定为2402M* 0xAA             : 前导帧* 0xD6BE898E       : 表示进行广播* 0x60             : 表示非连接无向广告事件* 0x0E             : 有效数据包长度(payload length)* 0x3B75AB2A02E1   : 蓝牙耳机地址* LTV1             : 广播数据中的强制字段,表示设备处于LE Limited Discoverable Mode,并且不支持BR/EDR。* LTV2             : 厂商自定义数据,表示电量* Battery_Capacity : 电量信息* 0xB2C78E         : CRC24校验*/LL_Send(2402M,0xAA,0xD6BE898E,0x60,0x0E,0x3B75AB2A02E1LTV1,LTV2,Battery_Capacity,0xB2C78E);
}
void Battery_Capacity_Send(int Battery_Capacity)
{/* 020105           : 强制字段,必须包含,表示设备处于LE Limited Discoverable Mode,并且不支持BR/EDR。* 04FF5900         : 04表示长度,FF表示自定义数据,0x0059是供应商ID* Battery_Capacity : 电量信息*/GAP_Send(020105,04FF5900,Battery_Capacity);
}

在这里插入图片描述

(11)总结:

  • 在广播方式中,LL层主要负责知道通讯双方地址,控制数据的状态信息,确保数据无误的上传到HOST层。
  • GAP层得到LL层的数据,并将数据封装成相应的含义。

(12)现在我们再回过头来看看上面的这个体系结构,是不是就能够理解GAP层为何会贯穿整个HOST层了呢?原因很简单,如果进行广播,只需要LL层和GAP层即可,因此GAP层会贯穿整HOST层。

在这里插入图片描述

连接方式

(1)通过上面广播的例子,我们理解了GAP层和LL层作用。现在我们看看连接方式是怎么样的呢。首先,我们需要搞明白,手机蓝牙耳机的连接(connection)是什么意思。
(2)以有线通讯为例,例如手机通过数据线连接电脑进行通讯,这个过程叫做连接。数据线将两个设备相连,实际上是让2个设备有共同的通信媒介,并让两者时钟进行同步。蓝牙连接也是同理,手机和蓝牙耳机建立蓝牙连接,就是让手机和蓝牙耳机两者一对一的同步成功。其具体包含以下方面:

  • 手机和蓝牙耳机对接下来要使用的物理信道达成一致。
  • 双方建立一个共同的时间锚点,也就是说,把双方的时间原点变成同一个点。
  • 两者时钟同步成功,即双方都知道对方什么时候发送数据包什么时候接收数据包。
  • 连接成功后,手机和蓝牙耳机通信流程如下所示:

在这里插入图片描述

(3)一旦手机(Master)蓝牙耳机(Slave) 连接成功,手机(Master) 将会以CI(connection interval)这个间隔向蓝牙耳机(Slave) 发送数据包,而蓝牙耳机(Slave) 也会周期性以CI(connection interval)为间隔打开射频窗口来接收手机(Master) 的数据包。同时,按照蓝牙规范要求,当蓝牙耳机(Slave) 收到手机(Master) 的数据包150us后,蓝牙耳机(Slave) 需要从发送状态切换为接收状态,把自己的数据发送给手机(Master) 。同理,手机(Master) 在发送完数据包150us后,需要从发送状态转换为接收状态。由此可见,连接状态下,手机(Master)蓝牙耳机(Slave) 的射频发送和接收窗口都是周期性地有计划地开和关,而且开的时间非常短,从而大大降低系统功耗并大大提高系统效率
(4)明白了连接状态下手机(Master)蓝牙耳机(Slave) 的收发方式,那么我们就来看看数据包如何发送。依旧是以蓝牙耳机(Slave) 将电量状态83%(十六进制表示为0x53)发送给手机(Master)

  • 应用层:只需要调用Battery_Capacity_Send(0x53)即可将电量信息发送出去。
  • GATT层蓝牙耳机(Slave) 数据0x53发出来了,手机(Master) 不知道这个0x53是啥意思啊。于是GATT层就需要定义数据的类型。例如这里创建一个Flag0x0013表示电量这种数据类型,这样GATT层把数据打包成130053小端模式!
  • ATT层蓝牙耳机(Slave) 把电量数据0x53发送给手机(Master) 了,但是这样又存在一个问题。手机(Master) 怎么知道这个数据到底是用来干嘛的呢?比如这个电量数据可以是将手机(Master) 的电量修改为0x53,或者是只是需要读到这个数据就可以。ATT层有读/写/notify/indicate等等通讯命令,我们这里选择notify命令0x1B,表示发送数据更新,不需要回复。这样数据包变成了:1B130053小端模式!
  • L2CAP层:数据包封装好了之后,问题是现在这个数据包发到哪个逻辑通道里面。这里我们指定逻辑通道编号0x0004(表示ATT命令),最后还需要加上ATT数据长度0x0004加在包头,最终数据就变为:040004001B130053
  • LL层:这一层要干的活上面已经说过了,因此不做赘述。

(5)最终数据包长这样:

  • AA : 前导帧(preamble)
  • 0x50655DAB : 访问地址(access address),即手机地址
  • 1E : LL帧头字段(LL header)
  • 08 : 有效数据包长度(payload length)
  • 04000400 : ATT数据长度,以及L2CAP通道编号
  • 1B : notify command
  • 0013 : 电量数据handle
  • 53 : 真正要发送的电量数据
  • F650D5 : CRC24值

在这里插入图片描述

参考

(1)红旭无线:BLE基础知识
(2)C站:【低功耗蓝牙】① 蓝牙广播数据格式分析
(3)谷雨文档中心:BLE技术揭秘
(4)TI官方蓝牙BLE 低功耗技术教程:蓝牙低功耗技术及其特点
(5)C站:蓝牙4.0、经典蓝牙、BT、BLE的关系与区别
(6)博客园:深入浅出低功耗蓝牙(BLE)协议栈
(7)博客园:三种蓝牙架构实现方案(蓝牙协议栈方案)
(8)知乎:(通信算法系列)蓝牙BLE物理层算法详解—GFSK调制与解调(1)
(9)简书:BLE 信道和自适应跳频
(10)C站:一文让你彻底了解市面蓝牙架构,无忧蓝牙产品选型
(11)博客园:详解BLE空口包格式—兼BLE Link layer协议解析
(12)[艾克姆科技教程]nRF52832开发指南.pdf
(13)低功耗蓝牙开发权威指南.pdf
(14)刘权-BLE4.0低功耗蓝牙协议总结.pdf

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/14820.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mysql教程(0):学习框架

1、Mysql简介 MySQL 是一个开放源代码的、免费的关系型数据库管理系统。在 Web 开发领域&#xff0c;MySQL 是最流行、使用最广泛的关系数据库。MySql 分为社区版和商业版&#xff0c;社区版完全免费&#xff0c;并且几乎能满足全部的使用场景。由于 MySQL 是开源的&#xff0…

1075: 求最小生成树(Prim算法)

解法&#xff1a; 总结起来&#xff0c;Prim算法的核心思想是从一个顶点开始&#xff0c;一步一步地选择与当前最小生成树相邻的且权值最小的边&#xff0c;直到覆盖所有的顶点&#xff0c;形成一个最小生成树。 #include<iostream> #include<vector> using names…

springboot基于Web前端技术的java养老院管理系统_utbl7

3.普通用户模块包括&#xff1a;普通会员的注册、养老院客房查询、养老院留言查询、预约老人基本信息登记、选择房间、用户缴费的功能。 4.数据信息能够及时进行动态更新&#xff0c;增删&#xff0c;用户搜素方便&#xff0c;使用户可以直接浏览相关信息&#xff0c;要考虑便于…

Vue3实战笔记(35)—集成炫酷的粒子特效

文章目录 前言一、vue3使用tsparticles二、使用步骤总结 前言 学习一个有趣炫酷的玩意开心一下。 tsparticles&#xff0c;可以方便的实现各种粒子特效。支持的语言框架也是相当的丰富. 官网&#xff1a;https://particles.js.org/ 一、vue3使用tsparticles 先来个vue3使用…

代码随想录训练营打卡第36天:动态规划解决子序列问题

1.300最长递增子序列 1.问题描述 找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。 2.问题转换 从nums[0...i]的最长的递增的子序列 3.解题思路 每一个位置的n…

C++多态详解

目录 一、多态的概念 二、多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写 4.例题理解&#xff08;超级重要&#xff0c;强烈建议做一下&#xff09; 5.C11 override和 final 6.重载、覆盖&#xff08;重写&#xff09;、隐藏&#xff08;重定义&#xff0…

零基础代码随想录【Day42】|| 1049. 最后一块石头的重量 II,494. 目标和,474.一和零

目录 DAY42 1049.最后一块石头的重量II 解题思路&代码 494.目标和 解题思路&代码 474.一和零 解题思路&代码 DAY42 1049.最后一块石头的重量II 力扣题目链接(opens new window) 题目难度&#xff1a;中等 有一堆石头&#xff0c;每块石头的重量都是正整…

(Qt) 默认QtWidget应用包含什么?

文章目录 ⭐前言⭐创建&#x1f6e0;️选择一个模板&#x1f6e0;️Location&#x1f6e0;️构建系统&#x1f6e0;️Details&#x1f6e0;️Translation&#x1f6e0;️构建套件(Kit)&#x1f6e0;️汇总 ⭐项目⚒️概要⚒️构建步骤⚒️清除步骤 ⭐Code&#x1f526;untitled…

【EasyX】快速入门——消息处理,音频

1.消息处理 我们先看看什么是消息 1.1.获取消息 想要获取消息,就必须学会getmessage函数 1.1.1.getmessage函数 有两个重载版本,它们的作用是一样的 参数filter可以筛选我们需要的消息类型 我们看看参数filter的取值 当然我们可以使用位运算组合这些值 例如,我们…

华为CE6851-48S6Q-HI升级设备版本及补丁

文章目录 升级前准备工作笔记本和交换机设备配置互联地址启用FTP设备访问FTP设备升级系统版本及补丁 升级前准备工作 使用MobaXterm远程工具连接设备&#xff0c;并作为FTP服务器准备升级所需的版本文件及补丁文件 笔记本和交换机设备配置互联地址 在交换机接口配置IP&#…

Facebook隐私保护:数据安全的前沿挑战

在数字化时代&#xff0c;随着社交媒体的普及和应用&#xff0c;个人数据的隐私保护问题日益受到关注。作为全球最大的社交平台之一&#xff0c;Facebook承载了数十亿用户的社交活动和信息交流&#xff0c;但与此同时&#xff0c;也面临着来自内外部的数据安全挑战。本文将深入…

AWS Elastic Beanstalk 监控可观测最佳实践

一、概述 Amazon Web Services (AWS) 包含一百多种服务&#xff0c;每项服务都针对一个功能领域。服务的多样性可让您灵活地管理 AWS 基础设施&#xff0c;然而&#xff0c;判断应使用哪些服务以及如何进行预配置可能会非常困难。借助 Elastic Beanstalk&#xff0c;可以在 AW…

AWTK实现汽车仪表Cluster/DashBoard嵌入式GUI开发(七):快启

前言: 汽车仪表是人们了解汽车状况的窗口,而仪表中的大部分信息都是以指示灯形式显示给驾驶者。仪表指示灯图案都较为抽象,对驾驶不熟悉的人在理解仪表指示灯含义方面存在不同程度的困难,尤其对于驾驶新手,如果对指示灯的含义不求甚解,有可能影响驾驶的安全性。即使是对…

Pytest框架实战二

在Pytest框架实战一中详细地介绍了Pytest测试框架在参数化以及Fixture函数在API测试领域的实战案例以及具体的应用。本文章接着上个文章的内容继续阐述Pytest测试框架优秀的特性以及在自动化测试领域的实战。 conftest.py 在上一篇文章中阐述到Fixture函数的特性&#xff0c;第…

shell循环

一、for循环 用法&#xff1a; for 变量 in 取值列表 do 命令序列 done 例1&#xff1a;打印1到10的数字列表 #!/bin/bashfor i in {1..10} do echo $i done 例2&#xff1a;#批量添加用户,用户名存放在users.txt文件中&#xff0c;每行一个,初始密码均设为123456 #!/bin/bas…

KMP算法【C++】

KMP算法测试 KMP 算法详解 根据解释写出对应的C代码进行测试&#xff0c;也可以再整理成一个函数 #include <iostream> #include <vector>class KMP { private:std::string m_pat;//被匹配的字符串std::vector<std::vector<int>> m_dp;//状态二维数组…

哪些类型的产品适合用3D形式展示?

随着3D技术的蓬勃发展&#xff0c;众多品牌和企业纷纷投身3D数字化浪潮&#xff0c;将产品打造成逼真的3D模型进行展示&#xff0c;消费者可以更加直观地了解产品的特点和优势&#xff0c;从而做出更明智的购买决策。 哪些产品适合3D交互展示&#xff1f; 产品3D交互展示具有直…

自己手写一个字符串【C风格】

//字符串的常见操作 #include <iostream>#define MAX_SIZE 15 #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 typedef int Status;//状态类型 typedef char ElemType;//元素类型typedef ElemType String[MAX_SIZE 1];//第一个字节记录长度//***tring是数…

c#自动生成缺陷图像-添加新功能(可从xml直接提取目标数据,然后进行数据离线增强)--20240524

在进行深度学习时,数据集十分重要,尤其是负样本数据。 故设计该软件进行深度学习数据预处理,最大可能性获取较多的模拟工业现场负样本数据集。 该软件基于VS2015、.NETFrameWork4.7.2、OpenCvSharp1.0.0.0、netstandard2.0.0.0、SunnyUI3.2.9.0、SunnyUI.Common3.2.9.0及Ope…

C盘磁盘空间不够用,怎样将d盘的空间划分给c盘?

C盘磁盘空间不够用&#xff0c;怎样将d盘的空间划分给c盘&#xff1f; 背景&#xff1a;win10系统下。C盘原有50G&#xff0c;如今只剩下8G&#xff0c;已经捉襟见肘了&#xff0c;想从D盘&#xff0c;割100G给C盘&#xff0c;以后软件能直接装C盘了。操作步骤如下&#xff1a…