(4)蓝牙使用(Classic BT+BLE)_同一个芯片经典蓝牙和ble能同时支持蓝牙连接和被扫描吗

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)方式存在,每条属性由四个元素组成:

  1. 属性句柄(Attribute Handle):正如我们可以使用内存地址查找内存中的内容一样,ATT 属性的句柄也可以协助我们找到相应的属性,例如第一个属性的句柄是0x0001,第二个属性的句柄是 0x0002,以此类推,最大可以到 0xFFFF。
  2. 属性类型(Attribute UUID):每个数据有自己需要代表的意思,例如表示温度、发射功率、电池等等各种各样的信息。蓝牙组织(Bluetooth SIG)对常用的一些数据类型进行了归类,赋予不同的数据类型不同的标识码(UUID)。例如0x2A09表示电池信息,0x2A6E表示温度信息。UUID可以是 16 比特的(16-bit UUID),也可以是 128 比特的(128-bit UUID)。
  3. 属性值(Attribute Value):属性值是每个属性真正要承载的信息,其他 3个元素都是为了让对方能够更好地获取属性值。有些属性的长度是固定的,例如电池属性(Battery Level)的长度只有 1个字节,因为需要表示的数据仅有 0~100%,而 1 个字节足以表示1~100的范围;而有些属性的长度是可变的,例如基于 BLE实现的透传模块。
  4. 属性许可(Attribute Permissions):每个属性对各自的属性值有相应的访问限制,比如有些属性是可读的、有些是可写的、有些是可读又可写的等等。拥有数据的一方可以通过属性许可,控制本地数据的可读写属性。

服务器和客户端的交互

我们把存有数据(即属性)的设备叫做服务器(Server),而将获取别人设备数据的设备叫做客户端(Client)。下面是服务器和客户端间的常用操作:
客户端给服务端发数据,通过对服务器的数据进行写操作(Write),来完成数据发送工作。写操作分两种,一种是写入请求(Write Request),一种是写入命令(Write Command),两者的主要区别是前者需要对方回复响应(Write Response),而后者不需要对方回复响应。
服务端给客户端发数据,主要通过服务端指示(Indication)或者通知(Notification)的形式,实现将服务端更新的数据发给客户端。与写操作类似,指示和通知的主要区别是前者需要对方设备在收到数据指示后,进行回复(Confirmation)。
客户端也可以主动通过读操作读取服务端的数据。
image.png
例如 PC 要获取传感器的数据时,PC 为 GATT Client,传感器为 GATT Server。

ESP32 蓝牙主机与控制器

从整体结构上,蓝牙可分为控制器(Controller)和主机(Host)两大部分:控制器包括了PHY、Baseband、Link Controller、Link Manager、Device Manager、HCI 等模块,用于硬件接口管理、链路管理等等;主机则包括了L2CAP、SMP、SDP、ATT、GATT、GAP以及各种规范,构建了向应用层提供接口的基础,方便应用层对蓝牙系统的访问。主机可以与控制器运行在同一个宿主上,也可以分布在不同的宿主上。
image.png

硬件连接

经典蓝牙

本章硬件无连线,使用蓝牙连接开发板和电脑,使用开发板端的蓝牙转串口,虚拟出一个串口设备。电脑端连接开发板蓝牙后,也会虚拟出一个串口,使用两个串口来通信。

软件设计

经典蓝牙

打开例程

本章使用Arduino的例程,选择示例—BluetoothSerial—SerialToSerial
image.png
打开后修改一下蓝牙名称和配对密码即可,不修改也行。
image.png
编译运行信息如下。image.png

连接蓝牙

使用电脑端的蓝牙搜索。能看到已经有了。点击连接。正常会要求输入配对密码,输入后连接。其会安装一些文件。连接成功后会虚拟出一个串口。(此处为 COM11)
image.png
image.png
image.png

打开虚拟串口

设定如下的参数后,打开 COM11。
image.png

验证功能

此时也打开Arduino的串口监视器。设定波特率 115200。
image.pngimage.png
点击串口助手中的发送按钮,Arduino的串口监视器中就出现了发送的字符了。也可以从串口监视器发送字符到串口助手,双向通信没问题。
image.png
经过以上步骤,板子就可以和电脑实现无线通信了。

完整代码
//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 的内容。
image.png

打开例程

本章使用Arduino的例程,选择示例—ESP32 BLE Arduino—BLE_uart
image.png
看例程前面的注释,含义如下。
例程创建了一个 BLE 服务器,有三个 UUID,第一个为设备 UID,第二个用于发送带有“Notify”的数据,第三个用于接收带有“Write”的数据。
创建 BLE 服务器有以下几步:

  1. 创建 BLE Server。
  2. 创建 BLE Service。
  3. 在 BLE Service 上创建 BLE Characteristic。
  4. 在 BLE Characteristic 上创建 BLE Descriptor。
  5. 启动服务。
  6. 开始广播。
