使用 CSerial (C++) 打开虚拟 COM 端口

Posted

技术标签:

【中文标题】使用 CSerial (C++) 打开虚拟 COM 端口【英文标题】:Opening a virtual COM port with CSerial (C++) 【发布时间】:2012-07-27 23:29:42 【问题描述】:

我正在使用Ramon de Klein's CSerial library 从我的 C++ 代码中打开和管理串行端口。

我的硬件实现了一个带有 FTDI 芯片的串行 tu USB 转换器,因此我可以将串行端口连接到我 CPU 中的 USB 插头。安装 FTDI 驱动程序后,“设备管理器”(Windows) 中会显示一个虚拟 COM 端口。

如果我尝试打开它,它会起作用。

但现在我已经安装了一个 USB 到以太网服务器,例如 this one。所以我安装了它的驱动程序和软件,在将一些 USB 设备连接到它后,它被检测到并作为虚拟串口添加到“设备管理器”窗口。

但是当我尝试打开端口时,它不起作用。 如果我用类似超级终端的应用程序打开端口,它确实可以工作,就像它是一个普通的串行端口一样,但在我的代码中没有。

CSerial 库就像在创建一个新文件一样工作,并且给定 LastErrorCode 为 2:“找不到文件”。这是 CSerial 库中的 Open 方法:

LONG CSerial::Open (LPCTSTR lpszDevice, DWORD dwInQueue, DWORD dwOutQueue, bool fOverlapped)

    // Reset error state
    m_lLastError = ERROR_SUCCESS;

    // Check if the port isn't already opened
    if (m_hFile)
    
        m_lLastError = ERROR_ALREADY_INITIALIZED;
        _RPTF0(_CRT_WARN,"CSerial::Open - Port already opened\n");
        return m_lLastError;
    

    // Open the device
    m_hFile = ::CreateFile(lpszDevice,
                           GENERIC_READ|GENERIC_WRITE,
                           0,
                           0,
                           OPEN_EXISTING,
                           fOverlapped?FILE_FLAG_OVERLAPPED:0,
                           0);
    if (m_hFile == INVALID_HANDLE_VALUE)
    
        // Reset file handle
        m_hFile = 0;

        // Display error
        m_lLastError = ::GetLastError();
        _RPTF0(_CRT_WARN, "CSerial::Open - Unable to open port\n");
        return m_lLastError;
    

#ifndef SERIAL_NO_OVERLAPPED
    // We cannot have an event handle yet
    _ASSERTE(m_hevtOverlapped == 0);

    // Create the event handle for internal overlapped operations (manual reset)
    if (fOverlapped)
    
        m_hevtOverlapped = ::CreateEvent(0,true,false,0);
        if (m_hevtOverlapped == 0)
        
            // Obtain the error information
            m_lLastError = ::GetLastError();
            _RPTF0(_CRT_WARN,"CSerial::Open - Unable to create event\n");

            // Close the port
            ::CloseHandle(m_hFile);
            m_hFile = 0;

            // Return the error
            return m_lLastError;
        
    
#else

    // Overlapped flag shouldn't be specified
    _ASSERTE(!fOverlapped);

#endif

    // Setup the COM-port
    if (dwInQueue || dwOutQueue)
    
        // Make sure the queue-sizes are reasonable sized. Win9X systems crash
        // if the input queue-size is zero. Both queues need to be at least
        // 16 bytes large.
        _ASSERTE(dwInQueue >= 16);
        _ASSERTE(dwOutQueue >= 16);

        if (!::SetupComm(m_hFile,dwInQueue,dwOutQueue))
        
            // Display a warning
            long lLastError = ::GetLastError();
            _RPTF0(_CRT_WARN,"CSerial::Open - Unable to setup the COM-port\n");

            // Close the port
            Close();

            // Save last error from SetupComm
            m_lLastError = lLastError;
            return m_lLastError;    
        
    

    // Setup the default communication mask
    SetMask();

    // Non-blocking reads is default
    SetupReadTimeouts(EReadTimeoutNonblocking);

    // Setup the device for default settings
    COMMCONFIG commConfig = 0;
    DWORD dwSize = sizeof(commConfig);
    commConfig.dwSize = dwSize;
    if (::GetDefaultCommConfig(lpszDevice,&commConfig,&dwSize))
    
        // Set the default communication configuration
        if (!::SetCommConfig(m_hFile,&commConfig,dwSize))
        
            // Display a warning
            _RPTF0(_CRT_WARN,"CSerial::Open - Unable to set default communication configuration.\n");
        
    
    else
    
        // Display a warning
        _RPTF0(_CRT_WARN,"CSerial::Open - Unable to obtain default communication configuration.\n");
    

    // Return successful
    return m_lLastError;

我不明白为什么它的工作方式与将 USB 直接插入计算机的方式不同:我一直认为如果 COM 列在“设备管理器”中,它应该可以工作,与它的位置无关真的有联系。

总的来说,数据的来源是:

RS232--->转换为USB--->USB CPU接口--->在COM口中虚拟化为RS232

现在是:

RS232--->转换为USB--->通过“netUSB服务器”转换为以太网--->CPU上的以太网/WiFi--->虚拟化为USB设备--->在 COM 端口中虚拟化为 RS232

有什么帮助吗?

【问题讨论】:

您的 CPU 上有 USB 连接器吗? 当然,我的 CPU 上有一个带 RS232 输出、RS232 到 USB 转换器和 USB 连接器的硬件。这样它就起作用了。如果我添加一个“USB网络服务器”,数据传输的方式是RS323-->USB--->以太网-->虚拟化为USB--->虚拟化为RS232到COM端口 @Roman Rdgz:实际上你所说的所有连接都连接到southbridge,它连接到northbridge,然后连接到CPU。 USB、RS232 和以太网不直接连接到 CPU。 @Insilico 这只是一种解释方式。重要的是,我有一个虚拟 COM 端口,一旦将 netUSB 添加到网络,它就不再从我的代码中打开,但它确实从超级终端打开 【参考方案1】:

问题的出现不是因为硬件元素,而是因为分配给 COM 端口的编号。

COM口大于9时,CreateFile函数打开设备失败,返回INVALID_HANDLE_VALUE。

Bug报,解决方法报here。

【讨论】:

以上是关于使用 CSerial (C++) 打开虚拟 COM 端口的主要内容,如果未能解决你的问题,请参考以下文章

在linux中创建使用opencv的C++动态库

在 C++ 中打开一个大于 9 的 COM 端口

在使用 C++ 进行虚拟继承期间调用构造函数

Unbuntu22.04安装教程以及Unbuntu下C++环境的配置

如何在 Linux 上创建虚拟 CAN 端口? (C++)

无法获取 Windows 7 C++ 上虚拟文件夹的路径(shell 命名空间扩展相关)