如何自动检测Arduino COM端口?
我使用一个Arduino与Firmata库通讯C#应用程序,和我想要消除的COM端口配置组件,因为它可以从机改为机...如何自动检测Arduino COM端口?
是否有可能:
- 枚举系统中的COM端口列表? (在我的谷歌搜索中,我已经看到一些相当丑陋的Win32 API代码,希望现在可能有更清洁的版本)
- 自动检测哪个COM端口连接到Arduino?
这个代码一点已经表现非常出色,这(返回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;
}
- 您可以使用SerialPort.GetPortNames()返回字符串COM端口名称的数组。
- 我不认为你可以自动检测端口,你必须ping设备,以查看设备是否连接。
我很好开放的端口和发送命令/监听响应......只是不知道是否有一个最佳实践“p ing“一个Arduino会回应..并且还发现该端口是否已被其他东西使用,等等。 – Brandon 2010-07-20 20:13:06
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
试试这个,我工作的一个非常类似的项目,任何人都可以随时编辑这个!
在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语句都在我最初测试的时候出现,这对我来说迄今为止都有效。祝你好运!
把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));
}
}
}
我发现我的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"));
这种方法并不能帮助您找出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();
你可以给你的答案添加一个简短的解释吗? – 2017-05-15 19:05:13
okey我很抱歉 – 2017-05-21 19:23:17
我试过这段代码,它似乎没有在我的机器上找到任何东西。当时我有一个seeeduino巨型连接。 – cmroanirgo 2011-04-20 02:07:05
@cmroanirgo它在设备管理器中显示的是什么? – Brandon 2011-04-20 04:26:12
它显示为“USB串行端口”(并且deicimila也响应相同)。对我来说,唯一真正的解决方案是打开每个COM端口,发送一个魔法字节,并听取魔术般的回应,就像其他答案所暗示的那样。 – cmroanirgo 2011-05-12 04:35:14