一、什么是 QtUsb
QtUsb 是一个专为 Qt 开发者设计的跨平台 USB 通信模块,底层基于成熟的 libusb-1.0 和 libhidapi 库实现。它封装了 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、使用注意事项
-
错误处理 :USB 操作可能因多种原因失败,务必检查返回值并使用
errorString()获取错误详情 -
异步优先 :在 UI 应用中使用
readyRead信号而非同步read(),避免界面卡顿 -
资源释放 :应用退出前调用
close()正确释放 USB 资源 -
权限配置:
-
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 安装
-
从项目的 Releases 页面 下载预编译包,如
v0.7.0-qt5.15-usb-msvc-dynamic-x64.7z -
解压后,将对应文件复制到 Qt 安装目录:
-
include/QtUsb→Qt/版本/编译器/include/ -
lib/*.lib、*.prl→Qt/版本/编译器/lib/ -
bin/*.dll、*.pdb→Qt/版本/编译器/bin/ -
mkspecs/modules/*.pri→Qt/版本/编译器/mkspecs/modules/
-
Windows 驱动问题 :如果设备使用 WinUSB/libusb 驱动,可能需要使用 Zadig 工具将设备驱动替换为 WinUSB 或 libusb-win32。
使用 Zadig 工具安装驱动 # 下载 Zadig,将设备驱动替换为 WinUSB 或 libusb-win32 # 下载地址:https://zadig.akeo.ie/
四、在 Qt 项目中配置
环境搭建与库集成
安装底层依赖,QtUsb 依赖于 libusb 和 libhidapi,需要先安装它们。
获取并编译 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. 将预编译好的文件(include、lib、bin、mkspecs)复制到 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 的字符串,1234 和 5678 就是对应的 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 设备驱动替换为 WinUSB 或 libusb-win32,这样 QtUsb 才能访问它。
-
macOS : 需要在应用的
Info.plist文件中添加 USB 权限描述字符串。
2. 调试与优化
-
使用调试版本 : 编译 QtUsb 时,在 CMake 或 qmake 命令中添加
CONFIG+=debug或-DCMAKE_BUILD_TYPE=Debug,可以生成包含调试信息的库,便于定位问题。 -
异步操作优先 : 在 UI 线程中避免使用同步的 USB 读写操作,应优先使用
readyRead信号和write槽函数的异步方式,防止界面假死。 -
缓冲区优化 : 对于大批量数据传输,可以通过
device->setReadBufferSize(size)设置一个合适的读取缓冲区大小,通常设为端点最大包大小的整数倍,以提升吞吐量。
八、进阶资源推荐
-
QtUsb 项目地址 :
git clone https://gitcode.com/gh_mirrors/qt/QtUsb -
官方文档 :Boot2QtUSB 访问配置指南
-
示例项目: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工具,用于调试其他安卓设备。