拔下USB时,COM端口消失

我正在使用USB端口作为连接器为平板电脑设计一种基于Arduino的扩展坞。 这意味着我需要支持在平板电脑上的应用程序运行时插拔USB连接器的能力。

平板电脑运行ac#应用程序(Win7 64位上的.net 4.5),我将连接到Arduino Uno。 启动应用程序时,我使用以下命令循环所有可用的COM端口:

var ports = SerialPort.GetPortNames(); // -> [COM3,COM4,COM8] foreach (var port in ports) { var serial = new SerialPort(portname, baudRate); //attempt handshake and connect to right port } 

这工作正常,但如果我拔下并重新插入USB电缆并重新尝试重新连接到Arduino(当应用程序仍在运行时),Arduino端口(COM8)不再列在:

 SerialPort.GetPortNames(); // -> [COM3,COM4] and no COM8 

即使重新启动应用程序(使用Arduino重新插入)也会导致仅列出[COM3,COM4]。

让它恢复工作的唯一方法是在应用程序未运行时拔掉并重新插入Arduino。

令我困惑的是,当我在启动应用程序后插入Arduino Uno时,SerialClass会识别新添加的端口并允许我连接。

只有在应用程序运行时拔出并重新插入设备时才会出现此问题。 似乎尽管能够重置COM端口(在代码中或在设备管理器中手动),但SerialClass(以及本机Win32_SerialPort – 我也检查了这一点)无法识别这一点,除非我重新启动应用程序

这可能是什么原因? 如何确保我的应用程序可以重新连接到该端口? 有没有其他方法可以使用SerialPort来处理USB连接器?

我找到了一个可以处理插拔插拔的解决方案。

首先,它需要使用SafeSerialPort ,它允许您正确配置串行端口。

 SafeSerialPort serialPort; private void Connect() { string portname = "COM8"; serialPort = new SafeSerialPort(portname, 9600); serialPort.DataReceived += port_DataReceived; serialPort.Open(); } 

其次,您需要使用LibUsbDotNet来检测USB设备是连接还是断开连接。 这将允许您确定是连接到设备还是重置COM端口。

 public UsbDevice MyUsbDevice; //Find your vendor id etc by listing all available USB devices public UsbDeviceFinder MyUsbFinder = new UsbDeviceFinder(0x2341, 0x0001); public IDeviceNotifier UsbDeviceNotifier = DeviceNotifier.OpenDeviceNotifier(); private void OnDeviceNotifyEvent(object sender, DeviceNotifyEventArgs e) { if (e.Object.ToString().Split('\n')[1].Contains("0x2341")) { if (e.EventType == EventType.DeviceArrival) { Connect(); } else if(e.EventType == EventType.DeviceRemoveComplete) { ResetConnection(); } } } 

最后,处理SerialPort将确保它在Windows中在HKEY_LOCAL_MACHINE \ HARDWARE \ DEVICEMAP \ SERIALCOMM中注册 ,这意味着SerialPort.GetPortNames()可以重新检测端口。

 private void ResetConnection() { try { //Send any data to cause an IOException serialPort.Write("Any value"); } catch (IOException ex) { //Dispose the SafeSerialPort serialPort.Dispose(); serialPort.Close(); } } 

完成此过程后,您可以在连接USB设备时重新连接到COM端口,而无需重新启动应用程序。

完整代码:

 using LibUsbDotNet; using LibUsbDotNet.DeviceNotify; using LibUsbDotNet.Info; using LibUsbDotNet.Main; SafeSerialPort serialPort; public SerialPortTest() { Connect(); UsbDeviceNotifier.OnDeviceNotify += OnDeviceNotifyEvent; } private void Connect() { string portname = "COM8"; serialPort = new SafeSerialPort(portname, 9600); serialPort.DataReceived += port_DataReceived; serialPort.Open(); } private void ResetConnection() { try { serialPort.Write("Any value"); } catch (IOException ex) { serialPort.Dispose(); serialPort.Close(); } } void port_DataReceived(object sender, SerialDataReceivedEventArgs e) { Console.WriteLine(serialPort.ReadExisting()); } public UsbDevice MyUsbDevice; //Vendor ID etc can be found through enumerating the USB devices public UsbDeviceFinder MyUsbFinder = new UsbDeviceFinder(0x2341, 0x0001); public IDeviceNotifier UsbDeviceNotifier = DeviceNotifier.OpenDeviceNotifier(); private void OnDeviceNotifyEvent(object sender, DeviceNotifyEventArgs e) { //if this is your usb device, in my case an Arduino if (e.Object.ToString().Split('\n')[1].Contains("0x2341")) { if (e.EventType == EventType.DeviceArrival) { Connect(); } else { ResetConnection(); } } } 

所以我相信这种情况正在发生,因为你的程序在第一次插入USB时会缓存USB的地址。

当有人插入设备时,集线器会检测D +或D-上的电压,并通过此中断端点向主机发送信号。 当主机轮询此中断端点时,它会获知新设备是否存在。 然后它指示集线器(通过默认控制管道)重置插入新设备的端口。 ***此重置使新设备采用地址0,然后主机可以直接与之交互; 此交互将导致主机为设备分配新的(非零)地址。

最好的办法是研究如何以编程方式刷新USB设备的地址缓存。

参考: http : //en.wikipedia.org/wiki/USB_hub