当前位置:网站首页>esp32系列(5):esp32 蓝牙架构学习
esp32系列(5):esp32 蓝牙架构学习
2022-07-30 16:57:00 【程序员超时空】
目录
1 ESP32 蓝牙架构学习
1.1 蓝牙
蓝牙是一种短距通信系统。
蓝牙系统分为两种不同的技术(ESP32都支持):
- 经典蓝牙(Classic Bluetooth)
- 蓝牙低功耗(Bluetooth Low Energy)
整体结构:

分为控制器(Controller)和主机(Host)两大部分。
- 控制器
- 组成:包括PHY、 Baseband、 Link Controller、 Link Manager、 Device Manager、 HCI 等模块。
- 功能:硬件接口管理、链路管理等。
- 主机
- 组成:包括了了 L2CAP、 SMP、 SDP、 ATT、 GATT、 GAP 以及各种规范。
- 功能:构建了了向应用层提供接口的基础,方便便应用层对蓝牙系统的访问。
- 特征:可以与控制器在同一宿主或不同宿主。
- 控制器
由于主机的特征,ESP32 有几种典型应用场景:
- 1 宿主相同(ESP-IDF默认):控制器(ESP32 Bluetooth Controller)与主机(ESP32 BLUEDROID )。
- 2 宿主不同:控制器(ESP32 Bluetooth Controller)与主机(PC/Phone/Pad )。
- 3 宿主不同:与2类似,但是用于BQB(或其它认证)的控制器测试。
1.1.1 HCI 接口选择
Host与Bluetooth Controller连接的HCI(主机控制接口, Host Controller Interface), 在ESP32中只能同时使用以下IO接口中的一个:
- UART
- VHCI
- SDIO
在ESP-IDF中,可以在 menuconfig 中配置蓝牙的 HCI IO接口方式。
1.1.2 蓝牙运行环境
ESP-IDF 的默认运行环境为双核 FreeRTOS, ESP32 的蓝牙可按照功能分为多个任务(task)运行,不同任务的优先级也有不同,其中优先级最的为运控制器的任务。控制器任务对实时性要求高,在FreeRTOS系统中的优先级仅次于IPC任务(IPC任务用于CPU的进程间通信)。BLUEDROID(ESP-IDF默认的蓝牙主机)共包含4个任务:
- BTC
- BTU
- HCI UPWARD
- HCI DOWNWARD
1.1.3 框架
1.1.3.1 控制器
ESP32 同时支持 Classic BT 和 BLE,蓝牙版本4.2 。集成了H4 协议、 HCI、 Link Manager、 Link Controller、 Device Manager、 HW Interface 等功能。这些功能以库的形式提供给开发者。
1.1.3.2 BLUEDROID
BLUEDROID蓝牙主机内部分为两层:
- BTU层
- 功能:负责蓝主机底层协议栈的处理,包括 L2CAP、 GATT/ATT、 SMP、 GAP 以及部分规范等。
- BTC层(除去HCI)
- 功能:负责向应用层提供接口支持、处理基于 GATT 的规范、处理杂项等 。
所有的API都在ESP_API层,开发者应当使用“esp”为前缀的蓝牙API。
1.2 经典蓝牙
ESP-IDF 中的蓝主机协议栈源于 BLUEDROID,后经过改良以配合嵌入式系统的应。
在底层中,蓝牙主机协议栈通过虚拟 HCI 接,与蓝牙双模控制进行通信;
在上层中,蓝牙主机协议栈将为用户应用程序提供用于协议栈管理和规范的 API。
主机协议栈支持的经典蓝牙协议和规范:
- 规范: GAP、A2DP (SNK)、AVRCP (CT)
- 协议: L2CAP、SDP、AVDTP、AVCTP
协议模型:

