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

Visual Studio C++串口通信报错及自动识别串口需求

问题解决:VS C++串口通信编译错误与自动识别实现

一、编译错误(C2665、E0289)解决

错误核心原因

项目字符集设置与函数参数类型不匹配:

  • Windows API的CreateFile在Unicode字符集下对应CreateFileW,要求传入LPCWSTR(宽字符指针);在多字节字符集下对应CreateFileA,要求传入LPCSTR(窄字符指针)。
  • 你传入的L"//./com3"是宽字符常量,若项目字符集设置为多字节字符集,会直接触发类型不匹配的编译错误。

解决方案

方案1:切换到Unicode字符集(推荐)

  1. 右键项目 → 属性 → 配置属性 → 常规 → 字符集
  2. 选择「使用 Unicode 字符集」,点击确定后重新编译。

方案2:适配多字节字符集

若必须使用多字节字符集,修改代码如下:

  • 将SerialPort类中的LPCWSTR COMport改为LPCSTR COMport
  • 构造函数、Connect函数的参数LPCWSTR COM改为LPCSTR COM
  • 调用构造函数时传入"//./com3"(去掉L前缀)

额外代码问题修复

除字符集问题外,代码还有几处逻辑错误需修正:

  1. 字符串长度计算错误
    sendCommand中dNoOFBytestoWrite = sizeof(commandBuffer);会获取指针的大小(4/8字节),而非实际命令字符串长度,改为:

    this->dNoOFBytestoWrite = strlen(commandBuffer) + 1; // +1包含字符串终止符
    
  2. 串口参数未生效
    当前代码仅定义了DCB和COMMTIMEOUTS结构体,但未将参数设置到串口,需在Connect函数的成功分支中添加:

    else {
        cout << "Opening serial port successful" << endl;
        // 设置串口参数
        DCB dcbSerialParams = { 0 };
        dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
        if (!GetCommState(hComm, &dcbSerialParams)) {
            cout << "Failed to get comm state" << endl;
        }
        dcbSerialParams.BaudRate = setBaudRate;
        dcbSerialParams.ByteSize = setByteSize;
        dcbSerialParams.StopBits = ONESTOPBIT;
        dcbSerialParams.Parity = NOPARITY;
        if (!SetCommState(hComm, &dcbSerialParams)) {
            cout << "Failed to set comm state" << endl;
        }
    
        // 设置超时
        COMMTIMEOUTS timeouts = { 0 };
        timeouts.ReadIntervalTimeout = 10;
        timeouts.ReadTotalTimeoutConstant = 10;
        timeouts.ReadTotalTimeoutMultiplier = 10;
        timeouts.WriteTotalTimeoutConstant = 50;
        timeouts.WriteTotalTimeoutMultiplier = 10;
        if (!SetCommTimeouts(hComm, &timeouts)) {
            cout << "Failed to set comm timeouts" << endl;
        }
        sendCommand(setBaudRate, setByteSize, commandBuffer);
    }
    

    同时删除sendCommand中重复的DCB和超时定义代码。

  3. 缓冲区初始化与冗余代码

    • 在SerialPort构造函数中添加memset(this->SerialBuffer, 0, BufSize);初始化缓冲区,避免输出乱码。
    • getData中ReadFile的第二个参数改为this->SerialBuffer,&*属于冗余操作。

二、串口自动识别实现

通过Windows设备枚举API获取所有可用串口,再尝试连接验证是否为目标设备:

1. 配置依赖

在SerialPort.h或调用文件中添加头文件:

#include <vector>
#include <string>
#include <setupapi.h>
#include <devguid.h>

同时在项目属性 → 链接器 → 输入 → 附加依赖项中添加setupapi.lib。

2. 编写串口枚举函数

std::vector<std::string> getAvailableSerialPorts() {
    std::vector<std::string> ports;
    // 获取当前存在的所有串口设备接口
    HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    if (hDevInfo == INVALID_HANDLE_VALUE) {
        return ports;
    }

    SP_DEVICE_INTERFACE_DATA deviceInterfaceData = { 0 };
    deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

    for (DWORD i = 0; SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_COMPORT, i, &deviceInterfaceData); i++) {
        DWORD requiredSize = 0;
        // 先获取所需缓冲区大小
        SetupDiGetDeviceInterfaceDetail(hDevInfo, &deviceInterfaceData, NULL, 0, &requiredSize, NULL);
        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
            continue;
        }

        // 分配缓冲区获取设备详情
        PSP_DEVICE_INTERFACE_DETAIL_DATA pDetailData = reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(malloc(requiredSize));
        pDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
        SP_DEVINFO_DATA devInfoData = { 0 };
        devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

        if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &deviceInterfaceData, pDetailData, requiredSize, NULL, &devInfoData)) {
            // DevicePath格式为"\\\\.\\COMx",可直接用于CreateFile
            ports.emplace_back(pDetailData->DevicePath);
        }
        free(pDetailData);
    }

    SetupDiDestroyDeviceInfoList(hDevInfo);
    return ports;
}

3. 自动识别并连接目标串口

遍历枚举到的串口,通过发送命令、读取响应验证是否为目标设备:

int main() {
    std::vector<std::string> ports = getAvailableSerialPorts();
    SerialPort* targetPort = nullptr;

    for (const auto& port : ports) {
        // 转换为宽字符适配Unicode字符集
        std::wstring wPort(port.begin(), port.end());
        SerialPort tempPort(wPort.c_str(), CBR_115200, 8, "#or", 24);
        
        // 验证目标设备:示例为检查是否包含预期响应
        tempPort.getData();
        if (strstr(tempPort.SerialBuffer, "expected_response") != nullptr) {
            targetPort = new SerialPort(wPort.c_str(), CBR_115200, 8, "#or", 24);
            break;
        }
    }

    if (targetPort != nullptr) {
        cout << "Connected to target port successfully" << endl;
        targetPort->getData();
        cout << targetPort->SerialBuffer << endl;
        delete targetPort;
    } else {
        cout << "Target serial port not found" << endl;
    }

    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 22:00:56