前言
对于QT,想使用 HID 一般需引入外部库,常见的库有两个:
①hidapi:https://github.com/signal11/hidapi
②libhid:https://github.com/libusb/hidapi
但是这两个的配置我均遇到了各种困难,折腾很久没有成功,最后偶然发现了一个很小众的,叫做HidApi,成功配置。链接如下:
HidApi库:https://github.com/yigityuce/HidApi
下载与配置
直接把代码下载下来就可以,然后把cpp文件和h文件添加进工程即可。
然后编译时可能会遇到类似于 “无法将参数从const char转换为LPCWSTR” 的错误,这大概是由于QT的字符集的问题,可参考 https://blog.csdn.net/caoshangpa/article/details/52698238 这个文章解决,简而言之就是禁用Unicode,即在.pro文件里加上
DEFINES -= UNICODE 或者 DEFINES -= UNICODE _UNICODE
之后再编译,可能还有个undefined reference to `_imp__SetupDiGetClassDevsA@16’的错误,我查到的解决方法是在.pro文件里加上
LIBS += -lsetupapi
我遇到的问题主要如上,之后应该就能编译成功了。
基本使用
代码中提供了 main.cpp 和 README.md 文件,可以从中参考使用方法。下面按照我个人的理解,介绍最基本的用法。
首先是建立三个对象:
HidApi hidApi;
HidDevice hidDev;//HID设备
HidDeviceList devList;//HID设备列表
可以使用以下函数检查 hidApi 是否正常初始化:
hidApi.isInitialized();
然后对 HID 设备进行扫描,存入列表,并选择需要进行通信的赋给 hidDev:
devList = hidApi.scanDevices();
/* scanDevices 函数的定义:
HidDeviceList HidApi::scanDevices(unsigned short _vendorId,
unsigned short _productId,
const wchar_t* _serial,
const wchar_t* _manufacturer,
const wchar_t* _product,
unsigned short _release,
unsigned short _usagePage,
unsigned short _usage)
*/
for(size_t i = 0; i < devList.size(); i++)//可打印扫描到的设备的信息
{
std::wcout << i + 1 << ". DEVICE\n"
<< "Path : " << devList[i].getPath().c_str() << std::endl
<< "Vendor Id : " << devList[i].getVendorId() << std::endl
<< "Product Id : " << devList[i].getProductId() << std::endl
<< "Serial : " << devList[i].getSerial() << std::endl
<< "Manufacturer: " << devList[i].getManufacturer() << std::endl
<< "Product : " << devList[i].getProductString() << std::endl
<< "Release No : " << devList[i].getRelease() << std::endl
<< "Usage Page : " << devList[i].getUsagePage() << std::endl
<< "Usage : " << devList[i].getUsage() << std::endl
<< "Interface : " << devList[i].getInterface() << std::endl
<< "-----------------------------------------------" << std::endl;
if(/*假如 devList[i] 就是要通信的那个*/) hidDev = devList[i];
}
scanDevices 函数支持通过参数来对设备进行过滤,保留自己想要的,若不写参数则不过滤。
接下来就可以与 hidDev 进行通信:
std::string hidWriteStr;//存储发送数据
hidWriteStr.resize(65, 0);//重置为65字节
//无论读写,上位机似乎要比下位机定义的多1字节,最开头的字节总是0
for(int i = 0; i <= 64; i++) hidWriteStr[i] = i;//数据示例
if(hidDev.isInitialized()){
bool isOpen = hidDev.open();//打开设备
if(isOpen){//若打开成功
hidDev.write(hidWriteStr);//向设备写数据,返回写入的长度
if(hidDev.readAvailable()){//假如有数据可读
std::string hidReadStr = hidDev.read(-1);//从设备读取数据
}
//read函数参数为超时时间,单位ms,若<0则为阻塞
}
hidDev.close();//关闭设备
}