QT调用HIDAPI进行 USB-HID设备通信

目录

一、引用hidapi库

二、创建 设备句柄

三、初始化

四、函数说明

(1)hid_open 打开

(2)hid_set_nonblocking 设置阻塞模式

(3)hid_read 读取

(4)hid_write写入

(5)其他函数

五、总结


一、引用hidapi库

QT中引用库的方式分为隐式调用和显式调用,也就是动态库和静态库。下面是在工程中添加的数据

 #在工程中添加库路径
  LIBS += -L$$PWD/DLL/ -lhidapi
  
  HEADERS += hidapi.h

二、创建 设备句柄

创建句柄就是方便对设备进行访问,类似描述符。

private: 
 hid_device *handle ; 

三、初始化

初始化步骤比较简单,调用hidapi库的初始化函数就行了,不调用也可以,反正在hid_open函数也会调用。

其中值得注意的是hid_read需要调用才能读取数据,没用触发事件,在QT中一般习惯了信号和槽,但很可惜没用触发事件,我这里使用的方法是开一个线程,循环的读取hid_read函数,来判断是否有数据到达。

 //1.初始化
 hid_init();   

 //2.打开设备 
handle = hid_open(    0x303a, 0x4012,NULL); 
 
 static unsigned char sendDATA[64] ;

// 3.发送数据
 int res = hid_write(handle, sendDATA, sizeof(sendDATA));  
// 4.读取数据
 int res = hid_read(handle, sendDATA, sizeof(sendDATA));  

四、函数说明

(1)hid_open 打开

打开的方式有两种,一种是hid_open以vid,pid的方式打开,还有一种的以路径的方式打开,具体看下面吧。

hid_device *  hid_open(unsigned short vendor_id,
                              unsigned short product_id, 
                              const wchar_t *serial_number);
/*
@参数1:VID 
@参数2:PID  
@参数3:设备序列号 (一般NULL即可,默认选第一个)
@返回值返回一个对象指针,NULL是打开失败   
*/ 

//另一个打开方式 通过路径打开
 hid_device *  hid_open_path(const char *path);
 这里要比hid_open多一个查找
 (1)hid_device_info *devs = hid_enumerate(0x303a, 0x4012);
 (2) hid_device * hid_handle = open_path(devs); 

(2)hid_set_nonblocking 设置阻塞模式

    设置阻塞模式,其实就是设置读取的时候,是否阻塞,设置成非阻塞的话,没用数据会执行后面的程序。

是否阻塞这个是我其中遇到调试一个问题,讲完函数在最后说一下注意事项。

int hid_set_nonblocking(hid_device *dev, int nonblock);
/*
@参数1:对象句柄 
@参数2:阻塞模式-非阻塞模式
 - 1 to enable nonblocking
 - 0 to disable nonblocking.    
@ 0 成功
@-1 失败   
*/  

(3)hid_read 读取

  读取的注意事项就是申请的大小可以跟USBhid设置设置成一样或者大一些

int hid_read(hid_device *dev, unsigned char *data, size_t length);
/*
@参数1:对象句柄
@参数2:存放读取的数据地址  
@参数3:长度
@返回值  读取长度   -1读取失败
*/ 

(4)hid_write写入

 函数说明如下:

int hid_write(hid_device *dev, const unsigned char *data, size_t length);
/*
@参数1:对象句柄
@参数2:写入的数据地址  
@参数3:写入长度
@返回值  写入长度   -1读取失败
*/

 程序使用的发送例子如下,  frm是CAN数据,自行按自定义格式就行。

注意发送的第一个字节需要跟 USB-hid设备的报告ID一致,例如我这次的hid设备就是0x03,后面的就是自定义数据了。


   static unsigned char USB_BUF[64] = { 0 };
   memset(USB_BUF,0,sizeof(USB_BUF));

   int count       = 0;
   unsigned int ID = frm->ID;
   USB_BUF[count++] = 0x03;
   USB_BUF[count++] = 0x0;
   USB_BUF[count++] = 0xff;


   for(int i = 0 ; i < 4 ; i++)
   {
      USB_BUF[count++] = ( ID >> ((3-i)*8) )&0xFF;
   }

   USB_BUF[count++] = frm->RemoteFlag;
   USB_BUF[count++] = frm->ExternFlag;
   USB_BUF[count++] = frm->DataLen;

   if(frm->DataLen < 9)
   for(int i = 0 ;i <  frm->DataLen ;i++)
        USB_BUF[(count++)] = frm->Data[i];


   int res;
  // res =  hid_send_feature_report(Usb_handle,USB_BUF,sizeof(USB_BUF));
   res =  hid_write(Usb_handle,USB_BUF,sizeof(USB_BUF));

(5)其他函数

   剩下的函数用到再查吧 ,总的来说,利用库实现HID在QT中不难
  主要是配合esp32和STM32的HID实现免驱通信,有时间搞一下ST的例子

<1>
struct hid_device_info *  hid_enumerate(unsigned short vendor_id, unsigned short product_id);
//简单概括就是 传入需要查找的VID和PID   返回一个 对象结构体
//当VID 和PID 都是 0 的时候,则搜索全部的HID设备  ,具体的可以通过对象的next访问到下一个对象
//下面是具体的介绍  
/** @brief Enumerate the HID Devices.
			This function returns a linked list of all the HID devices
			attached to the system which match vendor_id and product_id.
			If @p vendor_id is set to 0 then any vendor matches.
			If @p product_id is set to 0 then any product matches.
			If @p vendor_id and @p product_id are both set to 0, then
			all HID devices will be returned.

			@ingroup API
			@param vendor_id The Vendor ID (VID) of the types of device
				to open.
			@param product_id The Product ID (PID) of the types of
				device to open.
		    @returns
		    	This function returns a pointer to a linked list of type
		    	struct #hid_device_info, containing information about the HID devices
		    	attached to the system, or NULL in the case of failure. Free
		    	this linked list by calling hid_free_enumeration().
		*/
<2>
//简单概括一下就是发送特征报告的
int  hid_send_feature_report(hid_device *dev,
                            const unsigned char *data,
                            size_t length);

<3>
//简单概括一下就是获取特征报告的
int hid_get_feature_report(hid_device *dev,
                         unsigned char *data,
                          size_t length);

<4>
//获取序列号字符串
int  hid_get_serial_number_string(hid_device *dev, 
                           wchar_t *string,
                            size_t maxlen);

五、总结

      调试过程中主要是下位机的问题,想更方便看到效果, 可以买一个HID模块,本次调试中用到ch9326模块和Bus Hound进行调试。

 遇到的问题:

     1.刚开始调试的时候,没用考虑阻塞的问题,打开程序的时候设置的非阻塞,当手动关闭的时候再打开的时候没用设置非阻塞,导致hid_read函数阻塞导致整个ui阻塞了

     2.由于新接触hid的免驱设备,在调试的时候最好还是先确保一方设备没问题,再调试,刚开始跟同事调试的时候发现,死活连接不上,原来是esp32 usb-hid描述符配置有问题导致,后面买了个新设备调试,发现可以连接上,并能发送。

以下是hidapi库 链接,提取码:tang

hidapi链接

  • 5
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值