问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

BLE低功耗蓝牙技术详解:从理论到实践

创作时间:
作者:
@小白创作中心

BLE低功耗蓝牙技术详解:从理论到实践

引用
CSDN
1.
https://blog.csdn.net/qq_62544059/article/details/140582036

在物联网和嵌入式开发领域,低功耗蓝牙(BLE)技术因其低功耗、短距离通信等特点而被广泛应用。本文将从BLE的基本概念出发,介绍其在游戏手柄与单片机连接中的应用,并通过具体代码示例展示如何使用ESP32单片机读取游戏手柄数据。

BLE简介

BLE(Bluetooth Low Energy),也称为蓝牙低功耗,是一种无线个人区域网络技术,用于短距离数据交换。它在经典蓝牙的基础上进行了优化,专注于降低能耗,同时仍然提供足够的通信性能。

它具有非常低的电量消耗,并且可以在非常短的时间内进行连接和数据传输。不过也有很多缺点,包括通讯距离短,适合近距离的无线交互。

BLE蓝牙通讯特点

BLE通讯主要由广播(Advertising)和连接(Connection)两部分组成。广播是BLE设备宣布其存在并传递少量数据的一种方式,主要有Advertising Packets(包含设备的基本信息,如设备名称、服务UUID等)和Scan Response Packets(设备在接收到扫描请求时返回的额外信息)。

广播包结构包括Preamble(1字节,固定为0xAA),Access Address(4字节,广播信道的地址,固定为0x8E89BED6),PDU(可变长度,包含实际的数据),和CRC(3字节,用于校验数据完整性)。连接建立后,数据通过连接事件(Connection Events)进行传输,每个连接事件包括主设备(Central)和从设备(Peripheral)之间的一次完整的数据交换。连接事件结构包括Header(包含包类型和长度信息),LL Data(链路层数据,包括控制包或用户数据),和MIC(用于确保数据完整性和防止篡改)。

数据通过预定义的服务和特性(Characteristic)进行传输,每个特性都有一个唯一的UUID(通用唯一标识符)。服务是一个逻辑功能单元,包含多个特性,例如心率服务包含测量值和传感器位置等特性;特性是一个具体的数据单元,包括一个值和可选的描述符(提供关于特性值的额外信息,如格式、范围等)。

如果比较难明白的话,我们直接用手机的BLE调试助手连接我的手柄查看具体的。

一个BLE蓝牙设备会向外广播信息,而我们就需要知道特定的服务UUID和特性UUID来获取信息,例如这里我知道我需要的服务UUID如下。

特性UUID如下,这样子我就可以接收到设备发出的信息了,这些信息包括了手柄的摇杆,各个按键状态信息等等。

单片机连接手柄

我们首先需要一款能够支持BLE的单片机或者模块,这里选择使用ESP32,它可以连接BLE设备并且可以对信息处理。以下是具体的代码实现:

#include "BLEDevice.h"
#include <Wire.h>

BLEClient* pClient;
BLERemoteService* pRemoteService;
BLERemoteCharacteristic* pRemoteCharacteristic;

static BLEAddress targetAddress("a4:c1:38:91:43:57"); // 替换为目标设备的MAC地址

int Lx,Ly;

class MyClientCallback : public BLEClientCallbacks {
  void onConnect(BLEClient* pClient) {
    Serial.println("Connected to the target device.");
  }

  void onDisconnect(BLEClient* pClient) {
    Serial.println("Disconnected from the target device.");
  }
};

void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE client...");

  BLEDevice::init("");

  // 创建客户端
  pClient = BLEDevice::createClient();
  pClient->setClientCallbacks(new MyClientCallback());

  // 尝试连接目标设备
  if (pClient->connect(targetAddress)) {
    Serial.println("Connected to device.");
  } else {
    Serial.println("Failed to connect.");
    return;
  }

  // 获取远程服务
  pRemoteService = pClient->getService("00001812-0000-1000-8000-00805f9b34fb"); // 替换为目标设备的服务UUID
  if (pRemoteService == nullptr) {
    Serial.print("Failed to find service UUID: ");
    Serial.println("SERVICE_UUID");
    pClient->disconnect();
    return;
  }
  Serial.println("Found the service.");

  // 获取远程特性
  pRemoteCharacteristic = pRemoteService->getCharacteristic("00002a4d-0000-1000-8000-00805f9b34fb"); // 替换为目标设备的特性UUID
  if (pRemoteCharacteristic == nullptr) {
    Serial.print("Failed to find characteristic UUID: ");
    Serial.println("CHARACTERISTIC_UUID");
    pClient->disconnect();
    return;
  }
  Serial.println("Found the characteristic.");

  // 读取特性值
  if (pRemoteCharacteristic->canRead()) {
    std::string value = pRemoteCharacteristic->readValue();
    Serial.print("Characteristic value: ");
    Serial.println(value.c_str());
  }

  // 设置特性通知
  if (pRemoteCharacteristic->canNotify()) {
    pRemoteCharacteristic->registerForNotify(notifyCallback);
  }
}

void loop() {

}

// 通知回调函数
void notifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic,
                    uint8_t* pData,
                    size_t length,
                    bool isNotify) {
  Lx = pData[0];
  Ly = pData[1];
  Serial.print("x:"+String(Lx));
  Serial.println(",y:"+String(Ly));
}

这段代码展示了如何使用ESP32连接BLE设备并读取其数据。通过设置服务UUID和特性UUID,可以获取游戏手柄的摇杆位置和按键状态等信息。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号