2

我正在为平板电脑设计一种基于 Arduino 的扩展坞,使用 USB 端口作为连接器。这意味着我需要支持在平板电脑上的应用程序运行时插入/拔出 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 连接器是否有任何替代方法?

4

2 回答 2

2

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

首先,它需要使用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();
                    }
                }
            }
于 2013-05-24T11:46:45.560 回答
1

所以我相信这是因为你的程序在第一次插入 USB 时缓存了它的地址。

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

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

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

于 2013-05-23T18:12:22.990 回答