You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过CoreBluetooth连接指定BLE设备?ESP32+iOS舵机控制需求

CoreBluetooth 连接指定ESP32 BLE设备示例

核心逻辑

要精准连接你的ESP32,优先通过自定义服务UUID(最可靠)、设备名称或设备UUID(单设备固定)过滤扫描结果,避免连接无关设备。以下是完整实现代码。


iOS 端代码实现

1. 基础配置与代理声明

import CoreBluetooth

class BLEController: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {
    private var centralManager: CBCentralManager!
    // 替换为你ESP32上定义的自定义服务UUID
    private let targetServiceUUID = CBUUID(string: "0000FFE0-0000-1000-8000-00805F9B34FB")
    // 可选:ESP32的设备UUID(可从iOS蓝牙设置→该设备→信息中获取)
    private let targetPeripheralUUID = UUID(uuidString: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
    private var connectedPeripheral: CBPeripheral?
}

2. 初始化蓝牙管理器

override init() {
    super.init()
    // 主线程队列处理蓝牙回调
    centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.main)
}

3. 蓝牙状态检查与扫描/连接触发

func centralManagerDidUpdateState(_ central: CBCentralManager) {
    switch central.state {
    case .poweredOn:
        // 方案1:直接通过设备UUID连接(适用于已配对过的设备)
        if let uuid = targetPeripheralUUID {
            if let peripheral = central.retrievePeripherals(withIdentifiers: [uuid]).first {
                central.connect(peripheral, options: nil)
                return
            }
        }
        // 方案2:按服务UUID扫描(只返回包含目标服务的设备,效率更高)
        central.scanForPeripherals(withServices: [targetServiceUUID], options: [
            CBCentralManagerScanOptionAllowDuplicatesKey: false
        ])
    case .poweredOff:
        print("蓝牙已关闭")
    default:
        print("蓝牙不可用")
    }
}

4. 扫描结果过滤与连接

func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
    // 双重过滤:设备名称 + 服务UUID,确保精准匹配
    let targetDeviceName = "ESP32_SERVO_CTRL" // 替换为你的ESP32设备名称
    if peripheral.name == targetDeviceName || peripheral.services?.contains(where: { $0.uuid == targetServiceUUID }) == true {
        central.stopScan()
        connectedPeripheral = peripheral
        peripheral.delegate = self
        central.connect(peripheral, options: nil)
    }
}

5. 连接成功后发现服务与特征

// 连接成功回调
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
    print("已连接到ESP32:\(peripheral.name ?? "未知设备")")
    // 发现目标服务
    peripheral.discoverServices([targetServiceUUID])
}

// 发现服务后查找舵机控制特征
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
    guard let services = peripheral.services, error == nil else {
        print("发现服务失败:\(error?.localizedDescription ?? "未知错误")")
        return
    }
    for service in services where service.uuid == targetServiceUUID {
        // 替换为你定义的舵机控制特征UUID
        let servoCharUUID = CBUUID(string: "0000FFE1-0000-1000-8000-00805F9B34FB")
        peripheral.discoverCharacteristics([servoCharUUID], for: service)
    }
}

// 发现特征后即可读写数据控制舵机
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
    guard let characteristics = service.characteristics, error == nil else { return }
    for char in characteristics where char.uuid == CBUUID(string: "0000FFE1-0000-1000-8000-00805F9B34FB") {
        // 示例:发送舵机控制指令,比如"1:90"表示舵机1转到90度
        let cmd = "1:90".data(using: .utf8)!
        peripheral.writeValue(cmd, for: char, type: .withResponse)
    }
}

ESP32 端配套代码(Arduino)

确保ESP32的BLE服务、特征UUID与iOS端完全匹配:

#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <Servo.h>

// 与iOS端一致的UUID
#define SERVICE_UUID        "0000FFE0-0000-1000-8000-00805F9B34FB"
#define CHARACTERISTIC_UUID "0000FFE1-0000-1000-8000-00805F9B34FB"

Servo servo1;
Servo servo2;
BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;

class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string value = pCharacteristic->getValue();
      if (value.length() > 0) {
        // 解析指令格式:"舵机编号:角度"
        int servoNum = value[0] - '0';
        int angle = atoi(value.substr(2).c_str());
        switch(servoNum) {
          case 1: servo1.write(angle); break;
          case 2: servo2.write(angle); break;
        }
      }
    }
};

void setup() {
  servo1.attach(2); // 舵机1接GPIO2
  servo2.attach(4); // 舵机2接GPIO4
  
  BLEDevice::init("ESP32_SERVO_CTRL"); // 与iOS端一致的设备名称
  pServer = BLEDevice::createServer();
  BLEService *pService = pServer->createService(SERVICE_UUID);
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID,
                      BLECharacteristic::PROPERTY_WRITE |
                      BLECharacteristic::PROPERTY_READ
                    );
  pCharacteristic->setCallbacks(new MyCallbacks());
  pService->start();
  // 广播服务UUID,让iOS能快速识别
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->start();
}

void loop() {
  delay(100);
}

关键注意事项

  • 权限配置:在iOS项目的Info.plist中添加NSBluetoothAlwaysUsageDescription和NSBluetoothPeripheralUsageDescription,填写权限申请说明。
  • 设备UUID特性:同一BLE设备在同一iOS设备上的UUID固定,但跨iOS设备会不同,因此优先用服务UUID或设备名称做跨设备兼容。
  • 错误处理:需实现didFailToConnectPeripheral、didDisconnectPeripheral等代理方法处理连接失败、断开重连场景。

内容的提问来源于stack exchange,提问作者MWD_NAME

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 10:57:02