QT中USB入门(QtUsb)

一、什么是 QtUsb

QtUsb 是一个专为 Qt 开发者设计的跨平台 USB 通信模块,底层基于成熟的 libusb-1.0libhidapi 库实现。它封装了 Windows、Linux、macOS 等不同平台的原生 USB API,提供统一的 Qt 风格接口,让开发者能够"一次编写,到处运行"。

核心功能

功能 说明
批量传输 高效处理大量数据交换
中断传输 适用于实时性要求高的应用
热插拔检测 动态响应 USB 设备的连接与断开
设备枚举与过滤 按 VID/PID 等条件精确选择目标设备
HID 设备支持 无缝处理人机接口设备通信

二、QtUsb 类属性与方法

1、QUsb 类(设备管理器)

QUsb 是 QtUsb 的核心管理类,负责系统级 USB 设备枚举和热插拔事件管理。

1.1 公共方法

方法 返回值 说明
devices() QList<QUsbDeviceInfo> 获取系统中所有 USB 设备的列表
findDevices(filter) QList<QUsbDeviceInfo> 根据过滤器条件查找匹配的设备
isHotplugSupported() bool 检查当前平台是否支持热插拔检测

1.2 信号

信号 参数 说明
deviceAdded(QUsbDeviceInfo) info - 设备信息 USB 设备插入时触发
deviceRemoved(QUsbDeviceInfo) info - 设备信息 USB 设备拔出时触发

1.3 使用示例

cpp

复制代码
QUsb usbManager;

// 枚举所有设备
QList<QUsbDeviceInfo> devices = usbManager.devices();

// 热插拔检测
connect(&usbManager, &QUsb::deviceAdded, this, [](const QUsbDeviceInfo &info) {
    qDebug() << "设备已插入:" << info.product;
});

2、QUsbDevice 类(USB 设备操作)

QUsbDevice 代表一个具体的 USB 设备,提供打开/关闭、读写和控制传输等操作。

2.1 公共方法

方法 返回值 说明
open(vid, pid) bool 通过 VID/PID 打开设备
open(info) bool 通过设备信息结构体打开设备
open(path) bool 通过设备路径打开设备
close() void 关闭设备连接
isOpen() bool 检查设备是否已打开
read(size) QByteArray 读取指定字节数的数据
readAll() QByteArray 读取所有可用数据
write(data) qint64 写入数据,返回实际写入字节数
controlTransfer(type, request, value, index, data, timeout) QByteArray 执行控制传输
setReadBufferSize(size) void 设置读取缓冲区大小
errorString() QString 获取最后一次错误的描述信息

2.2 信号

信号 参数 说明
readyRead() 有新的数据可读取时触发
readFinished(bytesRead) bytesRead - 实际读取字节数 异步读取完成时触发
errorOccurred(error) error - 错误码 操作过程中发生错误时触发

2.3 使用示例

cpp

复制代码
QUsbDevice device;

// 打开设备
if (device.open(0x04D8, 0x003F)) {
    // 同步写入
    device.write("Hello USB!");
    
    // 异步读取
    connect(&device, &QUsbDevice::readyRead, this, [&]() {
        QByteArray data = device.readAll();
        processData(data);
    });
}

3、QUsbDeviceInfo 类(设备信息)

QUsbDeviceInfo 用于存储 USB 设备的基本描述信息。

3.1 属性

属性 类型 说明
vendorId / vid quint16 厂商 ID(VID)
productId / pid quint16 产品 ID(PID)
vendor QString 厂商名称字符串
product QString 产品名称字符串
serialNumber QString 设备序列号
busNumber int USB 总线编号
deviceAddress int 设备地址
devicePath QString 设备在系统中的路径

3.2 使用示例

cpp

