ESP32 BLE学习(0) — 基础架构
前言
(1)学习本文之前,需要先了解一下蓝牙的基本概念:BLE学习笔记(0.0) —— 基础概念(0)
(2) 学习一款芯片的蓝牙肯定需要先简单了解一下该芯片的体系结构,因此本文将会简单的介绍ESP32的蓝牙结构。
(3)因为乐鑫目前主推的是BLE低功耗蓝牙技术,因此我本人也主要侧重讲解BLE部分。
ESP32蓝牙系统介绍
蓝牙堆栈
(1)
ESP-IDF目前支持两个主机堆栈,Bluedroid(默认) 和Apache NimBLE。
- Bluedroid : 该堆栈支持传统蓝牙(
BR/EDR)和低功耗蓝牙(BLE)。如果是传统蓝牙(BR/EDR)有需求,则必须使用该堆栈。- Apache NimBLE : 仅支持低功耗蓝牙。如果仅仅是对
BLE有使用需求,建议选择该协议栈,因为该协议栈代码占用和运行时对内存的需求都会低一些。
蓝牙架构
(1)我们知道,蓝牙从整体架构上可以分为控制器 (
Controller) 和主机 (Host) 。
- 控制器 (
Controller) : 通常是一个物理设备,它能够发送和接收无线电信号,并懂得如何将这些信号翻译成携带信息的数据包。主要用于硬件接口管理、链路管理等等。- 主机 (
Host) : 它通常是一个软件协议栈,用于管理两台或多态设备间如何通讯以及如何实现无线电同时提供几种不同服务。它可以构建各种规范,向上层应用提供接口基础,方便应用层对蓝牙系统的访问编程。(2)首先,我们需要知道为什么蓝牙需要分为控制器 (
Controller) 和主机 (Host) 两层结构。这个时候我们就需要了解一下蓝牙技术设计初衷了,蓝牙致力于打造一种低成本的无线通讯方案,要实现低成本那么就需要有较大的销量。如今,手机作为当之无愧销量最大的消费电子设备,任何一项技术一旦进入了手机就非常容易取得成功。因此,低功耗蓝牙将会依附于蓝牙在手机上的高配售率快速拓宽市场。
(3)既然你要依附手机,那么很多东西都要从手机厂的角度进行思考问题。那么,如果你仔细阅读蓝牙核心规格,你会发现规格书更多地是站在手机角度来阐述的,然后“顺带”描述一下手机周边蓝牙设备的实现原理。
(4)大家都知道,手机厂一般不只是做手机,还会做一些手机相关的周边设备,例如华为不仅仅做华为手机,还有华为平板,华为耳机,华为电脑等等。华为手机和华为电脑只要通过无线网络连接在一起,就能够无感控制对方并且传输数据。但是,如果华为手机和苹果电脑组合在一起,却做不到无感控制对方。这是为什么呢?
(5)因为,手机厂都会在自家设备上跑一套协议栈用于适配自家的电子产品。协议栈设计的越好,手机厂自家的各种设备间信息传输更稳定,安全,用户体验也越好。因此手机厂不会把自家的协议栈分享给别人一起使用,这也导致的华为手机和苹果电脑之间部分功能无法实现的原因。(注意,虽然不同手机厂协议栈不一样,但还是符合SIG标准和规范的,因此大部分功能能够互通)
(6)既然手机厂的协议栈是不进行公开的,那么就存在一个问题,如果手机厂好不容易将自家的协议栈部署在一颗蓝牙芯片上,突然发现又有一颗性能更好、更便宜的蓝牙芯片了,需要更换芯片怎么办?这个时候需要更换部署,对于手机厂来说成本太高。因此SIG将跑协议栈的Host层与硬件管理的Control层进行隔离,中间统一一个接口标准HCI层。这样的话,手机厂只需要在AP芯片上跑协议栈Host层,而负责硬件的Control层单独一个芯片。当需要更换蓝牙芯片的时候,直接换即可,因为都是统一的HCI接口。