- L2CAP:L2CAP,Logical Link Control and Adaptation Protocol,即逻辑链路控制和适配协议。
- SDP:Service Discovery Protocol,服务发现协议
- 功能:允许应用程序发现其他对等蓝牙设备提供的服务,并确定可用服务的特征。
- GAP:Generic Access Profile,通用访问规范
- 功能:提供有关设备可发现性、可连接性和安全性的模式和过程描述。
- A2DP(Advanced Audio Distribution Profile,高级音频分发规范) 和 AVRCP(Audio/Video Remote Control Profile,音频/视频远程控制规范)
- 实现高质量单声道或立体声音频内容传输的协议和过程。
- SPP (Serial Port Profile,串口协议)
- 能在蓝牙设备之间创建串口进行数据传输的一种设备。
1.2.1 代码实现
有关经典蓝牙的例程路径为:examplesluetoothluedroidclassic_bt。
参考 bt_spp_acceptor demo,作为 acceptor 通过 spp 协议进行串口环回通信。
调用api的流程为:
- 1 esp_bt_controller_mem_release
功能:按模式释放controller内存
注意:esp_bt_controller_mem_release() 只能在esp_bt_controller_init() 之前或者 esp_bt_controller_deinit() 之后调用。
初始化时调用了esp_bt_controller_mem_release()之后,使用esp_bt_controller_enable()来使用BLE才是安全的。 - 2 esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
功能:获得控制器配置选项。通过配置掩码启用了某些功能的一些选项或参数。 - 3 esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
功能: 初始化 BT controller 以分配 task 和其他 资源。
注意:这个函数需要在调用任何 BT 函数之前调用一次。 - 4 esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode);
功能:使能 BT controller
注意:调用之后不能再次调用。如果需要动态改变 controller 的模式,则需要调用 esp_bt_controller_disable() 之后重新调用此函数。 - 5 esp_err_t esp_bluedroid_init(void);
功能:初始化和分配蓝牙资源
注意:必须优先于每一个bluetooth stuff。 - 6 esp_err_t esp_bluedroid_enable(void);
功能:启用蓝牙。
注意:必须在esp_bluedroid_init()之后。 - 7 esp_err_t esp_bt_gap_register_callback(esp_bt_gap_cb_t callback);
功能:注册gap回调函数
注意:此函数应在 esp_bluedroid_enable() 成功完成后调用
回调函数中对 BT GAP 回调事件进行判断并处理,如果收到认证完成事件(ESP_BT_GAP_AUTH_CMPL_EVT),则输出认证成功的消息。如果收到传统配对的PIN请求的事件(ESP_BT_GAP_PIN_REQ_EVT),先判断PIN的位数,如果是16位则设置PIN为 0000 0000 0000 0000 ,如果是4位则设置PIN为 1234 。 - 8 esp_err_t esp_spp_register_callback(esp_spp_cb_t callback);
功能:注册spp模块初始化回调函数 - 9 esp_err_t esp_spp_init(esp_spp_mode_t mode);
功能:初始化 spp 模块 - 10 esp_err_t esp_bt_gap_set_pin(esp_bt_pin_type_t pin_type, uint8_t pin_code_len, esp_bt_pin_code_t pin_code);
功能:为传统配对(Legacy Pairing)设置默认参数。
主文件代码:
编译的过程如果报错:fatal error:esp_bt.h: no such file or directory
解决:需要在menuconfig工具中配置SPP环境,配置好的环境设置保存在工程路径下的 sdkconfig 文件中。

- 设置
component config->Bluetooth为打开 - 设置
component config->Bluetooth->Bluetooth contriller->Bluetooth contorller mode (BR/EDR/BLE/DUALMODE)选择为BR/EDR Only - 设置
component config->Bluetooth->Bluedroid Options为 选中Classic Bluetooth下的SPP协议。
修改宏定义为显示数据:line 32: #define SPP_SHOW_MODE SPP_SHOW_DATA /*Choose show mode: show data or speed*/
测试结果:

