Библиотека Libusb для работы с USB Custom HID.

USB HID

Всем доброго дня! Сегодня мы будем писать свою собственную программу для хоста, которая будет осуществлять прием и передачу данных от устройства, для которого мы уже реализовали класс USB Custom HID. А произошло это в двух предыдущих статьях, посвященных работе с USB HID – раз и два. В качестве среды разработки я буду использовать мой любимый Qt Creator, а для работы с USB предлагаю использовать специально для этого созданную библиотеку Libusb. Собственно, начать думаю стоит с ее установки.

1. Скачиваем архив с библиотекой с официального сайта Libusb.

2. Теперь необходимо скопировать ряд файлов, которые можно найти в распакованном архиве в папке bin. Файл libusb0.dll копируем в папку C:\Windows\System32, а файл libusb0.sys  – в C:\Windows\System32\drivers. На этом операции с файловой системой заканчиваются и мы переходим к шагу 3 🙂

3. На каждое устройство, которое планируется использовать необходимо установить так называемый фильтр. Делается это следующим образом. Все в той же папке bin находим файл install-filter-win.exe и запускаем. В появившемся окне выбираем Install a device filter и нажимаем Next. Сразу же открывается новое окно, в котором мы видим список подключенных устройств. Нам необходимо найти наш девайс и выбрать именно его:

Qt и Libusb.

Жмем на Install и все – фильтр успешно установлен!

4. Создаем где-нибудь директорию для хранения файлов библиотеки – я к примеру создал папку прямо на диске C:/ и назвал ее вполне тривиально – libusb. В эту папку из скачанного архива переносим папки include и lib.

С установкой библиотеки на этом заканчиваем и переходим к созданию нового проекта в Qt Creator. Библиотеки-то готовы к использованию, но их необходимо подключить непосредственно к нашему проекту, для этого в файле .pro добавляем строки следующего содержания:

LIBS           += C:/libusb/lib/gcc/libusb.a
INCLUDEPATH    += C:/libusb/include/
DEPENDPATH     += C:/libusb/include/
PRE_TARGETDEPS += C:/libusb/lib/gcc/libusb.a

А в файле MainWindow.h добавляем:

#include "C:\libusb\include/lusb0_usb.h"

Сразу же определим переменную:

usb_dev_handle *USB_Device = NULL;

Для работы с USB-устройством нам по сути требуется научиться делать три вещи – обеспечивать подключение/открытие устройства с нужными значениями PID/VID, принимать данные и передавать данные. Вот именно в такой последовательности и будем разбираться. Начинаем с того, что определяем все подключенные к шине устройства:

usb_init();
usb_find_busses();
usb_find_devices();

Перебираем все устройства в поисках того, которое нам нужно. А нужен нам девайс со значениями PID / VID – 0x0483 / 0x5750:

struct usb_bus *usbBus;
struct usb_device *usbDevice;

for (usbBus = usb_get_busses(); usbBus; usbBus = usbBus->next)
{
	for (usbDevice = usbBus->devices; usbDevice; usbDevice = usbDevice->next)
	{
		if ((usbDevice->descriptor.idVendor == 0x0483) && (usbDevice->descriptor.idProduct == 0x5750))
		{
			USB_Device = usb_open(usbDevice);
		}
	}
}

Открыв устройство выполняем настройку:

usb_set_configuration(dev, 1);
usb_claim_interface(dev, 0);

Для примера делаем все максимально просто, в реальном проекте как минимум стоит проверить какой код возвращают все эти функции для того, чтобы детектировать возможные ошибки при подключении устройства. В качестве теста при приеме и передаче данных мы как раз-таки произведем анализ на ошибки и выведем их код при помощи qDebug().

А тем временем переходим к приему данных 🙂 А делается это очень просто:

int ret=0;
char usbData[64];

ret = usb_bulk_read(USB_Device, 0x81, usbData, 4, 2000);

if (ret < 0)
{
	qDebug() << "No received data!" << ret;
}
else
{
	qDebug() << "Received data" << usbData;
}

Все сводится к вызову одной функции, и ее аргументы:

  • объект USB_Device
  • 0x81 – это адрес конечной точки нашего устройства (помните, мы определяли все это при создании дескрипторов)
  • usbData – массив для сохранения принятых данных
  • количество принимаемых байт
  • таймаут

