版权声明:本文为博主原创文章,转载注明出处 https://blog.csdn.net/u010875635/article/details/71305410
使用libusb可以实现通用的usb通信,但是实现较为复杂,可以使用hidapi来封装一层,通过hidapi调用libusb。
具体流程如下:
1、编译libusb
下载地址:https://sourceforge.net/projects/libusb/files/libusb-1.0/
编译时,要加 --disable-udev参数,我们不使用这个lib
若是给本机使用:
若是交叉编译给arm开发板用
2、复制lib到系统lib环境中
3、使用hidapi
下载地址:https://github.com/signal11/hidapi/downloads,下载0.7版本
解压之后会发现里面有很多文件夹,例如hidapi, hidtest, linux, windows,其中hidapi是共用部分,linux下面有makefile,可以编译出linux下可以使用的hid读写的hidtest程式,读写的对象是vid为0x04d8,pid为0x003f。
编译demo需要修改makefile以支持我们编译的libusb路径查找。
修改内容如下:
然后make & make install
如果使用Qt,则复制3个文件,添加到工程中,hidapi文件夹下的hidapi.h,这个主要是结构体的封装,linux下的hid-libusb.c,这个主要是一些主体调用函数,hidtest中的hidtest.cpp,这个主要是测试的demo,可以直接修改自己使用,当然,不修改也可以使用demo。
编译是需要用到libusb,所以要在.pro文件中添加对应的头文件目录和lib目录,在最后面新增两行如下:
以下为C语言写法
修改hidtest.c为MainHidInterface.c和MainHidInterface.h
具体流程如下:
1、编译libusb
下载地址:https://sourceforge.net/projects/libusb/files/libusb-1.0/
编译时,要加 --disable-udev参数,我们不使用这个lib
若是给本机使用:
./configure --prefix=/opt/libusb1.0 --disable-udev
make
make install
若是交叉编译给arm开发板用
./configure --build=i686-linux --host=arm-linux --prefix=·pwd·/install CC=arm-linux-gcc CXX=arm-linux-g++ --disable-udev
make
make install
2、复制lib到系统lib环境中
cp /opt/libusb1.0/lib/libusb-1.0.so* /usr/lib
3、使用hidapi
下载地址:https://github.com/signal11/hidapi/downloads,下载0.7版本
解压之后会发现里面有很多文件夹,例如hidapi, hidtest, linux, windows,其中hidapi是共用部分,linux下面有makefile,可以编译出linux下可以使用的hid读写的hidtest程式,读写的对象是vid为0x04d8,pid为0x003f。
编译demo需要修改makefile以支持我们编译的libusb路径查找。
修改内容如下:
#LIBS = '`pkg-config libusb-1.0 libudev --libs`'
LIBS = -L"/usr/lib/x86_64-linux-gnu" -lusb-1.0 -lpthread
#INCLUDES ?= -I../hidapi `pkg-config libusb-1.0 --cflags`
INCLUDES ?= -I../hidapi -I/opt/libusb1.0/include/libusb-1.0
然后make & make install
如果使用Qt,则复制3个文件,添加到工程中,hidapi文件夹下的hidapi.h,这个主要是结构体的封装,linux下的hid-libusb.c,这个主要是一些主体调用函数,hidtest中的hidtest.cpp,这个主要是测试的demo,可以直接修改自己使用,当然,不修改也可以使用demo。
编译是需要用到libusb,所以要在.pro文件中添加对应的头文件目录和lib目录,在最后面新增两行如下:
INCLUDEPATH += /opt/libusb1.0/include/libusb-1.0
LIBS += -L"/usr/lib/x86_64-linux-gnu" -lusb-1.0
以下为C语言写法
修改hidtest.c为MainHidInterface.c和MainHidInterface.h
使用pthread来支持多线程读写,采用回调函数来返回读到的数据。
MainHidInterface.h
#ifndef DeltaHIDINTERFACE_H
#define DeltaHIDINTERFACE_H
#include <stdio.h>
#include <wchar.h>
#include <string.h>
#include <stdlib.h>
#include "hidapi.h"
// Headers needed for sleeping.
#include <unistd.h>
#define hidDataLength 64
//hid data receive callback function
typedef void (*DataArriveCallBackFunc)(unsigned char *recData,unsigned char length);
DataArriveCallBackFunc hidDataArriveCallBack;
hid_device *handle;
unsigned char isOpen;
int hidApi_Init(DataArriveCallBackFunc DataArriveCallBack);
int hidApi_Write(unsigned char *data, unsigned char length);
//when data arrived, the function will be called
void hidApi_DataReceive(unsigned char *recData,unsigned char length);
int hidApi_Close(void);
#endif // HIDINTERFACE_H
MainHidInterface.c
#include "hidinterface.h"
#include <pthread.h>
void hidRead_thread(void);
int hidApi_Init(DataArriveCallBackFunc DataArriveCallBack)
{
hidDataArriveCallBack = NULL;
// Open the device using the VID, PID,
// and optionally the Serial number.
////handle = hid_open(0x4d8, 0x3f, L"12345");
handle = hid_open(0x4d8, 0x3f, NULL);
if (!handle) {
printf("unable to open device\n");
isOpen = 0;
return -1;
}
printf("open device success\n");
isOpen = 1;
hidDataArriveCallBack = DataArriveCallBack;
hidRead_thread();
// Set the hid_read() function to be non-blocking.
hid_set_nonblocking(handle, 1);
return 0;
}
int hidApi_Write(unsigned char *data, unsigned char length)
{
int res;
unsigned char realData[length+1];
realData[0]=length;
int i;
for(i=0;i<length;i++)
{
realData[i+1]=data[i];
}
res = hid_write(handle, realData, length+1);
if (res < 0) {
printf("Unable to write()\n");
printf("Error: %ls\n", hid_error(handle));
return -1;
}
printf("write success\n");
return 0;
}
void hidApi_DataReceive(unsigned char *recData,unsigned char length)
{
if(hidDataArriveCallBack==NULL)
return;
hidDataArriveCallBack(recData,length);
}
void hidApi_Read()
{
unsigned char recData[hidDataLength];
int res;
while (isOpen==1) {
res = hid_read(handle, recData, hidDataLength);
if (res == 0)
;//printf("waiting...\n");
else if (res < 0)
{
printf("Unable to read()\n");
return -1;
}
else
{
int i;
// printf("Data read:\n ");
// // Print out the returned buffer.
//
// for (i = 0; i < res; i++)
// printf("%02hhx ", recData[i]);
// printf("\n");
unsigned char length = recData[0];
unsigned char datas[length];
for(i=0;i<length;i++)
{
datas[i]=recData[i+1];
}
hidApi_DataReceive(datas,length);
}
usleep(50*1000);
}
}
void hidRead_thread(void)
{
pthread_t id;
int ret, i;
ret=pthread_create(&id,NULL,(void *) hidApi_Read,NULL); // 成功返回0,错误返回错误编号
if(ret!=0) {
printf ("Create pthread error!\n");
exit (1);
}
//pthread_join(id,NULL);
printf ("Create pthread success!\n");
}
int hidApi_Close(void)
{
hid_close(handle);
isOpen = 0;
/* Free static HIDAPI objects. */
hid_exit();
return 0;
}
若想使用Qt C++,则要将pthread换成QThread来执行阅读,同时,不要再使用回调函数,因为回调函数不支持成员函数(含有默认指针this),仅支持static函数,不利于使用多个对象实例,可以使用信号与槽的机制将接收到的数据传输出来。
以下为Qt C++改写的范例,使用时要connect才能接收到数据。
MainHidInterface.h
MainHidInterface.cpp
MainHidInterface.h
#ifndef mMainHIDINTERFACE_H
#define mMainHIDINTERFACE_H
#include <iostream>
#include <QThread>
#include <QCoreApplication>
#include "hidapi.h"
// Headers needed for sleeping.
#include <unistd.h>
using namespace std;
#define hidDataLength 64
//typedef void (*DataRecCallbackFunc)(unsigned char *recData,unsigned char length);
class MainHidInterFace : public QThread
{
Q_OBJECT
public:
//Initial and set hid data receive callback function
MainHidInterFace();
int hidApi_Write(unsigned char *data, unsigned char length);
int hidApi_Close(void);
signals:
void hidDataArrived(unsigned char *data, unsigned char length);
private:
hid_device *handle;
unsigned char isOpen;
protected:
void run() ;
};
#endif // HIDINTERFACE_H
MainHidInterface.cpp
/*******************************************************
Windows HID simplification
Alan Ott
Signal 11 Software
8/22/2009
Copyright 2009, All Rights Reserved.
This contents of this file may be used by anyone
for any reason without any conditions and may be
used as a starting point for your own applications
which use HIDAPI.
********************************************************/
#include "hidinterface.h"
MainHidInterFace::MainHidInterFace()
{
// Open the device using the VID, PID,
// and optionally the Serial number.
////handle = hid_open(0x4d8, 0x3f, L"12345");
handle = hid_open(0x4d8, 0x3f, NULL);
if (!handle) {
printf("unable to open device\n");
isOpen = 0;
return;
}
printf("open device success\n");
isOpen = 1;
// Set the hid_read() function to be non-blocking.
hid_set_nonblocking(handle, 1);
emit hidDataArrived(NULL,0);
return;
}
int MainHidInterFace::hidApi_Write(unsigned char *data, unsigned char length)
{
int res;
unsigned char realData[length+1];
realData[0]=length;
int i;
for(i=0;i<length;i++)
{
realData[i+1]=data[i];
}
res = hid_write(handle, realData, length+1);
if (res < 0) {
printf("Unable to write()\n");
printf("Error: %ls\n", hid_error(handle));
return -1;
}
printf("write success\n");
return 0;
}
void MainHidInterFace::run()
{
unsigned char recData[hidDataLength];
int res;
while (isOpen==1) {
res = hid_read(handle, recData, hidDataLength);
if (res == 0)
;//printf("waiting...\n");
else if (res < 0)
{
printf("Unable to read()\n");
return;
}
else
{
int i;
// printf("Data read:\n ");
// // Print out the returned buffer.
//
// for (i = 0; i < res; i++)
// printf("%02hhx ", recData[i]);
// printf("\n");
unsigned char length = recData[0];
unsigned char datas[length];
for(i=0;i<length;i++)
{
datas[i]=recData[i+1];
}
emit hidDataArrived(datas,length);
}
usleep(50*1000);
}
}
int MainHidInterFace::hidApi_Close(void)
{
hid_close(handle);
isOpen = 0;
/* Free static HIDAPI objects. */
hid_exit();
delete handle;
return 0;
}