修改例程

在下图中的网址中生成 3 组 UUID。
image.png
image.png
再将 3 组 UUID 分别填入SERVICE_UUIDCHARACTERISTIC_UUID_RXCHARACTERISTIC_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"

编译后下载。
image.png

连接蓝牙

打开手机蓝牙,安装蓝牙调试助手,我用的是下面这款。
image.png
搜索蓝牙设备。名称是代码中默认的UART Service

  // Create the BLE Device
  BLEDevice::init("UART Service");

image.pngimage.png
点击即可配对。能看到SERVICE_UUIDCHARACTERISTIC_UUID_RXCHARACTERISTIC_UUID_TX是之前我们设置好的值。如果SERVICE_UUID不是设置的值,则可能是下面的原因。
image.png

验证功能

在手机端连接UART Service,再断开。会出现下面开始广播的提示。
image.png
image.png
在连接的页面选择最下面的 UUID 为4de93100-e96b-436b-a07b-21de47c15af6的特征值。然后输入要发送的字符串,点击写入。就能在 ESP32 的串口看到发送的数据了。
image.pngimage.png
image.png
也可以选择 16 进制发送。
image.pngimage.png
16 进制发送的 0x23,接收到的数值变成了“#”,这是因为此处是将收到的数据按照数据的Ascii码打印的,16 进制的 0x23 其Ascii码为“#”。
image.png
image.png
要想将收到的数据按照 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("\*\*\*\*\*\*\*\*\*");
    }
  }
};

image.png

完整代码

以下代码是在 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年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

![img](https://img-blog.csdnimg.cn/img_convert/1ed4d86adb98e63a55636fd774f9bcc7.png)

![img](https://img-blog.csdnimg.cn/img_convert/3b4723cd996f0208ff7c3c8146df4a46.jpeg)

![img](https://img-blog.csdnimg.cn/img_convert/ce5bc5ff4d4c09cc156b61570e637a5e.png)

 ![img](https://img-blog.csdnimg.cn/img_convert/c4e21f6bc4fe33a8550ad5fc1cac993a.png)

![img](https://img-blog.csdnimg.cn/img_convert/aee93589043d47ed904d4f9efd075dc3.png)

![img](https://img-blog.csdnimg.cn/img_convert/257f8373a9855fd303fd9bb2f621a577.png)

![](https://img-blog.csdnimg.cn/img_convert/3c12a636cd086ea7ee0990b5d57de051.png)

 

**既有适合小白学习的零基础资料,也有适合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)

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!


  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的CC2642 BLE蓝牙连接流程的代码示例,供您参考: ```c #include "simple_ble.h" #include "ti_drivers_config.h" // 定义服务和特征UUID static simple_ble_service_t my_service = {{ .uuid128 = {0x00, 0x00, 0x00, 0x00, 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x00} }}; static simple_ble_char_t my_char = { .uuid16 = 0x1234, .properties = PROP_RW, .value_length = 4 }; static uint8_t my_value[4] = {0x00, 0x01, 0x02, 0x03}; // 初始化BLE void ble_init(void) { // 初始化simple BLE库 simple_ble_init(&ti_drivers_ble_config); // 注册服务和特征 simple_ble_add_service(&my_service); simple_ble_add_characteristic(1, 1, 0, 0, // Service index, characteristic index sizeof(my_value), (uint8_t*)my_value, &my_service.uuid128, &my_char.uuid16, &my_char); // 开始广播 simple_ble_adv_only_name(); } // 处理BLE事件 void ble_evt_handler(ble_evt_t const* p_ble_evt) { switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_CONNECTED: // 连接建立后,可以在此处启动数据传输等操作 break; case BLE_GAP_EVT_DISCONNECTED: // 连接断开后,可以在此处停止数据传输等操作 break; default: // 其他事件处理 break; } } int main(void) { // 初始化BLE ble_init(); while (1) { // 处理BLE事件 simple_ble_app_event_loop(); // 主程序其他逻辑 // ... } } ``` 在上面的示例中,我们使用了Simple BLE库来简化BLE开发。首先在`ble_init()`函数中初始化Simple BLE库,注册服务和特征,并开始广播。在`ble_evt_handler()`函数中处理BLE事件,包括连接建立和连接断开。在主程序循环中,通过`simple_ble_app_event_loop()`函数来处理BLE事件。 需要注意的是,此示例仅演示了最基本的BLE连接流程,实际应用中需要根据具体需求进行修改和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值