С приемом и инициализацией разобрались, на очереди передача данных. Выглядит все это безобразие следующим образом:

usbData[0] = 'S';
usbData[1] = 'n';
usbData[2] = 'd';
usbData[3] = '
usbData[0] = 'S';
usbData[1] = 'n';
usbData[2] = 'd';
usbData[3] = '\0';
ret = usb_bulk_write(USB_Device, 0x01, usbData, 4, 500);
if (ret < 0)
{
qDebug() << "No sended data!" << ret;
}
else
{
qDebug() << "Sended data" << usbData;
}
'; ret = usb_bulk_write(USB_Device, 0x01, usbData, 4, 500); if (ret < 0) { qDebug() << "No sended data!" << ret; } else { qDebug() << "Sended data" << usbData; }

Здесь все практически так же, как и в случае приема данных, только не упускаем из виду, что адрес конечной точки стал другим. Что абсолютно логично, ведь для приема и передачи у нас используются разные endpoint’ы.

Теперь можно без проблем написать свое маленькое приложение, которое будет, к примеру, по нажатию кнопки выполнять отправку данных. А наша статья на этом подходит к концу, даже больше того, подходит к концу “трехстатейный” мини-курс посвященный работе с USB HID 🙂 Надеюсь информация окажется полезной и интересной! Следите за обновлениями и новыми статьями, ждем вас на сайте MicroTechnics снова!

Поделиться!

Подписаться
Уведомление о
guest
27 Комментарий
старее
новее большинство голосов
Inline Feedbacks
View all comments
Alexey
Alexey
4 лет назад

Спасибо огромное за цикл статей! Очень интересно, доступно и полезно! Буду внедрять в свой основной проект!

Паша
Паша
4 лет назад

За проделанную работу огромное спасибо! Будем пробовать.
А в следующих статьях было бы здорово увидеть работу с ethernet на базе W5100 или DP83848 Ethernet Board ( думаю не одному мне будет интересно )

Ed
Ed
4 лет назад

Самая адекватная информация. спасибо.

“1. Скачиваем архив с библиотекой с официального сайта Libusb.”
а подскажи пожалуйста более конкретную информацию, где это взять.

LEV
LEV
4 лет назад

Пока ещё не знаток в C++ и Qt, но связать МК и компьютером хочется) и есть непонятности по статье:

for (usbBus = usb_get_busses(); usbBus; usbBus = usbBus->next)
{
for (usbDevice = usbBus->devices; usbDevice; usbDevice = usbDevice->next)
{
if ((usbDevice->descriptor.idVendor == 0x0483) && (usbDevice->descriptor.idProduct == 0x5750))
{
USB_Device = usb_open(usbDevice);
}
}
}

for (usbBus = usb_get_busses(); usbBus; usbBus = usbBus->next)

Не понятно что такое “next” и почему в цикле он идёт 4-м параметром. При компиляции Qt выдает три ошибки на этой строке
F:\Qt\Project\USB_Lib01\USB\main.cpp:29: ошибка: expected ‘)’ before ‘;’ token
for (usbBus = usb_get_busses(); usbBus; usbBus = usbBus->next)
и
F:\Qt\Project\USB_Lib01\USB\main.cpp:29: ошибка: ‘next’ was not declared in this scope
for (usbBus = usb_get_busses(); usbBus; usbBus = usbBus->next)

Также непонятна переменная “gt” что за тип и откуда она взялась. При сборке проекта выдается ошибка F:\Qt\Project\USB_Lib01\USB\main.cpp:29: ошибка: ‘next’ was not declared in this scope
for (usbBus = usb_get_busses(); usbBus; usbBus = usbBus->next)

LEV
LEV
Reply to  Aveal
4 лет назад

1

LEV
LEV
Reply to  Aveal
4 лет назад

Теперь проект собирается, но в поле ошибок при сборке выходит следующее
Запускается F:\Qt\Project\Qt_OTHER\Express\build-USB_02-Desktop_Qt_5_6_0_MinGW_32bit-Debug\debug\USB_02.exe…
Программа неожиданно завершилась.
F:\Qt\Project\Qt_OTHER\Express\build-USB_02-Desktop_Qt_5_6_0_MinGW_32bit-Debug\debug\USB_02.exe завершился крахом