手机下载蓝牙串口调试助手软件,连接名为“SPP_ACCEPTOR_DEMO”的蓝牙设备
监视器:W (3646) BT_APPL: new conn_srvc id:26, app_id:255手机发送数据“12345678”
监视器:I (3646) SPP_ACCEPTOR_DEMO: ESP_SPP_SRV_OPEN_EVT I (10906) SPP_ACCEPTOR_DEMO: ESP_BT_GAP_MODE_CHG_EVT mode:2 I (11706) SPP_ACCEPTOR_DEMO: ESP_BT_GAP_MODE_CHG_EVT mode:0 I (11726) SPP_ACCEPTOR_DEMO: ESP_SPP_DATA_IND_EVT len=4 handle=129 I (11726) : 12 34 56 78
蓝牙串口通信测试完成。
1.3 低功耗蓝牙
1.3.1 GAP(Generic Access Profile)
Generic Access Profile,通用访问规范。
功能:定义了了 BLE 设备的发现流程,设备管理和设备连接的建立。
BLE GAP采用API调用和事件(Event)返回的设计模式,通过事件返回来获取 API 在协议栈的处理结果。当对端设备主动发起请求时,也是通过事件返回获取对端设备的状态。
BLE设备定义四类 GAP 角色:
- 广播者(Broadcaster):处于这种角色的设备通过发送广播 (Advertising) 让接收者发现自己。这种角色只能发广播,不能被连接。
- 观察者(Observer):处于这种角色的设备通过接收广播事件并发送扫描(scan)请求。这种角色只能发送扫描请求,不能被连接。
- 外围设备(Peripheral): 当广播者接受了观察者发来的请求后就就会进入这种角色。当设备进入这种角色后,将会作为从设备(slave)在链路中进行通信。
- 中央设备(Central): 当观察者主动进行初始化,并建立一个物理链路时就会进入这种角色。这种角色在链路中被称为主设备(master)
1.3.1.1 BLE角色转换图

1.3.1.2 BLE广播流程
方式:
- 使用public地址进行广播
- 使用可解析地址进行广播
- 使用静态随机地址进行广播
类型:
- 可连接可扫描非定向广播 (Connectable scannable undirected event type)
- 高占空比定向广播 (High duty cycle directed event type)
- 可扫描非定向广播 (Scannable undirected event type)
- 不可连接非定向广播 (Non-connectable undirected event type)
- 可连接低占空比定向广播 (Connectable low duty cycle directed event type)
1.3.1.3 BLE扫描流程
在 ESP32 中,扫描设备主要是通过调用 esp_ble_gap_set_scan_params 来设置扫描时的参数,然后调用 esp_ble_gap_start_scanning 开始扫描。扫描到的设备将会通过ESP_GAP_BLE_SCAN_RESULT_EVT 事件返回,最后当 duration 超时,会通过ESP_GAP_SEARCH_INQ_CMPL_EVT 事件返回。
1.3.2 GATT(Generic Attribute Profile)
1.3.2.1 ATT(Attribute Protocol)
BLE 中的数据以属性(Attribute)方式存在,每条属性由四个元素组成:
- 属性句句柄 (Attribute Handle) :类似于地址。
- 属性类型 (Attribute UUID) : 每个数据有自己需要代表的意思,用标识码 (UUID)区分。
- 属性值 (Attribute Value):属性值是每个属性真正要承载的信息。
- 属性许可 (Attribute Permissions) :每个属性对各自的属性值有相应的访问限制。

服务器(server): 存有数据(即属性)的设备。
客户端(client): 获取别人设备数据的设备。
常用操作:
- 客户端给服务端发数据:通过 写入请求 (Write Request)需要对方回复响应(Write Response)。写入命令 (Write
Command)不需要。 - 服务端给客户端发数据:通过 服务端指示 (Indication) 、通知 (Notification)
- 客户端也可以主动通过读操作读取服务端的数据
服务和客户端之间的交互操作都是通过上述的消息 ATT PDU 实现的。每个设备可以指定自己设备支持的最大 ATT 消息长度,我们称之为 MTU。 ESP32 IDF 里面规定 MTU 可以设置的范围是 23~517 字节,对属性值的总长度没有做限制。
1.3.2.2 GTAA 规范
ATT 属性协议规定了在 BLE 中的最小数据存储单位,而 GATT 规范则定义了:
- 如何用特性值和描述符表示一个数据
- 如何把相似的数据聚合成服务 (Service)
- 以及如何发现对端设备拥有哪些服务和数据
- GATT 规范引进了了特性值的概念,增加数据额外的信息。
为了包含额外的这些信息,每个属性中均需要安排一大段数据空间,存储这些额外信息。然而,一个数据很有可能用不不到绝大部分的额外信息,因此这种设计并这不符合 BLE “协议尽可能精简”的要求。在此背景下, GATT 规范引进了描述符的概念,每种描述符可以表达一种意思,用户可使用描述符,描述数据的额外信息。必需说明的是,每个数据和描述符并非一一对应,即一个复杂的数据可以拥有多个描述符,而一个简单的数据可以没有任何描述符。
BLE 协议中会把一些常用的功能定义成一个个的服务 (Service)*,每个服务包含若干个特性,每个特性包含若干个描述符。