复制代码
QList<QUsbDeviceInfo> devices = usbManager.devices();
for (const QUsbDeviceInfo &info : devices) {
    qDebug() << QString("VID:%1 PID:%2 名称:%3")
                .arg(info.vendorId, 4, 16, QChar('0'))
                .arg(info.productId, 4, 16, QChar('0'))
                .arg(info.product);
}

4、QUsbDeviceFilter 类(设备过滤器)

QUsbDeviceFilter 用于按条件筛选 USB 设备。

4.1 公共方法

方法 返回值 说明
setVendorId(vid) void 设置要匹配的厂商 ID
setProductId(pid) void 设置要匹配的产品 ID
setSerialNumber(serial) void 设置要匹配的序列号
vendorId() quint16 获取当前设置的厂商 ID
productId() quint16 获取当前设置的产品 ID
serialNumber() QString 获取当前设置的序列号
matches(info) bool 检查设备信息是否匹配过滤器条件

4.2 使用示例

cpp

复制代码
QUsbDeviceFilter filter;
filter.setVendorId(0x1234);
filter.setProductId(0x5678);

QList<QUsbDeviceInfo> devices = usbManager.findDevices(filter);

5、QUsbEndpoint 类(端点配置)

QUsbEndpoint 用于配置 USB 端点的传输类型和方向。

5.1 枚举类型

枚举 说明
EndpointType
ControlEndpoint 0 控制端点
IsochronousEndpoint 1 等时端点
BulkEndpoint 2 批量端点
InterruptEndpoint 3 中断端点
Direction
Read 输入 设备到主机方向
Write 输出 主机到设备方向
ReadWrite 双向 双向传输

5.2 公共方法

方法 返回值 说明
setType(type) void 设置端点类型(Bulk/Interrupt/Control)
setDirection(dir) void 设置传输方向
setMaxPacketSize(size) void 设置最大包大小
type() EndpointType 获取端点类型
direction() Direction 获取传输方向

5.3 使用示例

cpp

复制代码
QUsbEndpoint endpoint;
endpoint.setType(QUsbEndpoint::InterruptEndpoint);
endpoint.setDirection(QUsbEndpoint::ReadWrite);
device.setEndpoint(endpoint);
device.open(QIODevice::ReadWrite);

6、快速参考卡片

主要用途 关键方法
QUsb 设备管理与热插拔 devices(), findDevices(), 信号 deviceAdded/Removed
QUsbDevice 设备读写与控制 open(), read(), write(), controlTransfer(), 信号 readyRead
QUsbDeviceInfo 设备信息存储 vendorId, productId, product, serialNumber
QUsbDeviceFilter 设备筛选 setVendorId(), setProductId(), matches()
QUsbEndpoint 端点配置 setType(), setDirection(), setMaxPacketSize()

7、使用注意事项

  1. 错误处理 :USB 操作可能因多种原因失败,务必检查返回值并使用 errorString() 获取错误详情

  2. 异步优先 :在 UI 应用中使用 readyRead 信号而非同步 read(),避免界面卡顿

  3. 资源释放 :应用退出前调用 close() 正确释放 USB 资源

  4. 权限配置

    • Linux:配置 udev 规则 /etc/udev/rules.d/99-usb.rules

    • Windows:使用 Zadig 安装 WinUSB 驱动

    • macOS:在 Info.plist 中添加 USB 访问权限描述

三、环境搭建

Linux (Ubuntu) 安装

方式一:通过 PPA 安装(推荐)

bash

复制代码
sudo add-apt-repository ppa:fpoussin/ppa
sudo apt update
sudo apt install libqt5usb5 libqt5usb5-dev

方式二:从源码编译

bash

复制代码
# 安装依赖
sudo apt-get install libusb-1.0-0-dev libhidapi-dev pkg-config

# 克隆并编译
git clone https://github.com/fpoussin/QtUsb.git
cd QtUsb
mkdir build && cd build
qmake ..
make
sudo make install

