2010-07-20 214 views
17

我使用一个Arduino与Firmata库通讯C#应用程序,和我想要消除的COM端口配置组件,因为它可以从机改为机...如何自动检测Arduino COM端口?

是否有可能:

  1. 枚举系统中的COM端口列表? (在我的谷歌搜索中,我已经看到一些相当丑陋的Win32 API代码,希望现在可能有更清洁的版本)
  2. 自动检测哪个COM端口连接到Arduino?

回答

14

这个代码一点已经表现非常出色,这(返回COM口弦,即“COM12”如果检测到的Arduino):

private string AutodetectArduinoPort() 
     { 
      ManagementScope connectionScope = new ManagementScope(); 
      SelectQuery serialQuery = new SelectQuery("SELECT * FROM Win32_SerialPort"); 
      ManagementObjectSearcher searcher = new ManagementObjectSearcher(connectionScope, serialQuery); 

      try 
      { 
       foreach (ManagementObject item in searcher.Get()) 
       { 
        string desc = item["Description"].ToString(); 
        string deviceId = item["DeviceID"].ToString(); 

        if (desc.Contains("Arduino")) 
        { 
         return deviceId; 
        } 
       } 
      } 
      catch (ManagementException e) 
      { 
       /* Do Nothing */ 
      } 

      return null; 
     } 
+0

我试过这段代码,它似乎没有在我的机器上找到任何东西。当时我有一个seeeduino巨型连接。 – cmroanirgo 2011-04-20 02:07:05

+0

@cmroanirgo它在设备管理器中显示的是什么? – Brandon 2011-04-20 04:26:12

+2

它显示为“USB串行端口”(并且deicimila也响应相同)。对我来说,唯一真正的解决方案是打开每个COM端口,发送一个魔法字节,并听取魔术般的回应,就像其他答案所暗示的那样。 – cmroanirgo 2011-05-12 04:35:14

9
  1. 您可以使用SerialPort.GetPortNames()返回字符串COM端口名称的数组。
  2. 我不认为你可以自动检测端口,你必须ping设备,以查看设备是否连接。
+1

我很好开放的端口和发送命令/监听响应......只是不知道是否有一个最佳实践“p ing“一个Arduino会回应..并且还发现该端口是否已被其他东西使用,等等。 – Brandon 2010-07-20 20:13:06

+2

