libusb + Qt 实现

/ 1评 / 0

为了方便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);
            }
        }

        /* 这里可以做点别的轮询任务;演示就空转 */
    }
}

实测效果.

代码比较多比较大,所以就以附件形式放上来.

  1. shiinakaze说道:

    博主的blog能否给blog建一个category或者tag,方便查找。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注