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

Windows 10 BLE数据传输速率过低,如何提升传输性能?

Windows 10 BLE应用传输速率优化方案

问题背景

我在运行Windows 10的BLE示例应用,连接外设并发送数据。该外设通过Android应用可达到数KB/秒的传输速率,但Windows应用仅能达到约130B/秒。尝试以高速率发送70字节的数据包,期望传输速率至少达到10KB/秒(BLE 4.2理论性能为1Mbps),但未达到预期。目前未找到通过Windows.Devices.Bluetooth库调整BLE传输速率的配置方式,求提升速率的方法。

相关代码

public async void BLE_ConnectionAsync(string ble_name)
{
    bool bleCharacteristicsConnect = false;
    try
    {
        if(!bleCharacteristicsConnect)
        {
            if (ble_name != null)
            {
                nameBle = ble_name;
                string[] requestedProperties = { "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.IsConnected" };
                deviceWatcher = DeviceInformation.CreateWatcher(
                    BluetoothLEDevice.GetDeviceSelectorFromPairingState(false),
                requestedProperties,
                    DeviceInformationKind.AssociationEndpoint);
                deviceWatcher.Added += DevicedWatcher_Added;
                deviceWatcher.Updated += DevicedWatcher_Updated;
                deviceWatcher.Removed += DevicedWatcher_Removed;
                deviceWatcher.EnumerationCompleted += DevicedWatcher_EnumerationCompleted;
                deviceWatcher.Stopped += DevicedWatcher_Stopped;
                deviceWatcher.Start();

                while (true)
                {
                    if (device == null)
                    {
                        Thread.Sleep(200);
                    }
                    else
                    {
                        bluetoothLEDevice = await BluetoothLEDevice.FromIdAsync(device.Id);

                        result = await bluetoothLEDevice.GetGattServicesAsync();

                        if (result.Status == GattCommunicationStatus.Success)
                        {
                            var services = result.Services;

                            bool shouldExit = false;
                            foreach (var service in services)
                            {
                                string test = service.Uuid.ToString("N");
                                
                                string test2 = service.Uuid.ToString("N").Substring(4, 4);
                                Console.WriteLine("Service id: " + test2);
                                if (service.Uuid.ToString("N").Substring(4, 4) == "fe40" || service.Uuid.ToString("N").Substring(4, 4) == HEART_RATE_SERVICE_ID)

                                {

                                    GattCharacteristicsResult characteristicsResult = await service.GetCharacteristicsAsync();

                                    if (characteristicsResult.Status == GattCommunicationStatus.Success)
                                    {
                                        var characteristics = characteristicsResult.Characteristics;
                                        foreach (var characteristic in characteristics)
                                        {
                                            GattCharacteristicProperties properties = characteristic.CharacteristicProperties;

                                            try
                                            {

                                                GattCommunicationStatus status = await characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);

                                                if (status == GattCommunicationStatus.Success)
                                                {
                                                    characteristic.ValueChanged += Characteristic_ValueChanged;
                                                    selectedCharacteristic = characteristic;
                                                    Console.WriteLine("Read char "+characteristic.Uuid.ToString("N"));
                                                }
                                                else
                                                {

                                                }
                                            }
                                            catch (Exception ex)
                                            {
                                                bleCharacteristicsConnect = true;
                                                writeChar = characteristic;
                                                Console.WriteLine("Write char " + characteristic.Uuid.ToString("N"));
                                                OpenComPort(ble_name);
                                                shouldExit = true;
                                                break;
                                            }

                                        }

                                        if (shouldExit)
                                        {
                                            break;
                                        }
                                    }
                                }
                            }

                            break;

                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }
        }
      
    }
    catch (Exception ex)
    {
        log.Error(ex.Message);

    }
  
}



private async void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
    try
    {
        SerialPort sp = (SerialPort)sender;

        byte[] data = new byte[sp.BytesToRead];
        if(data.Length> MAX_PAYLOAD_SIZE)
        {
            sp.Read(data, 0, data.Length);

            byte[] _data = new byte[MAX_PAYLOAD_SIZE];
            
            int countPackets = (data.Length) / MAX_PAYLOAD_SIZE;
            int remainder = (data.Length) % MAX_PAYLOAD_SIZE;
            log.Info(" [COM --> BLE] \t Data Length = " + data.Length + " Data = " + ByteArrayToString(data));
            
            int i = 0;
            for (i = 0; i < countPackets; i++)
            {
                await writeChar.WriteValueAsync(data.AsBuffer(i * MAX_PAYLOAD_SIZE, MAX_PAYLOAD_SIZE));
            }
            if (remainder > 0)
            {
                await writeChar.WriteValueAsync(data.AsBuffer(i * MAX_PAYLOAD_SIZE, remainder)); 
            }


        }
       else
        {
            sp.Read(data, 0, data.Length);
            await writeChar.WriteValueAsync(data.AsBuffer());
        }

    }
    catch (Exception ex)
    {

        log.Error(ex.Message);
    }


}

优化方案

1. 启用BLE数据长度扩展(DLE)

BLE 4.2支持最大251字节的数据包,Windows默认可能未开启该功能,可通过注册表修改启用:

  • 打开注册表编辑器,定位到HKLM\SYSTEM\CurrentControlSet\Services\BTHPORT\Parameters
  • 添加DWORD值EnableDataLengthExtension,设置为1
  • 重启蓝牙服务或系统生效

2. 批量异步发送数据包

当前代码逐个等待单包写入完成,引入大量延迟。改用批量异步发送,充分利用BLE传输窗口:

// 替换DataReceivedHandler中的循环代码
var tasks = new List<Task>();
for (i = 0; i < countPackets; i++)
{
    tasks.Add(writeChar.WriteValueAsync(data.AsBuffer(i * MAX_PAYLOAD_SIZE, MAX_PAYLOAD_SIZE)).AsTask());
}
if (remainder > 0)
{
    tasks.Add(writeChar.WriteValueAsync(data.AsBuffer(i * MAX_PAYLOAD_SIZE, remainder)).AsTask());
}
await Task.WhenAll(tasks);

注意:需确认外设支持多包缓存,避免丢包。

3. 使用无响应写入模式

带响应的写入需要等待外设ACK,速率受限。确认特征支持WriteWithoutResponse后,改用无响应写入:

// 在特征选择时检查属性
if ((characteristic.CharacteristicProperties & GattCharacteristicProperties.WriteWithoutResponse) != 0)
{
    writeChar = characteristic;
    // 写入时指定无响应选项
    await writeChar.WriteValueAsync(buffer, GattWriteOption.WriteWithoutResponse);
}

无响应写入速率更高,但需自行处理可能的丢包场景。

4. 调整BLE连接参数

Windows默认连接间隔偏保守,可请求更优的参数提升传输效率:

// 在连接成功后添加参数调整逻辑
var currentParams = await bluetoothLEDevice.GetConnectionParametersAsync();
var desiredParams = new BluetoothLEConnectionParameters
{
    MinConnectionInterval = TimeSpan.FromMilliseconds(7.5), // BLE 4.2最小支持7.5ms间隔
    MaxConnectionInterval = TimeSpan.FromMilliseconds(15),
    SlaveLatency = 0,
    SupervisionTimeout = TimeSpan.FromMilliseconds(2000)
};
var result = await bluetoothLEDevice.RequestConnectionParametersAsync(desiredParams);

注意:外设需支持对应参数范围,否则请求可能被拒绝。

5. 替换阻塞式等待

原代码中Thread.Sleep(200)阻塞主线程,改用异步延迟避免影响调度:

// 替换BLE_ConnectionAsync中的循环等待
while (device == null)
{
    await Task.Delay(200);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 04:37:07