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

Windows下用C语言识别Standard Serial over Bluetooth Link的Outgoing COM端口

用C语言实现蓝牙串口识别与数据读取(Windows平台)

核心思路

可以用C语言结合Windows API实现需求:通过SetupAPI枚举系统串口设备,筛选出描述为Standard Serial over Bluetooth Link的设备,再读取注册表信息区分Outgoing端口,最后用Win32串口API打开端口并读取数据。

步骤拆解与关键实现

1. 枚举并筛选蓝牙串口设备

Windows将蓝牙串口归类到Ports (COM & LPT)设备类,需借助以下API遍历设备:

  • SetupDiGetClassDevs:获取指定设备类的所有已连接设备列表
  • SetupDiEnumDeviceInfo:遍历设备列表中的每个设备
  • SetupDiGetDeviceRegistryProperty:读取设备的描述信息,匹配Standard Serial over Bluetooth Link

2. 识别Outgoing端口

蓝牙串口的方向信息存储在设备注册表的Device Parameters子键下,通过RegQueryValueEx读取Direction值,筛选出值为Outgoing的端口,同时读取PortName获取COM端口号。

3. 打开串口并读取数据

用CreateFile打开目标COM端口,通过DCB结构体配置串口参数(匹配HC-05默认的9600波特率、8位数据位、无校验、1位停止位),最后用ReadFile循环读取数据。

完整代码示例

#include <windows.h>
#include <setupapi.h>
#include <initguid.h>
#include <devguid.h>
#include <stdio.h>

#define BLUETOOTH_SERIAL_DESC "Standard Serial over Bluetooth Link"
#define OUTGOING_DIRECTION "Outgoing"

// 查找目标蓝牙Outgoing串口
BOOL FindBluetoothOutgoingPort(char* outPortName, DWORD maxLen) {
    HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, NULL, NULL, DIGCF_PRESENT);
    if (hDevInfo == INVALID_HANDLE_VALUE) {
        printf("SetupDiGetClassDevs failed: %lu\n", GetLastError());
        return FALSE;
    }

    SP_DEVINFO_DATA devInfoData = {0};
    devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

    for (DWORD i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &devInfoData); i++) {
        // 读取设备描述
        TCHAR desc[256] = {0};
        if (!SetupDiGetDeviceRegistryProperty(hDevInfo, &devInfoData, SPDRP_DEVICEDESC, NULL, (PBYTE)desc, sizeof(desc), NULL)) {
            continue;
        }

        // 匹配蓝牙串口描述
        if (_tcscmp(desc, TEXT(BLUETOOTH_SERIAL_DESC)) != 0) {
            continue;
        }

        // 打开设备注册表项
        HKEY hDeviceKey = SetupDiOpenDevRegKey(hDevInfo, &devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
        if (hDeviceKey == INVALID_HANDLE_VALUE) {
            continue;
        }

        // 读取端口方向
        TCHAR direction[32] = {0};
        DWORD dataSize = sizeof(direction);
        if (RegQueryValueEx(hDeviceKey, TEXT("Direction"), NULL, NULL, (LPBYTE)direction, &dataSize) == ERROR_SUCCESS) {
            if (_tcscmp(direction, TEXT(OUTGOING_DIRECTION)) == 0) {
                // 读取端口名称
                TCHAR portName[32] = {0};
                dataSize = sizeof(portName);
                if (RegQueryValueEx(hDeviceKey, TEXT("PortName"), NULL, NULL, (LPBYTE)portName, &dataSize) == ERROR_SUCCESS) {
                    _tcscpy_s((TCHAR*)outPortName, maxLen, portName);
                    RegCloseKey(hDeviceKey);
                    SetupDiDestroyDeviceInfoList(hDevInfo);
                    return TRUE;
                }
            }
        }
        RegCloseKey(hDeviceKey);
    }

    SetupDiDestroyDeviceInfoList(hDevInfo);
    return FALSE;
}

// 打开串口并读取数据
BOOL ReadSerialPort(const char* portName) {
    HANDLE hSerial = CreateFile(portName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hSerial == INVALID_HANDLE_VALUE) {
        printf("CreateFile failed: %lu\n", GetLastError());
        return FALSE;
    }

    // 配置串口参数(匹配HC-05默认设置)
    DCB dcbSerialParams = {0};
    dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
    if (!GetCommState(hSerial, &dcbSerialParams)) {
        printf("GetCommState failed: %lu\n", GetLastError());
        CloseHandle(hSerial);
        return FALSE;
    }
    dcbSerialParams.BaudRate = CBR_9600;
    dcbSerialParams.ByteSize = 8;
    dcbSerialParams.StopBits = ONESTOPBIT;
    dcbSerialParams.Parity = NOPARITY;
    if (!SetCommState(hSerial, &dcbSerialParams)) {
        printf("SetCommState failed: %lu\n", GetLastError());
        CloseHandle(hSerial);
        return FALSE;
    }

    // 设置读取超时
    COMMTIMEOUTS timeouts = {0};
    timeouts.ReadIntervalTimeout = 50;
    timeouts.ReadTotalTimeoutConstant = 50;
    timeouts.ReadTotalTimeoutMultiplier = 10;
    if (!SetCommTimeouts(hSerial, &timeouts)) {
        printf("SetCommTimeouts failed: %lu\n", GetLastError());
        CloseHandle(hSerial);
        return FALSE;
    }

    // 循环读取数据
    char buffer[256] = {0};
    DWORD bytesRead = 0;
    printf("Reading data from %s...\n", portName);
    while (TRUE) {
        if (ReadFile(hSerial, buffer, sizeof(buffer)-1, &bytesRead, NULL)) {
            if (bytesRead > 0) {
                buffer[bytesRead] = '\0';
                printf("Received: %s", buffer);
            }
        } else {
            printf("ReadFile failed: %lu\n", GetLastError());
            break;
        }
    }

    CloseHandle(hSerial);
    return TRUE;
}

int main() {
    char portName[32] = {0};
    if (FindBluetoothOutgoingPort(portName, sizeof(portName))) {
        printf("Found Bluetooth Outgoing Port: %s\n", portName);
        ReadSerialPort(portName);
    } else {
        printf("No Bluetooth Outgoing Port found.\n");
    }
    return 0;
}

编译与运行说明

  • 使用MSVC编译器编译时,需链接setupapi.lib库:
    cl bluetooth_serial.c setupapi.lib
    
  • 程序需以管理员权限运行,否则可能无法读取设备注册表信息
  • 确保HC-05已与电脑配对并建立串口连接

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 08:45:08