Windows 安装

  1. 从项目的 Releases 页面 下载预编译包,如 v0.7.0-qt5.15-usb-msvc-dynamic-x64.7z

  2. 解压后,将对应文件复制到 Qt 安装目录:

    • include/QtUsbQt/版本/编译器/include/

    • lib/*.lib*.prlQt/版本/编译器/lib/

    • bin/*.dll*.pdbQt/版本/编译器/bin/

    • mkspecs/modules/*.priQt/版本/编译器/mkspecs/modules/

Windows 驱动问题 :如果设备使用 WinUSB/libusb 驱动,可能需要使用 Zadig 工具将设备驱动替换为 WinUSB 或 libusb-win32。

使用 Zadig 工具安装驱动 # 下载 Zadig,将设备驱动替换为 WinUSB 或 libusb-win32 # 下载地址:https://zadig.akeo.ie/

四、在 Qt 项目中配置

环境搭建与库集成

安装底层依赖,QtUsb 依赖于 libusblibhidapi,需要先安装它们。

获取并编译 QtUsb

  • 克隆仓库:

    bash

    复制代码
    git clone https://github.com/fpoussin/QtUsb.git
  • 编译与安装 (Unix 系统):

    bash

    复制代码
    cd QtUsb
    mkdir build && cd build
    qmake ..
    make && sudo make install

    在 Windows 上,可以使用项目提供的 build_msvc.bat 脚本进行编译。

在 Qt 项目中集成

集成方式主要分为两种,推荐使用第一种:

集成方式 操作步骤 优点
作为库(推荐) 1. 将预编译好的文件(includelibbinmkspecs)复制到 Qt 安装目录对应的文件夹下。 2. 在项目的 .pro 文件中添加 QT += usb 模块化管理,升级方便。
作为源码 1. 将 QtUsb/src 目录复制到你的项目中。 2. 在 .pro 文件中通过 include(qtusb/src/usb/files.pri) 将其包含。 无需预编译,部署简单,但可能与特定 Qt 版本绑定。

在项目的 .pro 文件中添加:

qmake

复制代码
QT += core usb

如果使用 CMake:

cmake

复制代码
find_package(Qt6 REQUIRED COMPONENTS Core Usb)
target_link_libraries(your_target Qt::Core Qt::Usb)

五、代码示例

开发流程

1. 设备枚举与过滤

首先,需要找到并识别目标 USB 设备。

cpp

复制代码
#include <QUsb>
#include <QDebug>

QUsb usbManager;
// 获取所有连接的USB设备列表
QList<QUsbDeviceInfo> devices = usbManager.devices();

// 使用过滤器按VID和PID查找特定设备
QUsbDeviceFilter filter;
filter.setVendorId(0x1234); // 替换为你的设备的VID
filter.setProductId(0x5678); // 替换为你的设备的PID
QList<QUsbDeviceInfo> targetDevices = usbManager.findDevices(filter);

2. 打开设备并进行配置

找到目标设备后,打开它并获取一个 QUsbDevice 对象以进行后续操作。

cpp

复制代码
// 使用过滤后的设备信息打开设备
QUsbDevice *device = usbManager.openDevice(targetDevices.first());
if (device && device->isOpen()) {
    qDebug() << "设备打开成功!";
    // 可以进行后续的读写操作了
} else {
    qCritical() << "设备打开失败,请检查权限或连接。";
}

3. 数据传输

QtUsb 支持多种传输类型,最常用的是批量传输和中断传输。

异步读取(推荐,避免界面卡顿)

cpp

复制代码
// 连接 readyRead 信号到槽函数
connect(device, &QUsbDevice::readyRead, this, [device](){
    QByteArray data = device->readAll();
    qDebug() << "收到数据:" << data.toHex();
});

// 写入数据
QByteArray writeData = QByteArray::fromHex("01020304");
qint64 bytesWritten = device->write(writeData);

同步读取

cpp

复制代码
QByteArray readBuffer(64, 0);
qint64 bytesRead = device->read(readBuffer.data(), readBuffer.size());
if (bytesRead > 0) {
    qDebug() << "同步读取到数据:" << readBuffer.toHex();
}

控制传输(用于发送命令)

cpp

复制代码
QByteArray requestData;
requestData.append(0x01); // 示例命令字节
QByteArray responseData = device->controlTransfer(
    QUsbDevice::EndpointOut, // 传输方向
    0x01,                    // bRequest
    0x0000,                  // wValue
    0x0000,                  // wIndex
    requestData,
    1000                     // 超时时间(ms)
);

4. 热插拔事件处理

通过 Qt 的信号槽机制,可以轻松实现设备的热插拔检测。

cpp

复制代码
// 连接设备插入和移除信号
connect(&usbManager, &QUsb::deviceInserted, this, [](const QUsbDeviceInfo &info){
    qDebug() << "设备已插入:" << info.product;
});
connect(&usbManager, &QUsb::deviceRemoved, this, [](const QUsbDeviceInfo &info){
    qDebug() << "设备已移除:" << info.product;
});

5. 错误处理与资源释放

完善的错误处理和资源管理是程序健壮性的保证。

cpp

复制代码
// 在读写操作后检查错误
if (device->error() != QUsbDevice::NoError) {
    qWarning() << "USB 操作出错:" << device->errorString();
    // 执行重试或断开操作
}

// 在程序退出或不再使用设备时,务必关闭并释放资源
void cleanup() {
    if (device) {
        device->close();
        delete device;
        device = nullptr;
    }
}

6. 示例代码

复制代码
#include <QCoreApplication>
#include <QUsb>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    
    // 枚举所有 USB 设备
    QUsb usb;
    QList<QUsbDeviceInfo> devices = usb.devices();
    
    qDebug() << "找到" << devices.count() << "个USB设备:";
    for (const QUsbDeviceInfo &device : devices) {
        qDebug() << QString("VID: 0x%1, PID: 0x%2")
                    .arg(device.vid, 4, 16, QChar('0'))
                    .arg(device.pid, 4, 16, QChar('0'));
    }
    
    // 打开指定设备
    // 通过 VID(Vendor ID,厂商 ID)和 PID(Product ID,产品 ID)查找特定设备
    auto usbDevice = QUsb::open(0x1234, 0x5678);  // 替换为你的 VID/PID
    if (usbDevice) {
        qDebug() << "设备打开成功";
        
        // 读取数据
        QByteArray readBuffer(64, 0);
        if (usbDevice->read(readBuffer.data(), 64) > 0) {
            qDebug() << "读取到数据:" << readBuffer.toHex();
        }
        
        // 写入数据
        QByteArray writeBuffer = QByteArray::fromHex("01020304");
        usbDevice->write(writeBuffer);
    }
    
    return a.exec();
}

六、常见问题与解决

问题 解决方案
找不到 QUsb 头文件 确认 .pro 中已添加 QT += usb,且 QtUsb 已正确安装
Windows 下无法打开设备 使用 Zadig 将设备驱动替换为 WinUSB 或 libusb-win32
Linux 下权限不足 创建 udev 规则文件 /etc/udev/rules.d/99-usb.rules,添加 SUBSYSTEM=="usb", ATTRS{idVendor}=="xxxx", MODE="0666"
编译时 undefined reference 检查是否链接了 libusb:LIBS += -lusb-1.0
如何获取设备的 VID 和 PID 在开始编写代码前,你需要先知道目标设备的 VID 和 PID。 Windows 1. 打开 设备管理器。 2. 找到你的设备,右键点击并选择 属性。 3. 切换到 详细信息 选项卡,在 属性 下拉列表中选择 硬件 ID。 4. 在 的窗口中,你会看到类似 USB\VID_1234&PID_5678 的字符串,12345678 就是对应的 VID 和 PID。 Linux 1. 打开一个终端。 2. 输入命令 lsusb。 3. 在输出结果中找到你的设备,你会看到类似 ID 1234:5678 的格式,冒号前是 VID,冒号后是 PID。

七、跨平台部署与调试

这是确保你的应用在其他操作系统上也能正常工作的关键步骤。

1. 处理不同平台的权限问题

  • Linux : 需要创建 udev 规则文件,赋予普通用户访问设备的权限。创建 /etc/udev/rules.d/99-myusb.rules 文件,内容如下:

    text

    复制代码
    SUBSYSTEM=="usb", ATTR{idVendor}=="1234", ATTR{idProduct}=="5678", MODE="0666"

    之后运行 sudo udevadm control --reload-rules 使规则生效。

  • Windows : 使用 Zadig 工具将你的 USB 设备驱动替换为 WinUSBlibusb-win32,这样 QtUsb 才能访问它。

  • macOS : 需要在应用的 Info.plist 文件中添加 USB 权限描述字符串。

2. 调试与优化

  • 使用调试版本 : 编译 QtUsb 时,在 CMake 或 qmake 命令中添加 CONFIG+=debug-DCMAKE_BUILD_TYPE=Debug,可以生成包含调试信息的库,便于定位问题。

  • 异步操作优先 : 在 UI 线程中避免使用同步的 USB 读写操作,应优先使用 readyRead 信号和 write 槽函数的异步方式,防止界面假死。

  • 缓冲区优化 : 对于大批量数据传输,可以通过 device->setReadBufferSize(size) 设置一个合适的读取缓冲区大小,通常设为端点最大包大小的整数倍,以提升吞吐量。

八、进阶资源推荐

  1. QtUsb 项目地址git clone https://gitcode.com/gh_mirrors/qt/QtUsb

  2. 官方文档Boot2QtUSB 访问配置指南

  3. 示例项目:USB 调试助手

    软件名称 下载地址 说明
    USB调试助手 (QT版) GitCode下载页面 开源项目,点击仓库中的下载链接获取最新版本,支持Windows/Linux/macOS。
    BusHound GitCode下载页面 知名USB分析工具,该页面提供了v6.0.1版本的下载链接。
    CEIWEI USB抓包 官方下载页面 官方提供百度网盘下载(提取码: 3k00),支持Win7至Win11。
    Device Monitoring Studio 官方网站 商业软件,需从官网下载,可先试用。
    Wireshark 官方下载页面 最流行的网络协议分析器,下载时请选择4.0以上版本以获得更好的USB支持 。
    USB3CV USB-IF官方目录 USB官方合规性测试工具,选择最新版 .exe 文件下载即可。
    ADB (Platform Tools) Android开发者官网 安卓调试官方工具包,解压后配置环境变量即可使用。
    Bugjaeger (移动端ADB) Apple App Store 运行在iOS设备上的ADB工具,用于调试其他安卓设备。
相关推荐
森G2 小时前
48、柱状图---------QChart
c++·qt
Larry_Yanan4 小时前
Qt+OpenCV(一)环境搭建
开发语言·c++·qt·opencv·学习
女王大人万岁5 小时前
Golang实战gRPC与Protobuf:从入门到进阶
服务器·开发语言·后端·qt·golang
sycmancia5 小时前
Qt——计算器示例(用户界面与业务逻辑的分离)
开发语言·qt·ui
charlie1145141916 小时前
现代Qt开发——0.1——如何在IDE中配置Qt环境?
开发语言·c++·ide·qt·嵌入式
Dovis(誓平步青云)6 小时前
《QT学习第二篇:QT的常用控件属性与按钮、view系列、Label、输入框》
开发语言·qt·学习
黎相思17 小时前
音乐播放器
qt
森G1 天前
46、环境配置---------QChart
c++·qt
冉佳驹1 天前
Qt【第六篇】 ——— 事件处理、多线程、网络与文件等操作详解
qt·http·udp·tcp·事件·多线程与互斥锁