2010-07-20 144 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