1.3.2.3 基于 ESP32 IDF 建立 GATT 服务(GATT 服务)
通过属性表 (Attribute Table)* 添加服务和特性的功能。用户只需将要添加的服务和特性逐一填入一个表格,然后调用
esp_ble_gatts_create_attr_tab 函数,即可添加对应的服务和特性。
1.3.2.4 基于 ESP32 IDF 发现对方设备的服务信息(GATT 客户端)
- 首先发现对方所有的 Service 信息,包括 Service 的 UUID 和 Handle 范围。
- 然后在 GATT 的 Handle 范围内 ,继续查找所有的特性。
- 然后在 GATT 的 Handle 范围内 ,继续查找特性后的所有的描述符。
先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦
边栏推荐
- 阿里SIM-基于检索的用户行为兴趣CTR模型(Search-based user Interest Model(SIM))
- 一篇文 带你搞懂,虚拟内存、内存分页、分段、段页式内存管理(超详细)
- 向量检索基础方法总结
- .NET 6.0中使用Identity框架实现JWT身份认证与授权
- You are a first-class loser, you become a first-class winner
- The first time I used debug query and found that this was empty, does it mean that the database has not been obtained yet?please help.
- 你是这样的volatile,出乎意料
- 京东获取推荐商品列表 API
- Mysql进阶优化篇01——四万字详解数据库性能分析工具(深入、全面、详细,收藏备用)
- MySQL索引常见面试题(2022版)
猜你喜欢

第一次用debug查询,发现这个为空,是不是代表还没获得数据库的意思?求帮助。

全球架构师峰会

Weka 3.8.6安装与Weka 3.8.6功能介绍

真正懂经营管理的CIO具备哪些特质

swagger使用教程——快速使用swagger

huato hot update environment construction (DLL method hot update C# code)

Daily practice------Generate 13-digit bar, Ean-13 code rule: The thirteenth digit is the check code obtained by the calculation of the first twelve digits.

说几个大厂分库分表的那点破事。

onenote use

JVM学习----垃圾回收
随机推荐
Large-scale integrated office management system source code (OA+HR+CRM) source code sharing for free
Is it reliable to work full-time in self-media?
gvim命令记录
数据预处理:离散特征编码方法
Daily practice------Generate 13-digit bar, Ean-13 code rule: The thirteenth digit is the check code obtained by the calculation of the first twelve digits.
How does the new retail saas applet explore the way to break the digital store?
C# 跨程序传图(共享内存块传图)跨exe传图
Lotus explodes the block failed
Scheduling_Channel_Access_Based_on_Target_Wake_Time_Mechanism_in_802.11ax_WLANs
[极客大挑战 2020]Roamphp1-Welcome
阿里巴巴CAN:Embedding前置的特征交互新思路
如何在 UE4 中用代码去控制角色移动
镜像站收集
S7-200SMART中定时器的使用方法和常见注意事项汇总
Redis缓存穿透-热点缓存并发重建-缓存与数据库双写不一致-缓存雪崩
crontab报错,但本地执行正常
华为云数据治理生产线DataArts,让“数据'慧'说话”
数组和指针(2)
Rounding out the most practical way of several DLL injection
报错500,“message“: “nested exception is org.apache.ibatis.binding.BindingException: 解决记录