stm32 USB HID单点触摸屏上报安卓触摸信号

此工程在个人博客使用stm32配置自定义的HID设备基础上修改

  1. 在上个博客中我们介绍了如何使用stm32配置成自定义的HID设备,使用usb通讯,但是仅仅只是实现了基于USB的通讯,真正需要运用的时候还需要在此基础上定义我们自己的协议,然后按照我们自己的协议通讯才行,这样的话,仅限于你们自己的设备之间的通讯,有一定的局限性,因此我们还需要在此基础上改进。
    同时手上有个项目需要使用stm32通过usb制作成一个触摸屏,touch screen,网上资料都找遍了,基本没有找到什么特别有价值的资料,可能做这方面的人比较少吧
  2. 使用stm32做成触摸屏只需要在之前的使用stm32配置自定义的HID设备基础上修改HID描述符就行了,但是HID描述符并不是那么容易弄明白的东西,哪怕是我现在实现了一部分,也仅仅只是明白了一点点而已,hid描述符生成具体有什么样的格式要求什么的,我并没有找到详细的说明,网上有一些简单的说明(就是有本书的第八章)大家可以上网找下
  3. 那么我是怎么弄好的呢?只能说我运气好了,手上刚好有一块触摸屏,然后我就直接把它插在电脑上,然后使用USBlyzer去捕获它的所有数据,然后模拟!但是不要觉得这样很简单,接下来你就知道了
    USB 输入设备
    下面是我导出的捕获到的数据,大家可以好好分析下
    stm32 USB HID单点触摸屏上报安卓触摸信号_第1张图片
    stm32 USB HID单点触摸屏上报安卓触摸信号_第2张图片
    stm32 USB HID单点触摸屏上报安卓触摸信号_第3张图片
    stm32 USB HID单点触摸屏上报安卓触摸信号_第4张图片
    对照使用stm32配置自定义的HID设备这篇博文后面的描述符看前面的一部分还是没问题的,但是当看到HID报告描述符的时候你就应该感到绝望了,这个触摸屏插上电脑之后,扫描都到的端口都有五个,因此HID报告描述符肯定有5个!
    stm32 USB HID单点触摸屏上报安卓触摸信号_第5张图片
    那么直接拷贝它的HID描述符吗?
    感觉这么可以,但是实际使用后发现并不可行,因为在铜须时候有几个回复,stm32没做,导致出问题了,为什么没做呢,因为我们是用cubemx生成的,他没生成那一部分,我也不会,所以就没做了,那么大家会的话也可以自己加上,就不用这么纠结了!那么如果不加的话就需要对HID报告描述符进行修改了
  4. 我们通过usblyzer捕获按键按下时上传的时有了重要发现
  5. stm32 USB HID单点触摸屏上报安卓触摸信号_第6张图片

每次当我们触摸时都会上报ID为4的数据,且松开的时候上报的数据内容第二个字节由0x83变为了0x82
也就是第二个字节的第一位1->0
那么我们只需要借鉴其HID描述符中id为4 的那一部分就可以了,也就是下面这一部分
stm32 USB HID单点触摸屏上报安卓触摸信号_第7张图片
同时,我们去掉中间那一部分没有用的,从触摸时上报的数据解析中看到的那个in Range 、confidence和contact identifier
stm32 USB HID单点触摸屏上报安卓触摸信号_第8张图片
我也不清楚这三个是干嘛的,直接用常量替换掉,同时需要注意的是,按键有效的只有第一位,那么需要构成一个字节,所以还需要补充7位常量,然后后面再跟上x,y的坐标值就好了,那么我们参考id为04的hid描述符,自己使用hid descriptor tool工具制作一个hid描述符如下所示
stm32 USB HID单点触摸屏上报安卓触摸信号_第9张图片

char ReportDescriptor[68] = {
    0x05, 0x0d,                    // USAGE_PAGE (Digitizers)
    0x09, 0x04,                    // USAGE (Touch Screen)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x09, 0x22,                    //   USAGE (Finger)
    0xa1, 0x00,                    //   COLLECTION (Physical)
    0x09, 0x42,                    //     USAGE (Tip Switch)
    0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
    0x75, 0x01,                    //     REPORT_SIZE (1)
    0x95, 0x01,                    //     REPORT_COUNT (1)
    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
    0x75, 0x07,                    //     REPORT_SIZE (7)
    0x95, 0x01,                    //     REPORT_COUNT (1)
    0x81, 0x03,                    //     INPUT (Cnst,Var,Abs)
    0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
    0x09, 0x30,                    //     USAGE (X)
    0x75, 0x10,                    //     REPORT_SIZE (16)
    0x95, 0x01,                    //     REPORT_COUNT (1)
    0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x0f,              //     LOGICAL_MAXIMUM (4095)
    0x35, 0x00,                    //     PHYSICAL_MINIMUM (0)
    0x46, 0xff, 0x0f,              //     PHYSICAL_MAXIMUM (4095)
    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
    0x09, 0x31,                    //     USAGE (Y)
    0x95, 0x01,                    //     REPORT_COUNT (1)
    0x75, 0x10,                    //     REPORT_SIZE (16)
    0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x0f,              //     LOGICAL_MAXIMUM (4095)
    0x35, 0x00,                    //     PHYSICAL_MINIMUM (0)
    0x46, 0xff, 0x0f,              //     PHYSICAL_MAXIMUM (4095)
    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
    0xc0,                          // END_COLLECTION
    0xc0                           // END_COLLECTION
};

