2010-07-20 14 views
17

estoy usando un Arduino con la biblioteca Firmata para la comunicación con una aplicación C#, y quiero eliminar un componente de configuración del puerto COM, ya que puede cambiar de máquina a máquina ...¿Cómo detectar automáticamente el puerto COM de Arduino?

¿Es posible:

  1. ¿Enumerar la lista de puertos COM en el sistema? (En mi Google he visto un código de API de Win32 bastante feo, esperando que haya una versión más limpia ahora)
  2. Detecte automáticamente qué puerto (s) COM están conectados a un Arduino?

Respuesta

14

Este pequeño trozo de código ha funcionado muy bien para esto (devuelve la cadena puerto COM, es decir, "COM12" si se detecta 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

He intentado este código y no parece encontrar nada en mi máquina. Tuve un seeeduino mega conectado en ese momento. – cmroanirgo

+0

@cmroanirgo ¿qué se muestra en el administrador de dispositivos? – Brandon

+2

Se muestra como un "puerto serie USB" (y una deicimila también responde lo mismo). Para mí, la única solución real era abrir cada puerto COM, enviar un byte mágico y escuchar una respuesta mágica, como sugieren las otras respuestas. – cmroanirgo

9
  1. Puede utilizar SerialPort.GetPortNames() para devolver una matriz de nombres de puertos COM cadena.
  2. No creo que pueda detectar automáticamente los puertos, debe hacer ping al dispositivo para ver si el dispositivo está conectado.
+1

estoy bien con la apertura de los puertos y el envío de un comando/respuesta para escuchar ... pero no sé si hay una la mejor práctica "p "a que respondería un Arduino ... y también averigüe si el puerto ya está siendo utilizado por otra cosa, etc. – Brandon

+2

This (http://stackoverflow.com/questions/195483/c-check-if-a- publicación de com-serial-port-is-already-open) habla de encontrar si un puerto está en uso. Básicamente, debes intentar abrirlos. Si obtiene una excepción, entonces probablemente esté en uso. Si se abre bien, puede verificar la propiedad IsOpen para verificar que esté conectada. Encontraría el mensaje más pequeño o un mensaje de respuesta de revisión de la placa Arduino para verificar que esté realmente conectado a la placa y no a otro dispositivo. – SwDevMan81

1

probar esto, estoy trabajando en una proyecto muy similar, también a cualquier persona por favor siéntase libre de editar esto!

En la parte de configuración del código Arduino, lo llamo método setupComms(), este método simplemente imprime una "A" hasta que recibe una "a". Una vez que se recibe "a", salta a la función de bucle principal(). ¡Entonces la porción C# comprueba cada puerto disponible para "A" y si se encuentra "A" sabemos que hemos abierto el puerto al Arduino!

De nuevo, esto puede no ser muy limpio, pero funciona, estoy abierto a cualquier comentario o sugerencia.

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

Todas las declaraciones de Try Catch están allí desde que estaba originalmente probando, esto me ha funcionado hasta ahora. ¡Buena suerte!

5

Llevando la ruta de gestión de WMI un poco más allá, he creado una clase contenedora que enlaza a los eventos Win32_SerialPorts y llena dinámicamente una lista de puertos seriales para dispositivos Arduino y Digi International (X-Bee), completa con PortNames y BaudRates.

Por ahora, he utilizado el campo Descripción de dispositivos en la entrada Win32_SerialPorts como la clave para el diccionario, pero esto puede cambiarse fácilmente.

Ha sido probado a una capacidad limitada con un Arduino UNO y parece ser estable.

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

Supongo que quiere decir "continuar" en lugar de "regresar" en esta línea: if (! Device ["PNPDeviceID"]. ToString(). Contiene ("VID_2341") &&! Device ["PNPDeviceID"]. ToString(). Contiene ("VID_04d0")) return; – Guilherme

+0

Muy posiblemente. Publiqué esta textual de una solución de trabajo. Ya no tengo un Arduino para probarlo, así que si funciona, házmelo saber y editaré la publicación. :-) – Apache

0

me he dado cuenta de que mi clon chino del Arduino nano muestra el puerto COM correctamente en el Administrador de dispositivos, pero no aparece en la aplicación de C# dorp desplegable cuando intenta y obtener todos los puertos que utiliza este comando:

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

Sin embargo, se muestra correctamente cuando se ejecuta:

foreach (string z in SerialPort.GetPortNames()) 

Así que tienen 2 listas: una con una producción de primera código, y una con salida de segundo código. Al comparar ambos, encontrará el puerto COM correcto.Obviamente, cuando se utilizan los comandos originales de Andurino Uno, el puerto se muestra correctamente, por lo que esta solución solo funcionará para los clones chinos que, por alguna extraña razón, son invisibles para using (var searcher = new ManagementObjectSearcher("SELECT * FROM WIN32_SerialPort"));

1

Este método no le ayuda a averiguar a qué puerto está conectado su arduino a su ordenador

SerialPort.GetPortNames Método()

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

¿Puedes agregar una breve explicación a tu respuesta? –

+0

okey Lo siento –

Cuestiones relacionadas