极客秀
搜索

什么是BLE低功耗蓝牙?游戏手柄和单片机的连接-用手柄操控设备!

这段时间在玩游戏的时候将我许久未用的游戏手柄拿了出来,玩着玩着突发奇想,能不能用单片机来接收游戏手柄的信息之后操控许多事情,例如利用游戏手柄来控制智能小车等,记得前段时间做的播种小车,利用的是手机APP控制,控制起来总是觉得有所别扭,缺乏感觉。
而且现在基本上都是介绍单片机做成手柄的,很少有介绍一个手柄如何连接上单片机。( ** 视频在文末 ** )
我的游戏手柄支持蓝牙/USB/2.4G连接,当然连接到单片机上那么我觉得最好而且最容易实现的当然是蓝牙,查阅资料得知,游戏手柄基本上是BLE蓝牙即低功耗蓝牙,那么我就先介绍一下什么是低功耗蓝牙。
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设备并且可以对信息处理。代码不多做赘述,到时候贴在文末,只说几个部分。

使用的ESP32库自带的BLE库,设备地址是一开始扫描的,这个相信大家有很多办法获取MAC.


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.");  }};

这段是BLE蓝牙设备连接的回调函数。

设置服务UUID和特性UUID,以及设置好接收到通知的回调函数,之后就可以尝试连接了,我们接收到的数据是20个字节长度的数据,包含了摇杆位置信息,手柄上各个按键的信息,我们只需要将其转码我们所需要的数据,就可以实现手柄的信息的提取。


#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) { // Serial.print("Notify callback for characteristic: "); // Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str()); // Serial.print(" of data length "); // Serial.println(length); // Serial.print("data: ");  //Serial.write(pData, length);  //Serial.println();  Lx = pData[0];  Ly = pData[1];  Serial.print("x:"+String(Lx));  Serial.println(",y:"+String(Ly));}  
1.转载请保留原文链接谢谢!
2.本站所有资源文章出自互联网收集整理,本站不参与制作,如果侵犯了您的合法权益,请联系本站我们会及时删除。
3.本站发布资源来源于互联网,可能存在水印或者引流等信息,请用户擦亮眼睛自行鉴别,做一个有主见和判断力的用户。
4.本站资源仅供研究、学习交流之用,若使用商业用途,请购买正版授权,否则产生的一切后果将由下载用户自行承担。
5.联系方式(#替换成@):pm#vimge.com

  相关内容