玩转USB HID系列:Linux下使用C语言和libusb开发USB HID

玩转USB系列:Linux下使用C语言和libusb开发USB HID

  • 实验环境
  • 开发步骤
    • 安装libusb
    • 试试好用否
    • 我们来与HID设备通讯!
  • 探索、学习与注意:
    • 1.&ctx是个什么鬼
    • 2.print_devs(devs)->print_devs(&devs);
    • 3.操作端口这类程序加上sudo !
    • 4.libusb_interrupt_transfer这个函数是write和read一体的!
    • 5.找不到函数报错的时候别急查网上,把头文件打开搜索一下更管用!
    • 6.终端清屏指令

实验环境

  1. ubuntu 16.04 LTS 64-bit
  2. gcc,vim
  3. STM32做下位机

开发步骤

安装libusb

sudo apt-get install libusb-1.0-0

注意:我在网上找到了多个安装教程写的安装命令和我的不一样:

  1. sudo apt-get install libusb-dev
  2. sudo apt-get install libusb-1.0-0-dev

这些命令安装的libusb我没有探索过,但有一点我知道,也是特容易踩坑的地方:
不同的libusb引用的头文件和函数还有编译时加的库名有细微的区别!!坑死我了
而好多教程都是上来就列代码,这就导致我们在看文章的时候觉得挺好,但是在自己机器上就是找不到函数或者头文件或者编译不过去等等…

本文章下面都以sudo apt-get install libusb-1.0-0为例子

试试好用否

我们来先试一试列出usb设备:

#include 
#include 
#include 

static void print_devs(libusb_device **devs)  
{  
    libusb_device *dev;  
    int i = 0;  
  
    while ((dev = devs[i++]) != NULL) {  
        struct libusb_device_descriptor desc;  
        int r = libusb_get_device_descriptor(dev, &desc);  
        if (r < 0) {  
            fprintf(stderr, "failed to get device descriptor");  
            return;  
        }  
  
        printf("%04x:%04x (bus %d, device %d)\n",  
            desc.idVendor, desc.idProduct,  
            libusb_get_bus_number(dev), libusb_get_device_address(dev));  
    }  
}  

int main()
{
	int r;
	ssize_t cnt;
	libusb_device **devs;                         //devices
	r=libusb_init(NULL);                          //init 初始化libusb
        if(r<0) {
            printf("failed to init libusb\n");
            return 1;
        }
	cnt = libusb_get_device_list(NULL,&devs);      //获取设备列表
        if (cnt < 0) {
            printf("failed to get device list\n");  
            return 1;
        }
	print_devs(devs);
	return 0;
}

保存,然后编译:注意!!编译的时候加上库名,就像这样

gcc hid_test_show.c -o hid -lusb-1.0

编译后执行:
看起来是不是和lsusb命令很像?

玩转USB HID系列:Linux下使用C语言和libusb开发USB HID_第1张图片
这一步正确了,就证明libusb已经安装可以使用了,往下!

我们来与HID设备通讯!

我的STM32信息:
interface 0
END POINT 0x01: OUT
END POINT 0x82: IN
包大小:64 byte

完成功能:PC机向STM32写入2个字节(查询命令)
STM32返回5个字节:[0]:数据长度(这里应该为4)[0]-[4]:一个double的电压值的内存形式

上代码:

#include 
#include 
#include 

static void print_devs(libusb_device **devs)  
{  
    libusb_device *dev;  
    int i = 0;  
  
    while ((dev = devs[i++]) != NULL) {  
        struct libusb_device_descriptor desc;  
        int r = libusb_get_device_descriptor(dev, &desc);  
        if (r < 0) {  
            fprintf(stderr, "failed to get device descriptor");  
            return;  
        }  
  
        printf("%04x:%04x (bus %d, device %d)\n",  
            desc.idVendor, desc.idProduct,  
            libusb_get_bus_number(dev), libusb_get_device_address(dev));  
    }  
}  