This(http://stackoverflow.com/questions/195483/c-check-if-a- com-serial-port-is-already-open)发布有关查找端口是否正在使用的讨论。基本上你需要尝试打开它们。如果你得到一个异常,那么它可能正在使用。如果打开正常,您可以检查IsOpen属性以验证其连接。我会从Arduino开发板发现最小的消息或修订响应消息,以确认您实际连接到了电路板而不是其他设备。 – SwDevMan81 2010-07-20 20:21:45

1

试试这个,我工作的一个非常类似的项目,任何人都可以随时编辑这个!

在Arduino代码的设置部分,我调用了setupComms()方法,这个方法只是打印一个“A”直到它接收到一个“a”。一旦收到“a”,它将跳转到主循环()函数。因此,C#部分检查每个可用端口的“A”,如果发现“A”,我们知道我们已经打开了Arduino的端口!

再次,这可能不是很干净,但它确实工作,我欢迎任何意见和建议!

foreach (string s in SerialPort.GetPortNames()) 
     { 
      com.Close(); // To handle the exception, in case the port isn't found and then they try again... 

      bool portfound = false; 
       com.PortName = s; 
       com.BaudRate = 38400; 
       try 
       { 
        com.Open(); 
        status.Clear(); 
        status.Text += "Trying port: " + s+"\r"; 
       } 
       catch (IOException c) 
       { 
        status.Clear(); 
        status.Text += "Invalid Port"+"\r"; 
        return; 
       } 
       catch (InvalidOperationException c1) 
       { 

        status.Clear(); 
        status.Text += "Invalid Port" + "\r"; 
        return; 
       } 
       catch (ArgumentNullException c2) 
       { 
        // System.Windows.Forms.MessageBox.Show("Sorry, Exception Occured - " + c2); 
        status.Clear(); 
        status.Text += "Invalid Port" + "\r"; 
        return; 
       } 
       catch (TimeoutException c3) 
       { 
        // System.Windows.Forms.MessageBox.Show("Sorry, Exception Occured - " + c3); 
        status.Clear(); 
        status.Text += "Invalid Port" + "\r"; 
        return; 
       } 
       catch (UnauthorizedAccessException c4) 
       { 
        //System.Windows.Forms.MessageBox.Show("Sorry, Exception Occured - " + c); 
        status.Clear(); 
        status.Text += "Invalid Port" + "\r"; 
        return; 
       } 
       catch (ArgumentOutOfRangeException c5) 
       { 
        //System.Windows.Forms.MessageBox.Show("Sorry, Exception Occured - " + c5); 
        status.Clear(); 
        status.Text += "Invalid Port" + "\r"; 
        return; 
       } 
       catch (ArgumentException c2) 
       { 
        //System.Windows.Forms.MessageBox.Show("Sorry, Exception Occured - " + c2); 
        status.Clear(); 
        status.Text += "Invalid Port" + "\r"; 
        return; 
       } 
       if (!portfound) 
       { 
        if (com.IsOpen) // Port has been opened properly... 
        { 
         com.ReadTimeout = 500; // 500 millisecond timeout... 
         sent.Text += "Attemption to open port " + com.PortName + "\r"; 
         try 
         { 
          sent.Text += "Waiting for a response from controller: " + com.PortName + "\r"; 
          string comms = com.ReadLine(); 
          sent.Text += "Reading From Port " + com.PortName+"\r"; 
          if (comms.Substring(0,1) == "A") // We have found the arduino! 
          { 
           status.Clear(); 
           status.Text += s + com.PortName+" Opened Successfully!" + "\r"; 
           //com.Write("a"); // Sends 0x74 to the arduino letting it know that we are connected! 
           com.ReadTimeout = 200; 
           com.Write("a"); 
           sent.Text += "Port " + com.PortName + " Opened Successfully!"+"\r"; 
           brbox.Text += com.BaudRate; 
           comboBox1.Text = com.PortName; 

          } 
          else 
          { 
           sent.Text += "Port Not Found! Please cycle controller power and try again" + "\r"; 
           com.Close();  
          } 
         } 
         catch (Exception e1) 
         { 
          status.Clear(); 
          status.Text += "Incorrect Port! Trying again..."; 
          com.Close(); 
         } 
        } 
       } 
     } 

所有的Try Catch语句都在我最初测试的时候出现,这对我来说迄今为止都有效。祝你好运!

5

把WMI管理路线做得更远一点,我想出了一个包装类,它挂接到Win32_SerialPorts事件并动态填充Arduino和Digi International(X-Bee)设备的SerialPorts列表, PortNames和BaudRates。

现在,我已经使用Win32_SerialPorts条目中的设备描述字段作为字典的关键字,但这可以很容易地更改。

它已经通过Arduino UNO进行了有限容量的测试,看起来很稳定。

// ------------------------------------------------------------------------- 
// <copyright file="ArduinoDeviceManager.cs" company="ApacheTech Consultancy"> 
//  Copyright (c) ApacheTech Consultancy. All rights reserved. 
// </copyright> 
// <license type="GNU General Public License" version="3"> 
//  This program is free software: you can redistribute it and/or modify 
//  it under the terms of the GNU General Public License as published by 
//  the Free Software Foundation, either version 3 of the License, or 
//  (at your option) any later version. 
// 
//  This program is distributed in the hope that it will be useful, 
//  but WITHOUT ANY WARRANTY; without even the implied warranty of 
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
//  GNU General Public License for more details. 
// 
//  You should have received a copy of the GNU General Public License 
//  along with this program. If not, see http://www.gnu.org/licenses 
// <license> 
// ------------------------------------------------------------------------- 

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Diagnostics; 
using System.IO.Ports; 
using System.Linq; 
using System.Management; 
using System.Runtime.CompilerServices; 

// Automatically imported by Jetbeans Resharper 
using ArduinoLibrary.Annotations; 

namespace ArduinoLibrary 
{ 
    /// <summary> 
    ///  Provides automated detection and initiation of Arduino devices. This class cannot be inherited. 
    /// </summary> 
    public sealed class ArduinoDeviceManager : IDisposable, INotifyPropertyChanged 
    { 
     /// <summary> 
     ///  A System Watcher to hook events from the WMI tree. 
     /// </summary> 
     private readonly ManagementEventWatcher _deviceWatcher = new ManagementEventWatcher(new WqlEventQuery(
      "SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2 OR EventType = 3")); 

     /// <summary> 
     ///  A list of all dynamically found SerialPorts. 
     /// </summary> 
     private Dictionary<string, SerialPort> _serialPorts = new Dictionary<string, SerialPort>(); 

     /// <summary> 
     ///  Initialises a new instance of the <see cref="ArduinoDeviceManager"/> class. 
     /// </summary> 
     public ArduinoDeviceManager() 
     { 
      // Attach an event listener to the device watcher. 
      _deviceWatcher.EventArrived += _deviceWatcher_EventArrived; 

      // Start monitoring the WMI tree for changes in SerialPort devices. 
      _deviceWatcher.Start(); 

      // Initially populate the devices list. 
      DiscoverArduinoDevices(); 
     } 

     /// <summary> 
     ///  Gets a list of all dynamically found SerialPorts. 
     /// </summary> 
     /// <value>A list of all dynamically found SerialPorts.</value> 
     public Dictionary<string, SerialPort> SerialPorts 
     { 
      get { return _serialPorts; } 
      private set 
      { 
       _serialPorts = value; 
       OnPropertyChanged(); 
      } 
     } 

     /// <summary> 
     ///  Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. 
     /// </summary> 
     public void Dispose() 
     { 
      // Stop the WMI monitors when this instance is disposed. 
      _deviceWatcher.Stop(); 
     } 

     /// <summary> 
     ///  Occurs when a property value changes. 
     /// </summary> 
     public event PropertyChangedEventHandler PropertyChanged; 

     /// <summary> 
     ///  Handles the EventArrived event of the _deviceWatcher control. 
     /// </summary> 
     /// <param name="sender">The source of the event.</param> 
     /// <param name="e">The <see cref="EventArrivedEventArgs"/> instance containing the event data.</param> 
     private void _deviceWatcher_EventArrived(object sender, EventArrivedEventArgs e) 
     { 
      DiscoverArduinoDevices(); 
     } 

     /// <summary> 
     ///  Dynamically populates the SerialPorts property with relevant devices discovered from the WMI Win32_SerialPorts class. 
     /// </summary> 
     private void DiscoverArduinoDevices() 
     { 
      // Create a temporary dictionary to superimpose onto the SerialPorts property. 
      var dict = new Dictionary<string, SerialPort>(); 

      try 
      { 
       // Scan through each SerialPort registered in the WMI. 
       foreach (ManagementObject device in 
        new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_SerialPort").Get()) 
       { 
        // Ignore all devices that do not have a relevant VendorID. 
        if (!device["PNPDeviceID"].ToString().Contains("VID_2341") && // Arduino 
         !device["PNPDeviceID"].ToString().Contains("VID_04d0")) return; // Digi International (X-Bee) 

        // Create a SerialPort to add to the collection. 
        var port = new SerialPort(); 

        // Gather related configuration details for the Arduino Device. 
        var config = device.GetRelated("Win32_SerialPortConfiguration") 
             .Cast<ManagementObject>().ToList().FirstOrDefault(); 

        // Set the SerialPort's PortName property. 
        port.PortName = device["DeviceID"].ToString(); 

        // Set the SerialPort's BaudRate property. Use the devices maximum BaudRate as a fallback. 
        port.BaudRate = (config != null) 
             ? int.Parse(config["BaudRate"].ToString()) 
             : int.Parse(device["MaxBaudRate"].ToString()); 

        // Add the SerialPort to the dictionary. Key = Arduino device description. 
        dict.Add(device["Description"].ToString(), port); 
       } 

       // Return the dictionary. 
       SerialPorts = dict; 
      } 
      catch (ManagementException mex) 
      { 
       // Send a message to debug. 
       Debug.WriteLine(@"An error occurred while querying for WMI data: " + mex.Message); 
      } 
     } 

     /// <summary> 
     ///  Called when a property is set. 
     /// </summary> 
     /// <param name="propertyName">Name of the property.</param> 
     [NotifyPropertyChangedInvocator] 
     private void OnPropertyChanged([CallerMemberName] string propertyName = null) 
     { 
      var handler = PropertyChanged; 
      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 
+0

我想你的意思是“继续”而不是“return”在这一行:if(!device [“PNPDeviceID”]。ToString()。Contains(“VID_2341”)&&!device [“PNPDeviceID”]。ToString()。包含(“VID_04d0”))return; – Guilherme 2016-09-22 04:44:57

+0

很可能。我从一个工作解决方案发布了这个逐字记录。我没有Arduino来测试它,所以如果它能正常工作,请告诉我,我将编辑这篇文章。 :-) – Apache 2016-09-24 22:02:50

0

我发现我的Arduino纳米的中国克隆在设备管理器中显示正确的COM端口,但它并没有在C#应用程序村落下拉列表中显示,当你使用这个尝试,并得到所有端口命令:

using (var searcher = new ManagementObjectSearcher("SELECT * FROM WIN32_SerialPort")); 

但是,在执行时,它被正确地示出:

foreach (string z in SerialPort.GetPortNames()) 

所以,我有2所列出:一个具有第一码输出,以及一个从第二代码输出。比较两者时,它会找到正确的COM端口。显然,当使用原始Andurino Uno时,两个命令都能正确显示端口,所以这个解决方案只适用于中国克隆,由于某种奇怪的原因,这些克隆不可见using (var searcher = new ManagementObjectSearcher("SELECT * FROM WIN32_SerialPort"));

1

这种方法并不能帮助您找出arduino连接的端口到您的计算机

SerialPort.GetPortNames方法()

// Get a list of serial port names. 
     string[] ports = SerialPort.GetPortNames(); 

     Console.WriteLine("The following serial ports were found:"); 
     Console.WriteLine("Aşşağıda Seri Bağlantı Noktaları Bulundu:");//For Turkish 
     // Display each port name to the console. 
     foreach(string port in ports) 
     { 
      Console.WriteLine(port); 
     } 

     Console.ReadLine(); 
+0

你可以给你的答案添加一个简短的解释吗? – 2017-05-15 19:05:13

+0

okey我很抱歉 – 2017-05-21 19:23:17