使用 usbser.sys 冻结 SerialPort.Open / DeviceIoControl / GetcommState

Posted

技术标签:

【中文标题】使用 usbser.sys 冻结 SerialPort.Open / DeviceIoControl / GetcommState【英文标题】:Freeze on SerialPort.Open / DeviceIoControl / GetcommState with usbser.sys 【发布时间】:2011-07-19 15:23:30 【问题描述】:

我有一个 C 程序,它打开一个 COM 端口的句柄,向它写入一些字节,读出一些字节,然后关闭句柄并退出。但是,当我连续运行该程序 10 次时,开始需要很长时间才能完成 GetCommState 函数并卡在 SetCommState 函数中。同样的事情发生在 C# 中,带有一个简单的 SerialPort 对象。

我能找到的唯一解决方法是将设备重新连接到端口。有没有更优雅的方法来摆脱这种冻结?可能只是一些 PC 配置错误?

更新

我已经重写了代码,使它使用DeviceIoControl 而不是SetCommState。但是,这里的问题完全相同。

device = 
    CreateFileW(
        L"\\\\.\\COM3", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 
        FILE_FLAG_OVERLAPPED, NULL);

static int SetBaudRate (HANDLE device) 
    int error = 0;
    int success = 0;
    OVERLAPPED overlapped = 0;
    overlapped.hEvent = CreateEvent(NULL, TRUE, 0, NULL);
    if (overlapped.hEvent) 
        SERIAL_BAUD_RATE baudRate = 0;
        baudRate.BaudRate = SERIAL_BAUD_115200;
        error = 
            DeviceIoControl(
                device, IOCTL_SERIAL_SET_BAUD_RATE, &baudRate, 
                sizeof(SERIAL_BAUD_RATE), NULL, 0, NULL, &overlapped);
        if (error || (!error && GetLastError() == ERROR_IO_PENDING)) 
            DWORD bytes = 0;
            if (GetOverlappedResult(device, &overlapped, &bytes, TRUE)) 
                success = 1;
            
        
    
    CloseHandle(overlapped.hEvent);
    return success;

第一个问题:DeviceIoControl 不会立即返回(虽然是异步调用的)并且会挂起大约两分钟。 第二个问题:两分钟后它失败,错误代码为 121(ERR_SEM_TIMEOUT:“信号量超时期限已过期。”)。

使用的驱动是标准的windows驱动usbser.sys 知道为什么函数调用没有立即返回吗?如果没有,如何为函数设置更短的超时时间? 知道函数失败的原因吗?

更新 2

也会冻结的示例 C# 代码(如上面的 C 程序):

using System;
using System.IO.Ports;

sealed class Program 
    static void Main (string[] args) 
        int i = 0;
        while (true) 
            Console.WriteLine(++i);
            SerialPort p = 
                new SerialPort("com3", 115200, Parity.None, 8, StopBits.One);
            p.DtrEnable = true;
            p.RtsEnable = true;
            p.ParityReplace = 0;
            p.WriteTimeout = 10000;
            p.ReadTimeout = 3000;
            try 
                p.Open();
                Console.WriteLine("Success!");
             catch (Exception e) 
                Console.WriteLine(e.GetType().Name + ": " + e.Message);
            
            p.Close();
            Console.ReadLine();
        
    

示例输出如下:

1 (device not yet connected)
IOException: The port 'com3' does not exist.

2 (device connected but not yet in windows device manager)
IOException: The port 'com3' does not exist.

3
IOException: The port 'com3' does not exist.

4 (device connected and recognized)
Success!

5
Success!

[...] (with about one second between each enter press)

15
Success!

16 (device still connected and recognized - nothing touched! after two minutes of freeze, semaphore timeout exactly as in the C version)
IOException: The semaphore timeout period has expired.


17 (device disconnected during the two minutes of freeze. it then returns instantly)
IOException: A device attached to the system is not functioning.


18 (device still disconnected - note that the exception is a different one than the one in the beginning although it's the same case: device not connected)
IOException: The specified port does not exist.

19
IOException: The port 'com3' does not exist.

【问题讨论】:

当您说“冻结系统”时,“系统”只是您的程序还是整个计算机? 只是程序。当我使用调试器单步执行代码时,GetCommState 会在 1 分钟后返回,而 SetCommState 需要更长的时间,直到由于超时而失败。 这是内置串口、虚拟口、USB串口还是别的什么? 选项是“内置”“USB”。什么是“内置 USB”COM 端口? 那么,等等,你的电脑主板上有一个USB转串口转换器吗?什么? 【参考方案1】:

这是我的用于处理串行端口通信的 c++ 类的工作部分,稍作更改以适应 C 和您的需求。如果它不起作用,则可能是您的虚拟端口驱动程序有问题

 DCB SerialPortSettings;
 HANDLE SerialPort;

int OpenPort(WCHAR* PortName,int BaudRate)


    SerialPort = CreateFileW(PortName,
        GENERIC_READ|GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_FLAG_OVERLAPPED,
        NULL);

    if(SerialPort==INVALID_HANDLE_VALUE)
        return -2;

    RtlZeroMemory(&SerialPortSettings,sizeof(DCB));
    SerialPortSettings.DCBlength = sizeof(DCB);
    if(!GetCommState(SerialPort,&SerialPortSettings))
    
        CloseHandle(SerialPort);
        return -3;
    

    //8n1 RS485
    SerialPortSettings.BaudRate = BaudRate;
    SerialPortSettings.ByteSize = 8;
    SerialPortSettings.Parity = NOPARITY;
    SerialPortSettings.StopBits = ONESTOPBIT;
    SerialPortSettings.fRtsControl = RTS_CONTROL_TOGGLE;

    if(!SetCommState(SerialPort,&SerialPortSettings))
    
        CloseHandle(SerialPort);
        return -4;
    


    return 0;


编辑:尝试从http://www.ftdichip.com/Drivers/VCP.htm 下载驱动程序,因为您描述的问题很可能是驱动程序或设备问题。为 Etan 工作:)

【讨论】:

我使用 Windows 附带的标准驱动程序将 USB 设备连接到虚拟 com 端口。问题不在于它根本不工作,而只是有时——例如在多次打开和关闭串行端口时。我还将在问题中添加一个简单的 c# 示例,它会产生错误。 尝试从ftdichip.com/Drivers/VCP.htm 下载驱动程序,因为您描述的问题很可能是驱动程序或设备问题 你能转发这个作为答案吗?问题源于设备的固件错误。升级解决了冻结问题。

以上是关于使用 usbser.sys 冻结 SerialPort.Open / DeviceIoControl / GetcommState的主要内容,如果未能解决你的问题,请参考以下文章

arduino驱动安装失败求助

mtk怎么安装刷机驱动

arduino连接电脑后设备管理器没有显示?

签名的 INF 驱动程序在它被签名的计算机上工作,而不是在其他计算机上工作

精简版GHOST版win7,arduino驱动安装失败的解决方法分享

在Excel中冻结窗格有哪些使用方法?同时冻结行列数据不再是难题!