int main()
{
	int r;
	ssize_t cnt;
	libusb_device_handle *dev_handle;             //a device handle
	libusb_device **devs;                         //devices
	//libusb_context **ctx=NULL;	
	r=libusb_init(NULL);                          //init 初始化libusb
        if(r<0) {
            printf("failed to init libusb\n");
            return 1;
        }
	cnt = libusb_get_device_list(NULL,&devs);      //获取设备列表
        if (cnt < 0) {
            printf("failed to get device list\n");  
            return 1;
        }
	//print_devs(devs);
        dev_handle = libusb_open_device_with_vid_pid(NULL, 0x0483, 0xa010); 
	if(dev_handle == NULL){
		printf("Cannot open device\n");
		return 1;
	}else
		printf("Device Opened\n");

	libusb_free_device_list(devs, 1);             //free the list, unref the devices in it
	
	if(libusb_kernel_driver_active(dev_handle, 0) == 1) { //find out if kernel driver is attached
		printf("Kernel Driver Active\n");
		if(libusb_detach_kernel_driver(dev_handle, 0) == 0) //detach it
			printf("Kernel Driver Detached!\n");
	}
	r = libusb_claim_interface(dev_handle, 0);         //claim interface 0 (the first) of device (mine had jsut 1)
	if(r < 0) {
		printf("Cannot Claim Interface\n");
		return 1;
	}
	printf("Claimed Interface\n");
	sleep(1);	
	unsigned char data[2];
	union f_to_char{
	char chr[4];
	float ft0;
	}temp_union;
	unsigned char tmp_char[64];
	data[0]=0x02;data[1]=0x64;
	int actual; //used to find out how many bytes were written
	while(1){
		r = libusb_interrupt_transfer(dev_handle, (0x01 | LIBUSB_ENDPOINT_OUT), data, 2, &actual, 0); //my device's out endpoint was 1, found with trial- the device had 2 endpoints: 2 and 129
		if(r == 0 && actual == 2) //we wrote the 2 bytes successfully
			printf("Writing Successful\n");
		else
			printf("Write Error\n");
	
		r = libusb_interrupt_transfer(dev_handle, (0x82 | LIBUSB_ENDPOINT_IN),tmp_char,64,&actual, 1000);//pay attion
		
		if(r == 0 && actual == 64) //we read the 64 bytes successfully
			printf("Read Successful\n");
		else
			printf("Read Error\n");
		//printf("%i,%i\n",r,actual);
		temp_union.chr[0]=tmp_char[1];
		temp_union.chr[1]=tmp_char[2];
		temp_union.chr[2]=tmp_char[3];
		temp_union.chr[3]=tmp_char[4];
		printf("The volt is %f mV\n",temp_union.ft0);
		usleep(1000*500);		
		printf("%s","\033[1H\033[2J");//clear display
		
	}	
	
	r = libusb_release_interface(dev_handle, 0); //release the claimed interface
	if(r!=0) {
		printf("Cannot Release Interface\n");
		return 1;
	}
	printf("Released Interface\n");

	libusb_close(dev_handle);                    //close the device we opened
	libusb_exit(NULL);                            //needs to be called to end the
	
	return 0;
}

探索、学习与注意:

1.&ctx是个什么鬼

(代码中调用libusb接口函数需要先建立上下文环境,其中结构体struct libusb_context代表一段libusb的会话,官方文档中有对这个结构的说明。
libusb_init()表示开启会话,libusb_exit()表示结束会话。通俗的理解就是struct libusb_context* ctx中的ctx代表一把钥匙,libusb_init(&ctx)表示开启,libusb_exit(null)表示锁上。)
这段解释来自网上,但是,我对其存疑!
因为,有另一篇帖子代码上所有的ctx位置全部给的NULL

我当前代码中全部ctx位置全部给的NULL,目前没发现问题。

2.print_devs(devs)->print_devs(&devs);

执行就显示这个(这个就是偶然写错了发现的~)
在这里插入图片描述

3.操作端口这类程序加上sudo !

    dev_handle = libusb_open_device_with_vid_pid(ctx, 0x0483, 0xa010); 
	if(dev_handle == NULL){
		printf("Cannot open device\n");
		return 1;
	}else
		printf("Device Opened\n");

找不到设备的时候先检查sudo加没加,不一定是设备不正常
不加sudo会Cannot open device,加上才打的开

4.libusb_interrupt_transfer这个函数是write和read一体的!

我当初找了半天读写函数在哪里,害!

5.找不到函数报错的时候别急查网上,把头文件打开搜索一下更管用!

之前已经说过了,libusb的函数有一些细微区别,还是自己看所安装libusb的文档或者头文件吧~

6.终端清屏指令

printf("%s","\033[1H\033[2J");//clear display

你可能感兴趣的:(玩转USB,STM32,Linux,usb,stm32,linux,c语言)