Как программно обнаружить последовательный порт Arduino на разных платформах?
Я пытаюсь написать небольшую программу, которая должна автоматически обнаруживать порты Arduino. Я перепробовал много методов, но не нашел ни одного надежного способа.
Я вижу, что Arduino IDE может обнаружить его, показав /dev/cu.xyz (Arduino Uno)
или COM6 (Arduino Uno)
и т. Д.
Как я могу определить, является ли устройство, подключенное к последовательному порту, Arduino или нет? Желательно без предварительной перепрошивки Arduino с определенной прошивкой.
Я нашел эту версию Python, которая использует serial.tools.list_ports.comports()
здесь, но она не работала, когда я тестировал ее на Windows и macOS.
Лучшее, что я могу получить,-это использовать USBManufacturer go-serial, я могу получить "Arduino (www.arduino.cc).
Я также нашел этот пост, посвященный тому же вопросу, но без какого-либо решения.
@leetom, 👍7
Обсуждение4 ответа
Вы можете запустить Arduino IDE до тех пор, пока не будет обнаружен порт, который хранится на жестком диске arduino IDE;выйти из IDE; затем прочитать этот файл с помощью вашей пользовательской Windows (или любой другой ОС, которую вы используете), чтобы получить ответ. Это ответ на ваш вопрос, который вы написали выше.
Это неприменимо, так как программа должна работать на машинах без Arduino IDE, и процесс обнаружения должен быть АВТОМАТИЧЕСКИМ., @leetom
Это не было ясно для меня из вашего вопроса-вот почему я написал: "Это ответ на ваш вопрос, который вы написали выше"., @Dat Han Bag
Arduino IDE имеет открытый исходный код, поэтому вы можете получить часть кода, которая делает это обнаружение COM-это потребует некоторой работы с вашей стороны-и использовать его в своей собственной программе, @Dat Han Bag
Так что, насколько я понимаю, это действительно ответ на ваш вопрос, @Dat Han Bag
Хорошо, я пытаюсь найти соответствующую часть из исходного кода. Все равно спасибо., @leetom
Вот решение:
В Windows Arduino IDE поставляется с инструментом под названием listComPorts.exe, в котором будут перечислены все COM-порты и их USB-информация, такая как VID & PID. Существует также файл с именем arduino.inf в папке драйверов, содержащий все известные типы устройств и их VID&PID и т.д., И мы можем искать подключенное устройство.
В *nix IDE использует libusb и не имеет такого инструмента, и легко найти инструмент для перечисления информации о usb на этих платформах.
Этот пакет go, упомянутый в вопросе, является хорошим выбором, который также использует libusb и может быть построен на всех платформах. (В Windows вы должны установить mingw для сборки кода C, cygwin и msys не работают, я попробовал TDM-GCC, и он работает. Вы также должны добавить LDFLAGS: -lsetupapi
(в serial.go), чтобы успешно связать код.) После перечисления всех последовательных портов вы можете найти "Arduino", чтобы определить порт. "CH340" также является ключевым словом для поиска, так как многие модифицированные платы используют этот чипсет.
Новая версия IDE не имеет listComPorts.exe все они используют libusb. Я нахожу этот инструмент начиная с версии 1.6.5.
Довольно поздно для вечеринки! Просто оставьте его здесь для тех, кто ищет решение в Windows.
Правильный способ - прочитать список устройств из реестра.
Первое место-это
HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM
Лучшее место находится здесь
HKLM\SYSTEM\CurrentControlSet\Services\usbser\Enum
Там у вас есть список устройств Arduino. Мой - Arduino Leonardo. Подлинный Arduino UNO использует аналогичный чип, и он тоже должен быть там.
Чтобы получить порт, просто скопируйте первое устройство (индекс 0) и подключите его в это место
HKLM\SYSTEM\CurrentControlSet\Enum
Итак, это так
HKLM\SYSTEM\CurrentControlSet\Enum\USB\VID_2341&PID_8036&MI_00\9&88cb209&0&0000
Таким образом, у вас есть дружественное имя и номер порта последовательного устройства. Затем просто напишите какой-нибудь код для чтения этих местоположений реестра.
В C
#include <windows.h>
#include <wchar.h>
#define MAX_VALUE_LENGTH 255
void getUSBSerialList()
{
HKEY hKey;
//проверьте, можем ли мы читать реестр
INT dwRegOPenKey = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\usbser\\Enum"), 0, KEY_READ, &hKey);
if(dwRegOPenKey != ERROR_SUCCESS) return 0;
DWORD type=REG_DWORD, size=0, USBser_count = 0; // место для записи RegQueryValueEx
DWORD dwRes;
//количество считываний USB-устройств
dwRes = RegQueryValueExW(hKey, _T("Count"), NULL, (LPDWORD) &type, (LPBYTE) &USBser_count, &size);
if (dwRes) return 0;
if (USBser_count)
{
for (INT i=0, dwRes = ERROR_SUCCESS; i<USBser_count; i++)
{
WCHAR achValue[MAX_VALUE_LENGTH];
WCHAR buffer[MAX_VALUE_LENGTH];
ZeroMemory(buffer, sizeof WCHAR * MAX_VALUE_LENGTH);
swprintf(achValue, L"%d",i); // прочитать имя значения" 0", "1"...
dwRes = RegQueryValueExW(hKey, achValue, NULL, (LPDWORD) &type, (LPBYTE) &buffer, &size);
// Вставьте это значение в "SYSTEM\\CurrentControlSet\\Enum\\".
HKEY hKey2;
swprintf(achValue, L"SYSTEM\\CurrentControlSet\\Enum\\%s",buffer);
INT dwRegOPenKey2 = RegOpenKeyExW(HKEY_LOCAL_MACHINE, achValue, 0, KEY_READ, &hKey2);
if (dwRegOPenKey2) return 0; // проверьте, существует ли этот ключ
// Отсюда читайте дружественное имя
dwRes = RegQueryValueExW(hKey2, _T("FriendlyName"), NULL, (LPDWORD) &type, (LPBYTE) &buffer, &size);
if (dwRes) return 0;
// или читать COM-порт
swprintf(achValue, L"%s\\Device Parameters", achValue);
dwRegOPenKey2 = RegOpenKeyExW(HKEY_LOCAL_MACHINE, achValue, 0, KEY_READ, &hKey2);
if (dwRegOPenKey2) return 0;
dwRes = RegQueryValueExW(hKey2, _T("PortName"), NULL, (LPDWORD) &type, (LPBYTE) &buffer, &size);
if (dwRes) return 0;
}
}
}
В C# для этого просто используйте объект реестра
int usbser_count = (int)Registry.GetValue("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\usbser\\Enum", "Count", -1);
Я не делал этого в C#, но я думаю, что это проще, чем в C.
Что делать, если ваш клон arduino использует CH340 вместо atmega16u2, он не появится в указанном выше расположении реестра. Вместо этого он появится здесь:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CH341SER_A64\Enum
Вы можете сделать то же самое для других типов USB-последовательных устройств, таких как CP210x (на некоторых платах ESP32 dev).
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\silabser\Enum
Или даже получить список устройств WinUSB (например, ST-Link v2).
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WINUSB\Enum
Вот фрагмент кода C#, основанный на ответе SimonVu14. Он просматривает именованные ключи и получает порты как для чипов Atmega, так и для CH340. Если вы ожидаете, что к компьютеру будет подключен только один Arduino, вы можете просто пойти с первым найденным. В противном случае вам нужно будет что-то придумать, чтобы выяснить, какой из них ваш (что обычно включает в себя открытие порта, отправку некоторого предопределенного запроса и ожидание некоторого предопределенного ответа), или дать пользователю возможность выбрать через пользовательский интерфейс.
private readonly string[] _arduinoKeys = {
@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\usbser\Enum",
@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CH341SER_A64\Enum"
};
/// <summary>
/// See https://arduino.stackexchange.com/questions/30808/how-to-detect-arduino-serial-port-programmatically-on-different-platforms/80887
/// </summary>
private IEnumerable<(string name, string port)> EnumerateArduinos()
{
foreach (var arduinoKey in _arduinoKeys)
{
var countObject = Registry.GetValue(arduinoKey, "Count", null);
if (countObject is not int count)
{
continue;
}
for (int i = 0; i < count; i++)
{
var enumObject = Registry.GetValue(arduinoKey, i.ToString(), null);
if (enumObject is not string enumKey)
{
continue;
}
var friendlyName = Registry.GetValue($@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\{enumKey}", "FriendlyName", null);
var portName = Registry.GetValue($@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\{enumKey}\Device Parameters", "PortName", null);
if (portName is string port && friendlyName is string name)
{
yield return (name, port);
}
}
}
}
- Команда strtok() с Serial связью
- Как изменить переменную при нажатии кнопки, подключенной к контакту 2
- Java NetBeans отправляет значение и получает значение от Arduino
- Почему нужно использовать latin-1 вместо utf-8 при использовании python с arduino?
- Акцептант векселей ИКТ
- Использование последовательной связи в .c-файлах
- Соединение I2C с модулем камеры MT9D111, странные результаты после записи регистров через i2C
- ПК не может получить доступ к порту HC-06 Bluetooth COM
Когда я подключаю Arduino Uno к своей коробке Linux,
lsusb
говорит: “ID 2341: 0043 Arduino SA Uno R3 (CDC ACM)”. Однако я не знаю, как это сделать на других ОС., @Edgar BonetЯ согласен с Эдгаром Бонетом - если вы можете перечислить USB-порты, вы можете определить, на каком из них есть Arduino, как это делает IDE., @Nick Gammon
Да, может быть, информация о usb-это все, что мы можем получить, так как последовательные порты больше не имеют никакой информации. Можно использовать порты
Description
иUSBManufacturer
. Спасибо вам, ребята., @leetomБыло бы полезно получить немного больше информации о том, что вы пытаетесь сделать., @mwwalk