2010-07-20 70 views
17

Tôi đang sử dụng Arduino với thư viện Firmata để liên lạc với ứng dụng C# và tôi muốn loại bỏ thành phần cấu hình cổng COM vì nó có thể thay đổi từ máy thành ...Làm cách nào để tự động phát hiện cổng COM COM?

Có thể:

  1. Liệt kê danh sách các cổng COM trong hệ thống? (Trong googling của tôi tôi đã nhìn thấy một số mã Win32 API khá xấu xí, hy vọng có thể có một phiên bản sạch hơn bây giờ)
  2. Tự động phát hiện cổng COM nào được kết nối với Arduino?

Trả lời

14

này chút mã đã thực hiện rất tốt cho việc này (trả về chuỗi COM port, tức là "COM12" nếu Arduino được phát hiện):

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

Tôi đã thử mã này và dường như không tìm thấy bất kỳ thứ gì trên máy của tôi. Tôi đã có một mega seeeduino kết nối vào thời điểm đó. – cmroanirgo

+0

@cmroanirgo nó hiển thị như thế nào trong trình quản lý thiết bị? – Brandon

+2

Nó hiển thị như là một "Cổng nối tiếp USB" (và một deicimila cũng phản ứng như nhau). Đối với tôi, giải pháp thực sự duy nhất là mở mỗi cổng COM, gửi một byte ma thuật và lắng nghe một phản ứng ma thuật, giống như các câu trả lời khác gợi ý. – cmroanirgo

9
  1. Bạn có thể sử dụng SerialPort.GetPortNames() để trả về một mảng tên cổng COM.
  2. Tôi không nghĩ rằng bạn có thể tự động phát hiện các cổng, bạn phải ping thiết bị để xem thiết bị có được kết nối hay không.
+1

tôi tốt với việc mở các cổng và gửi một lệnh/lắng nghe câu trả lời ... chỉ không biết nếu có một thực hành tốt nhất "p ing "rằng một Arduino sẽ trả lời .. và cũng tìm hiểu xem cổng đã được sử dụng bởi cái gì khác, vv – Brandon

+2

Điều này (http://stackoverflow.com/questions/195483/c-check-if-a- com-serial-port-is-already-open) các cuộc đàm phán về việc tìm kiếm một cổng đang được sử dụng hay không. Về cơ bản bạn cần phải thử và mở chúng. Nếu bạn nhận được một ngoại lệ, sau đó nó có thể được sử dụng. Nếu nó mở ra tốt, bạn có thể kiểm tra các tài sản IsOpen để xác minh rằng nó kết nối. Tôi sẽ tìm thấy thông điệp nhỏ nhất hoặc một thông điệp phản hồi sửa đổi từ bảng Arduino để xác minh rằng bạn đang thực sự kết nối với hội đồng quản trị và không phải một số thiết bị khác. – SwDevMan81

1

Hãy thử điều này, tôi đang làm việc trên một dự án rất giống nhau, bất cứ ai cũng cảm thấy tự do để chỉnh sửa điều này!

Trong phần thiết lập của mã Arduino, tôi gọi nó là phương thức setupComms(), phương thức này chỉ in dấu "A" cho đến khi nó nhận được "a". Khi nhận được "a", nó nhảy tới hàm vòng lặp chính(). Vì vậy, phần C# kiểm tra từng cổng có sẵn cho "A" và nếu "A" được tìm thấy, chúng tôi biết rằng chúng tôi đã mở cổng cho Arduino!

Một lần nữa, điều này có thể không rất sạch sẽ nhưng nó hoạt động, tôi mở cho mọi nhận xét và đề xuất!

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(); 
         } 
        } 
       } 
     } 

Tất cả câu lệnh Try Catch đều có trong đó từ khi tôi thử nghiệm ban đầu, điều này đã có hiệu quả đối với tôi. Chúc may mắn!

5

Sử dụng tuyến quản lý WMI thêm một chút, tôi đã đưa ra một lớp trình bao bọc cho các sự kiện Win32_SerialPorts và tự động điền danh sách các SerialPort cho thiết bị Arduino và Digi International (X-Bee), hoàn chỉnh với PortNames và BaudRates.

Hiện tại, tôi đã sử dụng trường Mô tả thiết bị trong mục nhập Win32_SerialPorts làm Khóa cho Từ điển, nhưng điều này có thể dễ dàng thay đổi.

Nó đã được thử nghiệm với công suất giới hạn với Arduino UNO và nó có vẻ ổn định.

// ------------------------------------------------------------------------- 
// <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

Tôi đoán bạn có nghĩa là "tiếp tục" thay vì "return" trong dòng này: if (! Device ["PNPDeviceID"]. ToString(). Chứa ("VID_2341") &&! Device ["PNPDeviceID"]. ToString(). Chứa ("VID_04d0")) trả về; – Guilherme

+0

Rất có thể. Tôi đã đăng nguyên văn này từ một giải pháp làm việc. Tôi không có Arduino để kiểm tra nó nữa, vì vậy nếu nó hoạt động, hãy cho tôi biết và tôi sẽ chỉnh sửa bài đăng. :-) – Apache

0

tôi đã nhận thấy rằng bản sao Trung Quốc của tôi về Arduino nano xuất hiện cổng COM đúng trong Devices Manager, nhưng nó không hiển thị trên C# ứng dụng Dorp xuống danh sách khi bạn cố gắng và có được tất cả các cổng sử dụng này lệnh:

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

Tuy nhiên, nó được hiển thị một cách chính xác khi thực hiện:

foreach (string z in SerialPort.GetPortNames()) 

Vì vậy, tôi có 2 danh sách: một với đầu ra của mã 1st, và một với sản lượng từ mã thứ 2. Khi so sánh cả hai, nó sẽ tìm thấy cổng COM chính xác.Rõ ràng, khi sử dụng lệnh Andurino Uno gốc, cả hai lệnh sẽ hiển thị cổng chính xác, vì vậy giải pháp này sẽ chỉ hoạt động đối với các bản sao Trung Quốc, vì một số lý do kỳ lạ, vô hình với using (var searcher = new ManagementObjectSearcher("SELECT * FROM WIN32_SerialPort"));

1

Phương pháp này không giúp bạn biết cổng nào của bạn được kết nối để máy tính của bạn

SerialPort.GetPortNames Method()

// 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

Bạn có thể thêm giải thích ngắn cho câu trả lời của mình không? –

+0

okey Tôi xin lỗi –

Các vấn đề liên quan