为了方便Qt + libusb这种的开发,我一般是另外安装一个MSYS2 MINGW64环境.这样我可以方便pacman安装各种包.
具体包可以查这个.
https://packages.msys2.org/base/mingw-w64-libusb
不选内置的编译器,新建自己的编译器并指向自己的MSYS2.

然后在pro文件(QMake工程)添加libusb的关联.
INCLUDEPATH += C:/msys64/mingw64/include/libusb-1.0
LIBS += -LC:/msys64/mingw64/lib -lusb-1.0
QMAKE_LFLAGS += -static -static-libgcc -static-libstdc++
LIBS += -Wl,-Bstatic -lwinpthread -Wl,-Bdynamic
之后就可以用libusb的API了,在开始USB通信前,我贴一下下位机的描述符.
code const UINT8 MyCfgDescr[] = {
/* --- Configuration Descriptor --- */
/* bLength */ 0x09,
/* bDescriptorType */ 0x02, /* CONFIGURATION */
/* wTotalLength */ 0x27,0x00, /* 39 字节总长(含子描述符) */
/* bNumInterfaces */ 0x01, /* 1 个接口 */
/* bConfigurationValue */ 0x01, /* 配置值 = 1 */
/* iConfiguration */ 0x00, /* 无配置字符串 */
/* bmAttributes */ 0x80, /* 0x80: Bus-powered; (0xC0: Self-powered) */
/* bMaxPower */ 0x32, /* 0x32 * 2mA = 100mA */
/* --- Interface 0: Vendor-defined --- */
/* bLength */ 0x09,
/* bDescriptorType */ 0x04, /* INTERFACE */
/* bInterfaceNumber */ 0x00, /* Interface #0 */
/* bAlternateSetting */ 0x00, /* Alternate 0 */
/* bNumEndpoints */ 0x03, /* 3 个端点(不含 EP0) */
/* bInterfaceClass */ 0xFF, /* Vendor-specific */
/* bInterfaceSubClass */ 0x80, /* 自定义 */
/* bInterfaceProtocol */ 0x55, /* 自定义 */
/* iInterface */ 0x00, /* 无接口字符串 */
/* --- Endpoint 0x82: IN, Bulk --- */
/* bLength */ 0x07,
/* bDescriptorType */ 0x05, /* ENDPOINT */
/* bEndpointAddress */ 0x82, /* IN | EP2 */
/* bmAttributes */ 0x02, /* 0x02 = Bulk */
/* wMaxPacketSize */ 0x40,0x00, /* 64B(FS Bulk 常用) */
/* bInterval */ 0x00, /* Bulk 在 FS 下忽略 */
/* --- Endpoint 0x02: OUT, Bulk --- */
0x07, 0x05, 0x02, 0x02, 0x40,0x00, 0x00,
/* --- Endpoint 0x81: IN, Interrupt --- */
0x07, 0x05, 0x81, 0x03, 0x40,0x00, 0x01 /* 轮询间隔 1ms(FS下1~255有效) */
};
可以看到是一个Bulk In/Bulk Out/Int In,没有Int Out是因为这个带宽其实很低,没多少意义,实际用途大多数都是Bulk Out.
在上位机打开设备后就可以写了.
int USBDevice::bulkWrite(const QByteArray& data, unsigned int timeoutMs) {
if (!h_) { setLastError("device not open"); return -1; }
int xfer = 0;
int r = libusb_bulk_transfer(h_, epBulkOut_,
reinterpret_cast<unsigned char*>(const_cast<char*>(data.constData())),
data.size(), &xfer, timeoutMs);
if (r != 0) { setLastError("bulk_write: " + luErrName(r)); return -1; }
return xfer;
}
程序主要逻辑是这样的,我们进行实测.
void main(void)
{
UINT8 i; /* C90: 循环变量统一提前声明 */
CfgFsys();
InitUSB_Device();
EA = 1;
for (;;) {
UINT8 n = 0;
/* 原子地"拿走"一帧,尽量短的关中断窗口 */
EA = 0;
n = rx_len;
if (n) {
for (i = 0; i < n; i++) proc[i] = rx_buf[i];
rx_len = 0; /* 清零=释放 rx_buf */
}
EA = 1;
if (n) {
/* 取反 */
for (i = 0; i < n; i++) proc[i] = ~proc[i];
/* 根据取反后的首字节路由 */
if (proc[0] > 0x7F) {
usb_send_int_blocking(proc, n);
} else {
usb_send_bulk_blocking(proc, n);
}
}
/* 这里可以做点别的轮询任务;演示就空转 */
}
}
实测效果.

代码比较多比较大,所以就以附件形式放上来.
博主的blog能否给blog建一个category或者tag,方便查找。