然后将生成的hid描述符替换掉以前的hid描述符,记得修改hid描述符数组的大小值

__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE]  __ALIGN_END =
{
    0x05, 0x0d,                    // USAGE_PAGE (Digitizers)
    0x09, 0x04,                    // USAGE (Touch Screen)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x09, 0x22,                    //   USAGE (Finger)
    0xa1, 0x00,                    //   COLLECTION (Physical)
    0x09, 0x42,                    //     USAGE (Tip Switch)
    0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
    0x75, 0x01,                    //     REPORT_SIZE (1)
    0x95, 0x01,                    //     REPORT_COUNT (1)
    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
    0x75, 0x07,                    //     REPORT_SIZE (7)
    0x95, 0x01,                    //     REPORT_COUNT (1)
    0x81, 0x03,                    //     INPUT (Cnst,Var,Abs)
    0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
    0x09, 0x30,                    //     USAGE (X)
    0x75, 0x10,                    //     REPORT_SIZE (16)
    0x95, 0x01,                    //     REPORT_COUNT (1)
    0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x0f,              //     LOGICAL_MAXIMUM (4095)
    0x35, 0x00,                    //     PHYSICAL_MINIMUM (0)
    0x46, 0xff, 0x0f,              //     PHYSICAL_MAXIMUM (4095)
    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
    0x09, 0x31,                    //     USAGE (Y)
    0x95, 0x01,                    //     REPORT_COUNT (1)
    0x75, 0x10,                    //     REPORT_SIZE (16)
    0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x0f,              //     LOGICAL_MAXIMUM (4095)
    0x35, 0x00,                    //     PHYSICAL_MINIMUM (0)
    0x46, 0xff, 0x0f,              //     PHYSICAL_MAXIMUM (4095)
    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
    0xc0,                          // END_COLLECTION
    0xc0                           // END_COLLECTION
}

然后在主程序中调用上报数据的api函数就可以了,
上报的内容第一个字节是0x01或者0x00,0x01代表按键有效
上报数据的2-3字节书x坐标
上报数据的4-5字节书y坐标
记得每次上报完按键按下之后需要上报一次按键未按下作为结束

uint8_t usb_send_buf[5]={0x01,0xA8,0x0A,0x6B,0x0A};
 while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  usb_send_buf[0]=0x01;
	  
	  for(i=0;i<64;i++)
	  {
		  usb_send_buf[1]=(((usb_send_buf[2]<<8)|usb_send_buf[1])-1)%256;
		  usb_send_buf[2]=(((usb_send_buf[2]<<8)|usb_send_buf[1])-1)/256;
		USBD_HID_SendReport(&hUsbDeviceFS,usb_send_buf,sizeof(usb_send_buf));
		HAL_Delay(7);	//必须要有短暂的延时 1ms都行		
	  }
	  
	  usb_send_buf[0]=0x00;
	  USBD_HID_SendReport(&hUsbDeviceFS,usb_send_buf,sizeof(usb_send_buf));
	  
	  usb_send_buf[1]=0xA8;
	  usb_send_buf[2]=0x0A;
	  
	  HAL_Delay(1000);
  }
  /* USER CODE END 3 */
}

烧录程序,之后大家可以 打开福昕pdf,随便开一个pdf,然后使用pdf的注释里面的画笔功能,之后别动鼠标(动鼠标会干扰usb模拟鼠标),然后可以看到每隔1s,鼠标会自己画一条横线
stm32 USB HID单点触摸屏上报安卓触摸信号_第10张图片

6.至此,stm32制作的触摸屏在电脑上已经可以使用了,但是如果插到安卓设备上,大家会发现,安卓上会出现一个鼠标图标,这是因为安卓根据设备符认为这是一个鼠标设备,但是我们想做的是一个触摸设备,我通过尝试修改HID描述符将USAGE改成Fingerstm32 USB HID单点触摸屏上报安卓触摸信号_第11张图片
重新烧录,在电脑上依旧可以使用,插上安卓,发现鼠标图标没有了,有触摸效果,但是感觉它摸的不正常,这肯定是不行的,没办法,那就直接拷贝我手上成品触摸屏的id为4的那部分HID设备描述符吧,即下图中我选中的部分,注意的是由于我们这只有一个hid描述,不需要id,所以大家把id那个删掉就好了
stm32 USB HID单点触摸屏上报安卓触摸信号_第12张图片
修改过的HID描述符