LEV
LEV
Reply to  LEV
4 лет назад

int main(int argc, char *argv[])
{
usb_dev_handle *USB_Device = NULL;
QApplication app(argc, argv);
MainWindow w;
usb_init();
usb_find_busses();
usb_find_devices();

struct usb_bus *usbBus;
struct usb_device *usbDevice;

for (usbBus = usb_get_busses(); usbBus; usbBus = usbBus->next)
{
for (usbDevice = usbBus->devices; usbDevice; usbDevice = usbDevice->next)
{
if ((usbDevice->descriptor.idVendor == 0x0743) && (usbDevice->descriptor.idProduct == 0x5750))
{
USB_Device = usb_open(usbDevice);
}
}
}

w.show();

return app.exec();

LEV
LEV
Reply to  LEV
4 лет назад

Если я закомментирую от usb_init(); до w.show(); то программа запускается (пустое окно).

В строках usb_set_configuration(dev, 1);
usb_claim_interface(dev, 0);

поменял dev на USB_Device, без этого ошибка – F:\Qt\Project\Qt_OTHER\Express\USB_02\main.cpp:45: ошибка: ‘dev’ was not declared in this scope
usb_set_configuration(dev, 1);

LEV
LEV
Reply to  Aveal
4 лет назад

Aveal, заработало. Контакт МК и ПК установлен, благодарю за статьи.

LEV
LEV
4 лет назад

А как быть в случае передачи с МК на ПК если я беру данные например с АЦП, там ведь тип не char получается… На ПК соответственно вижу разнообразные символы вместо цифр?

LEV
LEV
4 лет назад

Тут при работе с STM32 случилась неприятность. Вдруг в диспетчере задач и вкладки Устройства HID пропал мой STM32. Я переустановил драйвера, по новой настроил фильтра, всё вроде ок. Но проект на Qt с USB не запускается, сообщение Qt Программа неожиданно завершилась и ……….exe завершился крахом. В диспетчере МК отображается с вопросиком, в его свойствах написано “Запуск этого устройства невозможен. (Код 10)” и “Найдена лишняя конечная коллекция, или конечные коллекции не обнаружены.”.

Использую Windows 10, перед этим ничего не менял и не трогал, просто вдруг перестало работать.

Еще странно после установки драйверов libUSB (я кстати для их установки использовал exe файл котрый шел в архиве, как и раньше) МК попадал не в список HID, а в диспетчере создалась отельная вкладка “STM32 Custom Human interface” и фильтр её не видел. Далее я нажимал по этой вкладке-> обновить драйвер автоматически, вроде бы начиналась загрузка и установка но заканчивалось с ошибкой что то вроде Windows удалось обнаружить драйвера но при их установке возникла ошибка. И далее МК уже перемещался в HID устройства, после чего я мог внести его в фильтр.

Подскажите? Возможно бывало такое?

LEV
LEV
Reply to  Aveal
4 лет назад

Несколько раз переустановил драйвера и пока работает.
Ещё один вопросик, а на какой максимальной скоростью можно передавать данные, я так понимаю если передавать пакетами по 64 байта и каждый кадр будет передаваться с интервалом 1 мс то получается 64 КБ, правильно, реальна такая скорость достижима?

Евгений
Евгений
3 лет назад

Приветствую!
Хотелось бы уточнить тип проекта для Кьюта – он обычный, Win32 прога или консольный? Автору пожелание – если возможно, выложить в архиве этот проект, легче разбираться, заодно и ошибки в проекте в новых версиях Кьюта переловить и предостеречь других новичков…

Евгений
Евгений
3 лет назад

Здравствуйте! Не подскажете, как была исправлена ошибка, про которую писал LEV 27.04.2016 в 21:15, что проект собирается, но выходит в крах? У меня сейчас то же самое, не могу понять, где и что не так…

Кайл
Кайл
3 лет назад

А можно как-то без стороннего ПО для установки фильтра? (чтобы наша программа делала все сама, юзеру только запустить и подключить)

Присоединяйтесь!

Profile Profile Profile Profile Profile
Vkontakte
Twitter

Язык сайта

Август 2020
Пн Вт Ср Чт Пт Сб Вс
 12
3456789
10111213141516
17181920212223
24252627282930
31  

© 2013-2020 MicroTechnics.ru