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

news2024/11/26 6:20:38

前言

(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,0x3B75AB2A02E1
	         LTV1,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.coloradmin.cn/o/1689038.html

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

相关文章

创新指南|利用电商产品视频进行渠道营销的最佳策略,不断提升销售额

无论企业的利基市场如何&#xff0c;电商产品视频都已被证明是非常可靠的资产&#xff0c;可以让目标受众了解您所提供的产品——关键功能、展示重要的差异化优势甚至改变大多数营销活动的游戏规则。阅读本文&#xff0c;全面了解电商产品视频如何融入营销推广&#xff0c;以最…

IDEA 自定义注解(类注释、方法注释)

一、生成类注释 1、打开设置位置 打开File —> Settings —> Editor —> File and Code Templates —> Files —> Class 2、将自定义的类注解规则&#xff0c;复制到Class中。 /** * * 功能: * * 作者: 暗自着迷 * * 日期: ${YEAR}-${MONTH}-${DAY} ${HOU…

AI图片过拟合如何处理?答案就在其中!

遇到难题不要怕&#xff01;厚德提问大佬答&#xff01; 厚德提问大佬答8 你是否对AI绘画感兴趣却无从下手&#xff1f;是否有很多疑问却苦于没有大佬解答带你飞&#xff1f;从此刻开始这些问题都将迎刃而解&#xff01;你感兴趣的话题&#xff0c;厚德云替你问&#xff0c;你解…

头歌openGauss-存储过程第2关:修改存储过程

任务描述 本关任务&#xff1a; 修改存储过程pro0101&#xff0c;并调用&#xff1b; --修改sel_course表中成绩<60的记录为成绩10&#xff0c;然后将计算机学院所有学生的选课成绩输出&#xff1b; --a、需要先删除存储过程pro0101&#xff1b; drop procedure if exists p…

JAVA开发 基于最长公共子序列来计算两个字符串之间的重复率

计算两个字符串之间的重复率 最长公共子序列实现代码 最长公共子序列 基于最长公共子序列&#xff08;Longest Common Subsequence, LCS&#xff09;的重复率的中心逻辑是首先找到两个或多个序列中同时出现的、不一定连续但保持相对顺序的最长子序列&#xff0c;然后计算这个最…

5款AI工具,PS插件的智能升级

在Photoshop插件的世界里&#xff0c;创新和效率是永远的主题。随着AI技术的融入&#xff0c;传统的PS插件正在经历一场革命。本文将介绍五款结合了人工智能技术的PS插件&#xff0c;它们不仅提升了设计工作的效率&#xff0c;还拓展了创意的边界。 StartAI —— 智能设计的未来…

【因果推断从入门到精通二】随机实验3

目录 检验无因果效应假说 硬币投掷的特殊性何在&#xff1f; 检验无因果效应假说 无因果效应假说认为&#xff0c;有些人存活&#xff0c;有些人死亡&#xff0c;但接受mAb114治疗而不是ZMapp与此无关。在174例接受mAb14治疗的患者中&#xff0c;113/17464.9%存活了28天&…

画图工具之PlantUML插件使用

文章目录 1 PlantUML插件1.1 引言1.2 什么是PlantUML1.3 PlantUML插件1.3.1 IntelliJ IDEA中插件1.3.2 VS Code中插件1.3.3 使用例子 1.4 PlantUML时序图语法1.4.1 声明参与者1.4.2 消息传递1.4.2.1 同步消息1.4.2.2 异步消息1.4.2.3 返回消息1.4.2.4 自调用 1.4.3 生命线&…

字符函数:分类函数与转换函数

字符函数 一.字符分类函数二.字符转换函数 在编程的过程中&#xff0c;我们经常要处理字符和字符串&#xff0c;为了方便操作字符和字符串&#xff0c;C语⾔标准库中提供了一系列库函数&#xff0c;接下来我们就学习⼀下这些函数。 一.字符分类函数 C语言中有⼀系列的函数是专门…

基于python向量机算法的数据分析与预测

3.1 数据来源信息 该数据集来源于Kaggle网站&#xff0c;数据集中包含了罗平菜籽油的销售数据&#xff0c;每行数据对应一条记录&#xff0c;记录了罗平菜籽油销售数据。其中&#xff0c;菜籽产量、菜籽价格和菜籽油价格是数值型数据&#xff0c;共2486条数据。 通过读取Exce…

大模型日报|今日必读的 13 篇大模型论文

大家好&#xff0c;今日必读的大模型论文来啦&#xff01; 1.MIT新研究&#xff1a;并非所有语言模型特征都是线性的 最近的研究提出了线性表征假说&#xff1a;语言模型通过操作激活空间中概念&#xff08;“特征”&#xff09;的一维表征来执行计算。与此相反&#xff0c;来…

现代密码学——消息认证和哈希函数

1.概述 1.加密-->被动攻击&#xff08;获取消息内容、业务流分析&#xff09; 消息认证和数字签名-->主动攻击&#xff08;假冒、重放、篡改、业务拒绝&#xff09; 2.消息认证作用&#xff1a; 验证消息源的真实性&#xff0c; 消息的完整性&#xff08;未被篡改…

Redis篇 有关Redis的认识和Redis的特性应用场景

Redis 一. Redis的基本概念1.1 应用/系统1.2 模块/组件1.3 分布式1.4 集群1.5 主/从1.6 中间件1.7 可用性1.8 响应时长1.9 吞吐 二.Redis的特性三.使用场景 一. Redis的基本概念 1.1 应用/系统 一个应用就是一个组,一个服务器程序 1.2 模块/组件 一个应用,里面有很多功能,每个…

spring boot打的包直接运行

Spring Boot 提供了一个插件 spring-boot-maven-plugin 把程序打包成一个可执行的jar包&#xff0c;直接执行java -jar xxx.jar即可以启动程序 1、引用 spring-boot-maven-plugin插件 <build><plugins><plugin><groupId>org.springframework.boot<…

2024年顶级算法-黑翅鸢优化算法(BKA)-详细原理(附matlab代码)

黑翅鸢是一种上半身蓝灰色&#xff0c;下半身白色的小型鸟类。它们的显著特征包括迁徙和捕食行为。它们以小型哺乳动物、爬行动物、鸟类和昆虫为食&#xff0c;具有很强的悬停能力&#xff0c;能够取得非凡的狩猎成功。受其狩猎技能和迁徙习惯的启发&#xff0c;该算法作者建立…

转运机器人负载最高可达 1000kg,重复精度高达±5mm

转运机器人&#xff0c;内部搭载ICD系列核心控制器&#xff0c;拥有不同的移载平台&#xff0c;负载最高可达 1000kg;重复精度高达5mm;支持 Wi-Fi漫游&#xff0c;实现更稳健的网络数据交互;无轨化激光 SLAM 导航&#xff0c;配合 3D 避障相机等多传感器进行安全防护。转运器人…

FreeRTOS_同步互斥与通信_环形buffer、队列_学习笔记

FreeRTOS_同步互斥与通信_概念_学习笔记 信号量、互斥量的本质是队列&#xff0c;队列的本质是加强版环形缓冲区 5 FreeRTOS数据传输的方法-环形buffer、队列 如果我有两个任务TaskA和TaskB&#xff0c;他俩可以同时运行。想要在他们之间传递数据&#xff0c;可以用一个全局变…

深入解析kube-scheduler的算法自定义插件

目录 ​编辑 一、问题引入 二、自定义步骤 三、最佳实践考虑 一、问题引入 当涉及到 Kubernetes 集群的调度和资源分配时&#xff0c;kube-scheduler 是一个关键组件。kube-scheduler 负责根据集群的调度策略&#xff0c;将 Pod 分配到适当的节点上。kube-scheduler 默认使…

YTM32的flash应用答疑-详解写保护功能

YTM32的flash应用答疑-详解写保护功能 文章目录 YTM32的flash应用答疑-详解写保护功能IntroductionPrincipleOperation & DemonstrationDemo #1 验证基本的写保护功能Demo #2 编程CUS_NVR设定EFM_ADDR_PROT初值Demo #3 启用写保护后试试块擦除操作 Conclusion Introduction…

HarmonyOS之ArkUI布局设计常见细节

这里写目录标题 1. Button设置带有渐变色的背景图片无效1.1 问题分析1.2 成功案例 2. 路由跳转失败2.1 问题分析 1. Button设置带有渐变色的背景图片无效 1.1 问题分析 说明&#xff1a;设置颜色渐变需先设置backgroundColor为透明色。 Button($r(app.string.login), { type…