BLE是蓝牙4.0标准中的一个子集,也就是说,蓝牙4.0标准包含了BLE和经典蓝牙(BR/EDR)两种模式。BLE是低功耗蓝牙,而经典蓝牙则是一种传统的蓝牙技术,适用于传输音频和文件等大数据量数据。
蓝牙4.0是一个综合性协议规范,它将低功耗蓝牙和经典蓝牙两种技术融合在一起,从而提供了更广泛的应用场景和更高效的数据传输能力。在蓝牙4.0中,低功耗蓝牙和经典蓝牙可以同时运行,并且可以互相通信,从而实现了更加灵活和高效的应用。
因此,BLE和蓝牙4.0之间的关系是子集和总体的关系,BLE是蓝牙4.0标准中的一个特定技术分支。
GATT
GATT(Generic Attribute Profile)是蓝牙低功耗(Bluetooth Low Energy,BLE)协议栈中的一部分,它定义了 BLE 设备之间交换数据的格式和规范。
GATT基于属性和服务的概念,通过将数据封装在属性中,从而实现设备之间的通信。在GATT中,一个服务表示一个特定的功能,一个服务可以包含多个属性。每个属性都有一个唯一的标识符(UUID),可以用来识别它们。属性可以是只读的(Read),也可以是可写的(Write)。属性还可以包含一个描述符(Descriptor),用于描述属性的特性和值。
此外,GATT使用基于请求-响应模型的通信方式。当一个设备想要读取或写入属性时,它会发送一个请求给另一个设备,请求的格式包含要访问的属性的UUID和操作类型(读或写)。接收方设备会根据请求返回响应消息,其中包含请求的数据,或者在写入操作时返回确认消息。
BLE 里面的数据以属性(Attribute)方式存在,每条属性由四个元素组成:
- 属性句柄(Attribute Handle):正如我们可以使用内存地址查找内存中的内容一样,ATT 属性的句柄也可以协助我们找到相应的属性,例如第一个属性的句柄是0x0001,第二个属性的句柄是 0x0002,以此类推,最大可以到 0xFFFF。
- 属性类型(Attribute UUID):每个数据有自己需要代表的意思,例如表示温度、发射功率、电池等等各种各样的信息。蓝牙组织(Bluetooth SIG)对常用的一些数据类型进行了归类,赋予不同的数据类型不同的标识码(UUID)。例如0x2A09表示电池信息,0x2A6E表示温度信息。UUID可以是 16 比特的(16-bit UUID),也可以是 128 比特的(128-bit UUID)。
- 属性值(Attribute Value):属性值是每个属性真正要承载的信息,其他 3个元素都是为了让对方能够更好地获取属性值。有些属性的长度是固定的,例如电池属性(Battery Level)的长度只有 1个字节,因为需要表示的数据仅有 0~100%,而 1 个字节足以表示1~100的范围;而有些属性的长度是可变的,例如基于 BLE实现的透传模块。
- 属性许可(Attribute Permissions):每个属性对各自的属性值有相应的访问限制,比如有些属性是可读的、有些是可写的、有些是可读又可写的等等。拥有数据的一方可以通过属性许可,控制本地数据的可读写属性。
服务器和客户端的交互
我们把存有数据(即属性)的设备叫做服务器(Server),而将获取别人设备数据的设备叫做客户端(Client)。下面是服务器和客户端间的常用操作:
客户端给服务端发数据,通过对服务器的数据进行写操作(Write),来完成数据发送工作。写操作分两种,一种是写入请求(Write Request),一种是写入命令(Write Command),两者的主要区别是前者需要对方回复响应(Write Response),而后者不需要对方回复响应。
服务端给客户端发数据,主要通过服务端指示(Indication)或者通知(Notification)的形式,实现将服务端更新的数据发给客户端。与写操作类似,指示和通知的主要区别是前者需要对方设备在收到数据指示后,进行回复(Confirmation)。
客户端也可以主动通过读操作读取服务端的数据。
例如 PC 要获取传感器的数据时,PC 为 GATT Client,传感器为 GATT Server。
ESP32 蓝牙主机与控制器
从整体结构上,蓝牙可分为控制器(Controller)和主机(Host)两大部分:控制器包括了PHY、Baseband、Link Controller、Link Manager、Device Manager、HCI 等模块,用于硬件接口管理、链路管理等等;主机则包括了L2CAP、SMP、SDP、ATT、GATT、GAP以及各种规范,构建了向应用层提供接口的基础,方便应用层对蓝牙系统的访问。主机可以与控制器运行在同一个宿主上,也可以分布在不同的宿主上。
硬件连接
经典蓝牙
本章硬件无连线,使用蓝牙连接开发板和电脑,使用开发板端的蓝牙转串口,虚拟出一个串口设备。电脑端连接开发板蓝牙后,也会虚拟出一个串口,使用两个串口来通信。
软件设计
经典蓝牙
打开例程
本章使用Arduino
的例程,选择示例—BluetoothSerial—SerialToSerial
。
打开后修改一下蓝牙名称和配对密码即可,不修改也行。
编译运行信息如下。
连接蓝牙
使用电脑端的蓝牙搜索。能看到已经有了。点击连接。正常会要求输入配对密码,输入后连接。其会安装一些文件。连接成功后会虚拟出一个串口。(此处为 COM11)
打开虚拟串口
设定如下的参数后,打开 COM11。
验证功能
此时也打开Arduino
的串口监视器。设定波特率 115200。
点击串口助手中的发送按钮,Arduino
的串口监视器中就出现了发送的字符了。也可以从串口监视器发送字符到串口助手,双向通信没问题。
经过以上步骤,板子就可以和电脑实现无线通信了。
完整代码
//This example code is in the Public Domain (or CC0 licensed, at your option.)
//By Evandro Copercini - 2018
//
//This example creates a bridge between Serial and Classical Bluetooth (SPP)
//and also demonstrate that SerialBT have the same functionalities of a normal Serial
#include "BluetoothSerial.h"
//#define USE\_PIN // Uncomment this to use PIN during pairing. The pin is specified on the line below
const char \*pin = "3625"; // Change this to more secure PIN.
String device_name = "CC-BT";
#if !defined(CONFIG\_BT\_ENABLED) || !defined(CONFIG\_BLUEDROID\_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif
#if !defined(CONFIG\_BT\_SPP\_ENABLED)
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
#endif
BluetoothSerial SerialBT;
void setup() {
Serial.begin(115200);
SerialBT.begin(device_name); //Bluetooth device name
Serial.printf("The device with name \"%s\" is started.\nNow you can pair it with Bluetooth!\n", device_name.c\_str());
//Serial.printf("The device with name \"%s\" and MAC address %s is started.\nNow you can pair it with Bluetooth!\n", device\_name.c\_str(), SerialBT.getMacString()); // Use this after the MAC method is implemented
#ifdef USE\_PIN
SerialBT.setPin(pin);
Serial.println("Using PIN");
#endif
}
void loop() {
if (Serial.available()) {
SerialBT.write(Serial.read());
}
if (SerialBT.available()) {
Serial.write(SerialBT.read());
}
delay(20);
}
BLE
由于微信官方文档-小程序指南中写了小程序目前不支持经典蓝牙,只支持蓝牙低功耗(BLE)。所以就有了下面 BLE 的内容。
打开例程
本章使用Arduino
的例程,选择示例—ESP32 BLE Arduino—BLE_uart
。
看例程前面的注释,含义如下。
例程创建了一个 BLE 服务器,有三个 UUID,第一个为设备 UID,第二个用于发送带有“Notify”的数据,第三个用于接收带有“Write”的数据。
创建 BLE 服务器有以下几步:
- 创建 BLE Server。
- 创建 BLE Service。
- 在 BLE Service 上创建 BLE Characteristic。
- 在 BLE Characteristic 上创建 BLE Descriptor。
- 启动服务。
- 开始广播。
修改例程
在下图中的网址中生成 3 组 UUID。
再将 3 组 UUID 分别填入SERVICE_UUID
、CHARACTERISTIC_UUID_RX
、CHARACTERISTIC_UUID_TX
的位置,代码如下。
#define SERVICE\_UUID "2c3eaaaa-6762-4039-8902-6fd7e51b81af" // UART service UUID
#define CHARACTERISTIC\_UUID\_RX "4de93100-e96b-436b-a07b-21de47c15af6"
#define CHARACTERISTIC\_UUID\_TX "5fb4a2c3-d9cb-4f0e-9c6b-7ed3a60800be"
编译后下载。
连接蓝牙
打开手机蓝牙,安装蓝牙调试助手,我用的是下面这款。
搜索蓝牙设备。名称是代码中默认的UART Service
。
// Create the BLE Device
BLEDevice::init("UART Service");
点击即可配对。能看到SERVICE_UUID
、CHARACTERISTIC_UUID_RX
、CHARACTERISTIC_UUID_TX
是之前我们设置好的值。如果SERVICE_UUID
不是设置的值,则可能是下面的原因。
验证功能
在手机端连接UART Service
,再断开。会出现下面开始广播的提示。
在连接的页面选择最下面的 UUID 为4de93100-e96b-436b-a07b-21de47c15af6
的特征值。然后输入要发送的字符串,点击写入。就能在 ESP32 的串口看到发送的数据了。
也可以选择 16 进制发送。
16 进制发送的 0x23,接收到的数值变成了“#”,这是因为此处是将收到的数据按照数据的Ascii
码打印的,16 进制的 0x23 其Ascii
码为“#”。
要想将收到的数据按照 16 进制打印,修改一下给打印函数的传参,编译下载,发送 16 进制 0x23 即可。
class MyCallbacks : public BLECharacteristicCallbacks
{
void onWrite(BLECharacteristic \*pCharacteristic)
{
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0)
{
Serial.println("\*\*\*\*\*\*\*\*\*");
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++)
Serial.print(rxValue[i], HEX);
Serial.println();
Serial.println("\*\*\*\*\*\*\*\*\*");
}
}
};
完整代码
以下代码是在 VS Code 环境下,采用
platformio
插件创建的工程。
#include <Arduino.h>
/\*
Video: https://www.youtube.com/watch?v=oCMOYS71NIU
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp\_utils/tests/BLE%20Tests/SampleNotify.cpp
Ported to Arduino ESP32 by Evandro Copercini
Create a BLE server that, once we receive a connection, will send periodic notifications.
The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE"
Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with "NOTIFY"
The design of creating the BLE server is:
1. Create a BLE Server
2. Create a BLE Service
3. Create a BLE Characteristic on the Service
4. Create a BLE Descriptor on the characteristic
5. Start the service.
6. Start advertising.
In this example rxValue is the data received (only accessible inside that function).
And txValue is the data to be sent, in this example just a byte incremented every second.
\*/
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
BLEServer \*pServer = NULL;
BLECharacteristic \*pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint8\_t txValue = 0;
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE\_UUID "2c3eaaaa-6762-4039-8902-6fd7e51b81af" // UART service UUID
#define CHARACTERISTIC\_UUID\_RX "4de93100-e96b-436b-a07b-21de47c15af6"
#define CHARACTERISTIC\_UUID\_TX "5fb4a2c3-d9cb-4f0e-9c6b-7ed3a60800be"
class MyServerCallbacks : public BLEServerCallbacks
{
void onConnect(BLEServer \*pServer)
{
deviceConnected = true;
};
void onDisconnect(BLEServer \*pServer)
{
deviceConnected = false;
}
};
class MyCallbacks : public BLECharacteristicCallbacks
{
void onWrite(BLECharacteristic \*pCharacteristic)
{
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0)
{
Serial.println("\*\*\*\*\*\*\*\*\*");
Serial.print("Received Value: ");
## 最后
**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**
**深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。**
**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**







**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!
外链图片转存中...(img-vh82rcfE-1715842229142)]
[外链图片转存中...(img-A68PapPf-1715842229143)]
[外链图片转存中...(img-msBwQJu5-1715842229144)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!