第一次写这种文章,不清晰的地方请帮忙指出
QT环境准备
引言
PC环境:window7
网上很多QT的USB访问,使用的是MCVS的环境,我一番使用下来遇到很多问题,
使用C#写USB驱动需要用到LIBUSBDONET这个库,但是这个库需要手动使用内部的工具生成驱动上位机才能访问到,但是我的是标准的HID设备且每次使用都需要安装一下驱动不太适合,所以改用QT使用libusb这个库来绕开这一步直接访问我的HID设备。
做的过程中发现libusb也分好几种方法,像hidapi这个库虽然很方便,但是在WIN7系统上,hid_write方法总是会失败而hid_read正常,查了很久的资料也找不到解决问题的方法。
Libusb0.h这个库也是需要手动用inf-wizard.exe生成驱动之后上位机才能识别,且此工具会更改USB设备的枚举,我的设备正常枚举是这样
经过inf-wizard.exe生成后,HID这个接口消失,卸载了好几遍驱动才恢复回来。
环境介绍
最后选用libusb1.0这个库
配套的头文件是libusb.h
QT使用的环境是5.15.2MinGw32bit,MinGw实际上就是GCC编译,所以对应使用后缀.a的lib
PS:如果使用MCVS的编译器,记得选用liusb-1.0.lib的静态库,最好是32位的。
在QT中导入LIBUSB
我这边的QT是需要ui界面的,所以新建了一个标准的mainwindow的工程,文件结构是
1.放置了需要引用的.a文件和.h文件
2.QT的工程文件
打开对应的.pro文件,导入libUSB的库,是通过路径索引的方法,导入的方法很多,还是推荐直接填写路径的方法,因为-L的方法有时候会出错,看个人选用。
这种导入.h的方法就不需要在Headers文件中再次导入我们的libusb.h文件直接在代码中
#Include”libusb.h”就可以了,如图所示。
QT代码部分
USB初始化
1.初始化
在窗口生成的时候,放入USB初始化的语句,若初始化成功,则res变量值为0,这一步如果出现函数解析错误的报错,就需要检查当前libusb库是否跟编译对应,或者将libusb重新生成一遍。
然后对应在窗口关闭时销毁USB
#include "ui_mainwindow.h"
#include "libusb.h"
#include "self_config.h"
#include
#include
#include
#include
#include
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
int res;
res=libusb_init(NULL);
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
libusb_exit(NULL);
delete ui;
}
USB打印设备
打印所有USB设备,这一步可以检查上位机是否能访问到现在PC上接入的USB设备,如果就要检查是否使用到libusb0.h这种库,因为网上搜索libusb也会搜索到libusb0.h这种库,但是库里面函数名和使用的方法也不一样,几率不是很大,可以用BUS HOUND多多检查。
int find_all_of_devices(void)
{
libusb_device **devs;
ssize_t cnt;
cnt = libusb_get_device_list(NULL, &devs);
print_dev(devs);
}
void print_dev(libusb_device **devs)
{
libusb_device *dev;
int i = 0, j = 0;
uint8_t path[8];
while ((dev = devs[i++]) != NULL)
{
struct libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(dev, &desc);
if (r < 0) {
qDebug("failed to get device descriptor");
return;
}
//main_show->ui->textBrowser->setText("aaaa");
#if 1
qDebug("%04x:%04x (bus %d, device %d)",
desc.idVendor, desc.idProduct,
libusb_get_bus_number(dev), libusb_get_device_address(dev));
r = libusb_get_port_numbers(dev, path, sizeof(path));
if (r > 0) {
qDebug(" path: %d", path[0]);
for (j = 1; j < r; j++)
qDebug(".%d", path[j]);
}
#endif
}
}
Usb读写设备
测试设备介绍:
此次用测试的设备是一块新塘的板子,接入PC后枚举后可以看到有一个HID接口
使用libusb_open_device_with_vid_pid方法来访问我们指定的设备
void test_my_usb_devices(int vid,int pid)
{
libusb_device_handle *handle;
libusb_device *dev;
int bus;
struct libusb_config_descriptor *conf_desc;
const struct libusb_endpoint_descriptor *endpoint;
uint8_t endpoint_in = 0, endpoint_out = 0;
int endpoint_num, nb_ifaces, altesetting = -1;
struct libusb_ss_endpoint_companion_descriptor *ep_comp = NULL;
uint8_t buf[63]={
0};
int i;
int res;
int size=0;
/*打开设备*/
handle = libusb_open_device_with_vid_pid(NULL, vid, pid);
if (handle == NULL)
qDebug("open devices failed");
dev = libusb_get_device(handle);
bus = libusb_get_bus_number(dev);
libusb_get_config_descriptor(dev, 0, &conf_desc);
nb_ifaces = conf_desc->bNumInterfaces;
qDebug()<<nb_ifaces;
读取设备读、写端点
if(nb_ifaces>0)
{
altesetting=conf_desc->interface[0].num_altsetting;
if(altesetting>0)
{
endpoint_num=conf_desc->interface[0].altsetting[0].bNumEndpoints;
if(endpoint_num>0)
{
for(i=0;i<endpoint_num;i++)
{
endpoint= &conf_desc->interface[0].altsetting[0].endpoint[i];
if ((endpoint->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) & (LIBUSB_TRANSFER_TYPE_BULK | LIBUSB_TRANSFER_TYPE_INTERRUPT)) {
if (endpoint->bEndpointAddress & LIBUSB_ENDPOINT_IN) {
if (!endpoint_in)
endpoint_in = endpoint->bEndpointAddress;
}
else {
if (!endpoint_out)
endpoint_out = endpoint->bEndpointAddress;
}
}
}
}
else
qDebug("endpoint num error");
}
else
{
qDebug("altsetting error");
}
}
else
qDebug("interface found error");
/*释放配置描述符*/
libusb_free_config_descriptor(conf_desc);
/*卸载驱动内核*/
libusb_set_auto_detach_kernel_driver(handle, 1);
/*为指定的设备申请接口*/
res=libusb_claim_interface(handle, 0);
res<0?qDebug("claim interface error"):qDebug("claim interface success");
USB读写操作
while (1)
{
memset(&buf[0], 0, 63);
qDebug("Testing interrupt read using endpoint %02X...\n", endpoint_in);
res = libusb_interrupt_transfer(handle, endpoint_in, buf, 64, &size, 1000);
if (res >= 0) {
qDebug("read ok:");
for (uint8_t i = 0; i < 64; i++)
{
qDebug("%02x ", buf[i]);
}
}
else {
qDebug(" %s\n", libusb_strerror((enum libusb_error)res));
}
buf[0] = 0x12;
buf[1] = 0x13;
buf[2] = 0x14;
buf[3] = 0x15;
qDebug("\nTesting interrupt write using endpoint %02X...\n", endpoint_out);
res = libusb_interrupt_transfer(handle, endpoint_out, buf, 63, &size, 1000);
//r = libusb_interrupt_transfer(handle, endpoint_out, report_buffer, 64, &size, 1000);
//r = libusb_interrupt_transfer(handle, endpoint_out, report_buffer, 65, &size, 1000);
if (res >= 0) {
qDebug("write ok\n");
}
else {
qDebug(" %s\n", libusb_strerror((enum libusb_error)res));
}
Sleep(1000);
}
}
最后我在按钮点击事件中调用,PID和VID可以通过BUS HOUND查看确定一下
void MainWindow::on_btn1_open_clicked()
{
find_all_of_devices();
test_my_usb_devices(0x248a,0x1239);
}