(7)现在我们有了上述基础,再来看看
ESP32的蓝牙结构。ESP32有一个Control层,负责物理层相关的处理。Host层就有三种应用场景:
- 单芯片跑蓝牙程序:使用
Control层和Host层都运行在ESP32上,Host层有三种选择,乐鑫官方提供的Bluedroid(默认) 和NimBLE协议栈,或者自己在ESP32上编写一个自己的协议栈。- 双芯片跑蓝牙程序:在
ESP32上运行Control层,外接一个运行蓝牙协议栈的Host层。- 认证测试:我们如果想要使用
ESP32作为开发用的蓝牙芯片,那么就需要知道它是否符合一些认证标准。因此就可以使用一个UART外接PC机进行认证测试。

代码分析
(1)我们首先需要找到gatt_server_service_table例程根据上面所说的知识分析一下
app_main()函数做了什么。
(2)该例程虽然是使用的Bluedroid协议栈,但是只用了BLE部分。
<1>esp_bt_controller_mem_release()因为我们这里只需要BLE部分,所以需要先将传统蓝牙的内存进行释放。
// 释放经典蓝牙控制器内存
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
<2>
esp_bt_controller_init()是对Control层进行初始化,BT_CONTROLLER_INIT_CONFIG_DEFAULT()是一个宏作为蓝牙初始化的默认参数,这个宏默认仅初始化BLE部分。
// 初始化蓝牙 Control 层
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ret = esp_bt_controller_init(&bt_cfg);
if (ret) {ESP_LOGE(GATTS_TABLE_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));return;
}
<3>我们对蓝牙
Control初始化完成之后,需要调用esp_bt_controller_enable()对Control层进行使能。传入值是一个enum参数。
ESP_BT_MODE_IDLE: 失能蓝牙ESP_BT_MODE_BLE: 仅运行低功耗蓝牙(BLE)ESP_BT_MODE_CLASSIC_BT: 仅运行传统蓝牙(BR/EDR)ESP_BT_MODE_IDLE: 即运行低功耗蓝牙(BLE)又运行传统蓝牙(BR/EDR)
// 使能蓝牙 Control 层
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (ret) {ESP_LOGE(GATTS_TABLE_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));return;
}
<4>如果我们的
Host层不是运行在ESP32上,那么只需要进行如上操作即可。但是该例程是采用的单芯片方案,因此还需要对Host层进行初始化,这是使用的Bluedroid协议栈。
// 初始化蓝牙 HOST 层
ret = esp_bluedroid_init();
if (ret) {ESP_LOGE(GATTS_TABLE_TAG, "%s init bluetooth failed: %s", __func__, esp_err_to_name(ret));return;
}
<5>初始化
bluedroid之后,再进行使能即可。
// 使能蓝牙 HOST 层
ret = esp_bluedroid_enable();
if (ret) {ESP_LOGE(GATTS_TABLE_TAG, "%s enable bluetooth failed: %s", __func__, esp_err_to_name(ret));return;
}
<6>如下部分在后面章节会进一步讲解,各位看一下代码注释简单了解即可。
// 注册 GATT 回调函数,处理所有的 GATT 事件ret = esp_ble_gatts_register_callback(gatts_event_handler);if (ret){ESP_LOGE(GATTS_TABLE_TAG, "gatts register error, error code = %x", ret);return;}// 注册 GAP 回调函数,ret = esp_ble_gap_register_callback(gap_event_handler);if (ret){ESP_LOGE(GATTS_TABLE_TAG, "gap register error, error code = %x", ret);return;}/* 注册一个app_id, 协议栈将会分配一个对应的 gatts_if,用于标识一个 GATT 服务。* 调用这个函数就会触发 esp_ble_gatts_register_callback() 注册的回调函数中的 ESP_GATTS_REG_EVT 事件*/ret = esp_ble_gatts_app_register(heart_rate_profile_tab[PROFILE_APP_IDX].app_id);if (ret){ESP_LOGE(GATTS_TABLE_TAG, "gatts app register error, error code = %x", ret);return;}// 设置本地 MTU 大小esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(500);if (local_mtu_ret){ESP_LOGE(GATTS_TABLE_TAG, "set local MTU failed, error code = %x", local_mtu_ret);}
参考
(1)乐鑫官方文档:ESP32蓝牙架构
(2)《低功耗蓝牙开发权威指南》第三章 —— 低功耗蓝牙的体系结构。
(3)《低功耗蓝牙开发权威指南》2.9章节 —— 十亿只是小目标。
(4)博客园:三种蓝牙架构实现方案(蓝牙协议栈方案)
相关文章:
ESP32 BLE学习(0) — 基础架构
前言 (1)学习本文之前,需要先了解一下蓝牙的基本概念:BLE学习笔记(0.0) —— 基础概念(0) (2) 学习一款芯片的蓝牙肯定需要先简单了解一下该芯片的体系结构&a…...
【JAVA】Java中Spring Boot如何设置全局的BusinessException
文章目录 前言一、函数解释二、代码实现三、总结 前言 在Java应用开发中,我们常常需要读取配置文件。Spring Boot提供了一种方便的方式来读取配置。在本文中,我们将探讨如何在Spring Boot中使用Value和ConfigurationProperties注解来读取配置。 一、函数…...
pdf.js实现web h5预览pdf文件(兼容低版本浏览器)
注意 使用的是pdf.js 版本为 v2.16.105。因为新版本 兼容性不太好,部分手机预览不了,所以采用v2版本。 相关依赖 "canvas": "^2.11.2", "pdfjs-dist": "^2.16.105", "core-js-pure": "^3.37.…...
SSID简介
一、 SSID 概念定义 SSID(Service Set Identifier)即服务集标识符。它是无线网络中的一个重要标识,用于区分不同的无线网络。 相当于无线网络的名称,用于区分不同的无线网络。用户在众多可用网络中识别和选择特定网络的依据。通…...
PS通过GTX实现SFP网络通信1
将 PS ENET1 的 GMII 接口和 MDIO 接口 通过 EMIO 方 式引出。在 PL 端将引出的 GMII 接口和 MDIO 接口与 IP 核 1G/2.5G Ethernet PCS/PMA or SGMII 连接, 1G/2.5G Ethernet PCS/PMA or SGMII 通过高速串行收发器 GTX 与 MIZ7035/7100 开发…...
前端面试项目细节重难点(已工作|做分享)(九)
面试官:请你讲讲你在工作中如何开发一个新需求,你的整个开发过程是什么样的? 答:仔细想想,我开发新需求的过程如下: (1)第一步:理解需求文档: 首先&#x…...
区间预测 | Matlab实现BP-ABKDE的BP神经网络自适应带宽核密度估计多变量回归区间预测
区间预测 | Matlab实现BP-ABKDE的BP神经网络自适应带宽核密度估计多变量回归区间预测 目录 区间预测 | Matlab实现BP-ABKDE的BP神经网络自适应带宽核密度估计多变量回归区间预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现BP-ABKDE的BP神经网络自适应带…...
抢占人工智能行业红利,前阿里巴巴产品专家带你15天入门AI产品经理
前言 当互联网行业巨头纷纷布局人工智能,国家将人工智能上升为国家战略,藤校核心课程涉足人工智能…人工智能领域蕴含着巨大潜力,早已成为业内共识。 面对极大的行业空缺,不少人都希望能抢占行业红利期,进入AI领域。…...
MEMS:Lecture 16 Gyros
陀螺仪原理 A classic spinning gyroscope measures the rotation rate by utilizing the conservation of angular momentum. 经典旋转陀螺仪通过利用角动量守恒来测量旋转速率。 Coriolis Effect and Coriolis Force 科里奥利效应是一种出现在旋转参考系中的现象。它描述了…...
Java中List流式转换为Map的终极指南
哈喽,大家好,我是木头左! 在Java编程中,经常需要将一个List对象转换为另一个Map对象。这可能是因为需要根据List中的元素的某些属性来创建一个新的键值对集合。在本文中,我将向您展示如何使用Java 中的流式API轻松地实…...
【秋招突围】2024届秋招笔试-小红书笔试题-第一套-三语言题解(Java/Cpp/Python)
🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系计划跟新各公司春秋招的笔试题 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 📧 清隆这边…...
HAL库开发--STM32的HAL环境搭建
知不足而奋进 望远山而前行 目录 文章目录 前言 下载 安装 解压 安装 添加开发包 修改仓库路径 下载软件开发包(慢,不推荐) 解压已有软件开发包(快,推荐) 总结 前言 在嵌入式系统开发中&#x…...
【DPDK学习路径】七、创建RX/TX队列
上一节我们讲述了如何申请内存池缓冲区以便接下来创建 RX 队列,这一节我们将给出具体如何创建 RX/TX 队列。 在 DPDK 中提供了 rte_eth_rx_queue_setup 及 rte_eth_tx_queue_setup 这两个接口用于接收/发送队列的创建。 下面给出一个为各个网卡创建RX/TX 队列的实例…...
【ArcGISProSDK】OpenItemDialog打开文件对话框
打开单个文件 效果 代码 public async void OpenFunction() {// 获取默认数据库var gdbPath Project.Current.DefaultGeodatabasePath;OpenItemDialog openItemDialog new OpenItemDialog() { Title "打开要素文件",InitialLocation gdbPath,Filter ItemFilte…...
TensorFlow2.x基础与mnist手写数字识别示例
文章目录 Github官网文档Playground安装声明张量常量变量 张量计算张量数据类型转换张量数据维度转换ReLU 函数Softmax 函数卷积神经网络训练模型测试模型数据集保存目录显示每层网络的结果 TensorFlow 是一个开源的深度学习框架,由 Google Brain 团队开发和维护。它…...
大数据开发语言Scala入门
Scala是一种多范式编程语言,它集成了面向对象编程和函数式编程的特性。Scala运行在Java虚拟机上,并且可以与Java代码无缝交互,这使得它成为大数据处理和分析领域中非常受欢迎的语言,尤其是在使用Apache Spark这样的框架时。 Scal…...
【CDN】逆天 CDN !BootCDN 向 JS 文件中植入恶意代码
今天在调试代码,突然控制台出现了非常多报错。 这非常可疑,报错指向的域名也证实了这一点。 因为我的 HTML 中只有一个外部开源库(qrcode.min.js),因此只有可能是它出现了问题。 我翻看了请求记录,发现这…...
摆脱Jenkins - 使用google cloudbuild 部署 java service 到 compute engine VM
在之前 介绍 cloud build 的文章中 初探 Google 云原生的CICD - CloudBuild 已经介绍过, 用cloud build 去部署1个 spring boot service 到 cloud run 是很简单的, 因为部署cloud run 无非就是用gcloud 去部署1个 GAR 上的docker image 到cloud run 容…...
【CS.PL】Lua 编程之道: 控制结构 - 进度24%
3 初级阶段 —— 控制结构 文章目录 3 初级阶段 —— 控制结构3.1 条件语句:if、else、elseif3.2 循环语句:for、while、repeat-until3.2.1 输出所有的命令行参数3.2.2 while.lua3.2.3 repeat.lua及其作用域 🔥3.2.4 for.lua (For Statement)…...
从“数据孤岛”、Data Fabric(数据编织)谈逻辑数据平台
提到逻辑数据平台,其核心在于“逻辑”,与之相对的便是“物理”。在过去,为了更好地利用和管理数据,我们通常会选择搭建数据仓库和数据湖,将所有数据物理集中起来。但随着数据量、用数需求和用数人员的持续激增…...
HertzBeat与Prometheus兼容性详解:平滑迁移和生态整合终极指南
HertzBeat与Prometheus兼容性详解:平滑迁移和生态整合终极指南 Apache HertzBeat是一款功能强大的开源实时监控系统,与Prometheus生态系统完美兼容,提供无代理、高性能集群和自定义监控功能。🚀 作为新一代监控工具,H…...
5步打造Android Studio中文界面配置:从基础设置到效率倍增的本地化环境方案
5步打造Android Studio中文界面配置:从基础设置到效率倍增的本地化环境方案 【免费下载链接】AndroidStudioChineseLanguagePack AndroidStudio中文插件(官方修改版本) 项目地址: https://gitcode.com/gh_mirrors/an/AndroidStudioChineseLanguagePack…...
League-Toolkit:英雄联盟智能助手的全方位解决方案
League-Toolkit:英雄联盟智能助手的全方位解决方案 【免费下载链接】League-Toolkit 兴趣使然的、简单易用的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit 在快节奏的英雄联盟…...
基于Python+Hadoop+Spark的美食推荐系统 数据采集与可视化平台 Django框架
1、项目介绍 技术栈 Python语言、Django框架、Scrapy爬虫框架、Echarts 可视化,采集下厨房网站数据。功能模块推荐美食美食用料排行榜分析美食分类占比分析饮食科普美食分类美食详情信息美食详情做法后台数据管理项目介绍本项目基于指定技术栈,爬取下厨房…...
告别移植头疼!用STM32CubeMX快速复用正点原子LCD库的3个关键步骤
告别移植头疼!用STM32CubeMX快速复用正点原子LCD库的3个关键步骤 在嵌入式开发中,复用成熟的驱动代码是提升效率的关键。正点原子的LCD库因其稳定性和易用性广受欢迎,但在STM32CubeMX生成的HAL工程中直接使用却常常遇到各种兼容性问题。本文将…...
Dify插件安装全攻略:从在线市场到离线部署的完整实践
1. Dify插件安装前的准备工作 在开始安装Dify插件之前,我们需要先了解几个关键概念。Dify 1.0.0版本之后,所有工具和模型供应商都改为了插件形式,这意味着我们需要掌握插件的安装方法才能充分发挥Dify的功能。插件主要分为五大类:…...
如何用免费工具实现专业级UML设计?高效绘图全攻略
如何用免费工具实现专业级UML设计?高效绘图全攻略 【免费下载链接】umlet Free UML Tool for Fast UML Diagrams 项目地址: https://gitcode.com/gh_mirrors/um/umlet 在软件开发流程中,架构师小张曾因缺少专业UML工具而陷入困境:用普…...
KDE vs直方图:7个真实数据集对比告诉你何时该用核密度估计
KDE vs直方图:7个真实数据集对比揭示核密度估计的最佳实践 在数据分析的日常工作中,我们常常需要快速理解数据的分布特征。直方图作为最基础的分布可视化工具,几乎成为每个数据分析师的第一选择。但当我第一次在电商用户行为分析中遇到双峰分…...
2026整家定制一线品牌选购报告:基于物理指标与国标数据的多维交叉验证
针对用户关于“2026年整家定制一线品牌推荐”及“质量好的定制品牌有哪些”的咨询,评估的核心不应仅停留在品牌知名度,而在于能否在结构力学稳定性、材料理化抗性、数字化设计精度及长效履约信用四个维度完成证据链闭环。本文通过检索 金牌家居ÿ…...
5步征服显存难题:多语言MiniLM模型量化优化实战指南
5步征服显存难题:多语言MiniLM模型量化优化实战指南 【免费下载链接】paraphrase-multilingual-MiniLM-L12-v2 项目地址: https://ai.gitcode.com/hf_mirrors/ai-gitcode/paraphrase-multilingual-MiniLM-L12-v2 1. 诊断显存瓶颈 在部署paraphrase-multili…...