__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE]  __ALIGN_END =
{
    0x05, 0x0d,                    // USAGE_PAGE (Digitizers)
    0x09, 0x04,                    // USAGE (Touch Screen)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x09, 0x22,                    //   USAGE (Finger)
    0xa1, 0x00,                    //   COLLECTION (Physical)
    0x09, 0x42,                    //     USAGE (Tip Switch)
    0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
    0x75, 0x01,                    //     REPORT_SIZE (1)
    0x95, 0x01,                    //     REPORT_COUNT (1)
    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
	0x09 , 0x32, 
	0x15 , 0x00 ,
	0x25 , 0x01 ,
	0x81 , 0x02 ,
	0x09 , 0x51 ,
	0x75 , 0x05,
	0x95 , 0x01 ,
	0x16 , 0x00 , 0x00,
	0x26 , 0x10 , 0x00,
	0x81 , 0x02,
	0x09 , 0x47 ,
	0x75 , 0x01,
	0x95 , 0x01 ,
	0x15 , 0x00,
	0x25 , 0x01 ,
	0x81 , 0x02 ,
	0x05 , 0x01 ,
	0x09 , 0x30 ,
	0x75 , 0x10 ,
	0x95 , 0x01 ,
	0x55 , 0x0D,
	0x65 , 0x33,
	0x35 , 0x00,
	0x46 , 0x60 , 0x17 ,
	0x26 , 0xFF , 0x0F ,
	0x81 , 0x02 ,
	0x09 , 0x31 ,
	0x75 , 0x10 ,
	0x95 , 0x01 ,
	0x55 , 0x0D ,
	0x65 , 0x33 ,
	0x35 , 0x00 ,
	0x46 , 0x26 , 0x0E, 
	0x26 , 0xFF , 0x0F ,
	0x81 , 0x02 ,
	0x05 , 0x0D ,
	0x09 , 0x55 ,
	0x25 , 0x08 ,
	0x75 , 0x08 ,
	0x95 , 0x01 ,
	0xB1 , 0x02 ,
	0xC0 , 
	0xC0 , 
//    0x75, 0x07,                    //     REPORT_SIZE (7)
//    0x95, 0x01,                    //     REPORT_COUNT (1)
//    0x81, 0x03,                    //     INPUT (Cnst,Var,Abs)
//    0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
//    0x09, 0x30,                    //     USAGE (X)
//    0x75, 0x10,                    //     REPORT_SIZE (16)
//    0x95, 0x01,                    //     REPORT_COUNT (1)
//    0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
//    0x26, 0xff, 0x0f,              //     LOGICAL_MAXIMUM (4095)
//    0x35, 0x00,                    //     PHYSICAL_MINIMUM (0)
//    0x46, 0xff, 0x0f,              //     PHYSICAL_MAXIMUM (4095)
//    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
//    0x09, 0x31,                    //     USAGE (Y)
//    0x95, 0x01,                    //     REPORT_COUNT (1)
//    0x75, 0x10,                    //     REPORT_SIZE (16)
//    0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
//    0x26, 0xff, 0x0f,              //     LOGICAL_MAXIMUM (4095)
//    0x35, 0x00,                    //     PHYSICAL_MINIMUM (0)
//    0x46, 0xff, 0x0f,              //     PHYSICAL_MAXIMUM (4095)
//    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
//    0xc0,                          // END_COLLECTION
//    0xc0                           // END_COLLECTION
};

然后主函数依旧上报触摸数据,借鉴之前触摸板上报的,注意的是成品触摸板上报的时候,第一个字节是ID0x04,我们直接去掉这一个字符就好了,

	  usb_send_buf[0]=0x83;
	  usb_send_buf[1]=0xB0;usb_send_buf[2]=0x08;
	  usb_send_buf[3]=0x8c;usb_send_buf[4]=0x0B;
	  USBD_HID_SendReport(&hUsbDeviceFS,usb_send_buf,sizeof(usb_send_buf));
	  HAL_Delay(7);
	  
	  usb_send_buf[0]=0x83;
	  usb_send_buf[1]=0xAB;usb_send_buf[2]=0x07;
	  usb_send_buf[3]=0x07;usb_send_buf[4]=0x07;
	  USBD_HID_SendReport(&hUsbDeviceFS,usb_send_buf,sizeof(usb_send_buf));
	  HAL_Delay(7);
	  	  
		usb_send_buf[0]=0x82;
	  usb_send_buf[1]=0xAB;usb_send_buf[2]=0x07;
	  usb_send_buf[3]=0x07;usb_send_buf[4]=0x07;
	  USBD_HID_SendReport(&hUsbDeviceFS,usb_send_buf,sizeof(usb_send_buf));
	  HAL_Delay(7);
	  
	   HAL_Delay(1000);

下载测试,发现电脑和安卓上都都可以用了!
那么触摸的时候具体是触摸在哪一个位置呢?
根据设备描述符我们可以知道x的 最小值为0 最大值为4095,y的 最小值为0 最大值为4095
那么通过程序测试我们发现,(0,0)为电脑屏幕的左上角,(4095,4095)为屏幕的右下角

工程链接:工程链接

你可能感兴趣的:(嵌入式开发,usb,stm32)