? HID设备全称:Human Interface Devices ,我们常使用的鼠标键盘,就是HID设备,当然不止这些了,随着USB速率不断提高,HID设备可以用在很多方面了。另外HID设备有一个优点就是免驱,正因为如此,笔者认为在使用USB通信,做上下位机开发,首选HID。像CDC这种(BULK传输方式),很多时候涉及到驱动问题,操作比较麻烦,特别对于用户小白,压根就不想关心这个,所以不是很建议。
在不同速度下,HID设备端点大小有很大的差异,下面是1笔事务下的速率。
低速设备:最大8byte/10ms 800byte/s 左右
全速设备:最大64byte/1ms 64000byte/s 左右
高速设备:最大1024byte/0.125ms 0.125ms最多可3笔事务,可达 24M/s 左右
前期准备:
1.带USB 2.0高速功能的MCU (笔者使用的NXP RT1052)
2.libusb 1.x 版本
3.VS2015 keil (IDE环境选择很多,因人而异)
下位机
1.描述符基本构成
部分描述符展示:
Device Descriptor:
------------------------------
0x12 bLength
0x01 bDescriptorType
0x0200 bcdUSB
0x00 bDeviceClass
0x00 bDeviceSubClass
0x00 bDeviceProtocol
0x40 bMaxPacketSize0 (64 bytes)
0x0483 idVendor
0x5700 idProduct
0x00C8 bcdDevice
0x01 iManufacturer "L17"
0x02 iProduct "Hid High Boot"
0x03 iSerialNumber
0x01 bNumConfigurations
Configuration Descriptor:
------------------------------
0x09 bLength
0x02 bDescriptorType
0x0029 wTotalLength (41 bytes)
0x01 bNumInterfaces
0x01 bConfigurationValue
0x00 iConfiguration
0xC0 bmAttributes (Self-powered Device)
0x19 bMaxPower (50 mA)
Interface Descriptor:
------------------------------
0x09 bLength
0x04 bDescriptorType
0x00 bInterfaceNumber
0x00 bAlternateSetting
0x02 bNumEndPoints
0x03 bInterfaceClass (Human Interface Device Class)
0x00 bInterfaceSubClass
0x00 bInterfaceProtocol
0x00 iInterface
HID Descriptor:
------------------------------
0x09 bLength
0x21 bDescriptorType
0x0110 bcdHID
0x21 bCountryCode
0x01 bNumDescriptors
0x22 bDescriptorType (Report descriptor)
0x001B bDescriptorLength
Endpoint Descriptor:
------------------------------
0x07 bLength
0x05 bDescriptorType
0x81 bEndpointAddress (IN endpoint 1)
0x03 bmAttributes (Transfer: Interrupt / Synch: None / Usage: Data)
0x0400 wMaxPacketSize (1 x 1024 bytes)
0x01 bInterval (1 microframes)
Endpoint Descriptor:
------------------------------
0x07 bLength
0x05 bDescriptorType
0x02 bEndpointAddress (OUT endpoint 2)
0x03 bmAttributes (Transfer: Interrupt / Synch: None / Usage: Data)
0x0400 wMaxPacketSize (1 x 1024 bytes)
0x01 bInterval (1 microframes)
除上述展示的描述符外,另外一个特别重要的HID报告描述符也值得注意(特别是:数据域的数量,每个数据域的长度),HID描述符比较复杂就不展开说了,可以下载官方文档或者用报告描述符生成工具去配置深入了解。
Human Interface Devices (HID) Information | USB-IF
HID Descriptor Tool | USB-IF
2.hid发送接收测试
usb_status_t USB_DeviceHidCallback(class_handle_t handle, uint32_t event, void *param)
{
usb_status_t error = kStatus_USB_Error;
switch (event)
{
case kUSB_DeviceHidEventSendResponse:
{
iSSendEnd = true;
}
break;
case kUSB_DeviceHidEventRecvResponse:
if (g_UsbDeviceHidGeneric.attach)
{
error = USB_DeviceHidRecv(g_UsbDeviceHidGeneric.hidHandle, USB_HID_GENERIC_ENDPOINT_OUT,
(uint8_t *)g_UsbDeviceHidGeneric.buffer,USB_HID_GENERIC_OUT_BUFFER_LENGTH);
HID_SendBuffer((uint8_t *)g_UsbDeviceHidGeneric.buffer);
}
break;
case kUSB_DeviceHidEventGetReport:
case kUSB_DeviceHidEventSetReport:
case kUSB_DeviceHidEventRequestReportBuffer:
error = kStatus_USB_InvalidRequest;
break;
case kUSB_DeviceHidEventGetIdle:
case kUSB_DeviceHidEventGetProtocol:
case kUSB_DeviceHidEventSetIdle:
case kUSB_DeviceHidEventSetProtocol:
break;
default:
break;
}
return error;
}
usb_status_t HID_SendBuffer(unsigned char* buff)
{
iSSendEnd = false;
return USB_DeviceSendRequest(g_UsbDeviceHidGeneric.deviceHandle,USB_HID_GENERIC_ENDPOINT_IN,buff,HS_HID_GENERIC_INTERRUPT_IN_PACKET_SIZE);
}
下位机将接收到的端点OUT数据,再通过端点IN转发给上位机。
上位机
上位机部分笔者调用的是第三方库:libusb 当然也可以用微软自带库开发。下面简单介绍下,开发流程
1.遍历Windows端口所有usb设备,获取设备数量
libusb_get_device_list
2.遍历所有设备的描述符信息,通过PID VID等信息找到我们指定的设备
libusb_get_device_descriptor
3.打开指定设备
libusb_open
4.根据指定设备查询设备接口类型(项目中有可能是组合设备,存在不同接口类型),找到HID接口,
获取该接口端点IN OUT
5.端点上通信(hid 是中断传输,所以调用中断传输sdk)
libusb_interrupt_transfer
具体代码就不展示了,毕竟也是个人成果。
void CHidDealDlg::OnBnClickedButtonSend()
{
#if 1
int i;
for (i=0;i<1024;i++)
{
hid20buf[i] = i & 0x00ff;
}
#endif
HidDevice.HID20_Write(hid20buf,1024,10);
InsertMessageToListBox(TEXT("Send 1024 byte data to Mcu!!!"));
}
unsigned int WINAPI xUSB_RxThread(PVOID lpParameter)
{
CHidDealDlg* pThis = (CHidDealDlg*)lpParameter;
int dataLen;
while (1)
{
dataLen = HidDevice.HID20_Read(hid20_Rxbuf,10);
if (dataLen > 0)
{
pThis->InsertMessageToListBox(TEXT("Receive 1024 byte data success!!!"));
}
Sleep(1);
}
return 0;
}
测试结果如下:
|