<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
一、自定义HID设备的相关概念
1、HID设备
HID设备的直译是指“人机接口设备”,但实际上HID设备并不需要一定有人机接口。只要是主机与设备之间数据交换格式满足一定的要求,都可以使用人机接口类别来实现。
HID设备实现的数据交换的特征:
(1)交换的数据用报表描述符描述其格式,主机和设备以描述符约定的格式交换数据。
(2)数据传输速率较低。
鼠标、键盘都是windows系统标准的“HID设备”,这样的设备在主机端甚至都不需要编写应用程序。
但是我们在控制系统中,将开发板做成一个HID设备,肯定是要在PC与开发板之间交换一些特殊的控制和配置数据,而不是为了把开发板做成一个键盘或鼠标。
要达到这样的目的,可以使用自定义的“HID设备”。
2、自定义HID设备
实际上,要让主机将设备视为一个“自定义的HID设备”,很简单,只要在“接口描述符”指定“HID类别”,而在“报告描述符”里不指明具体用途页就行了。
下面是接口描述符:
0x09, /*bLength: Interface Descriptor size*/
USB_INTERFACE_DESCRIPTOR_TYPE,/*bDescriptorType: Interface descriptor type*/
0x00, /*bInterfaceNumber: Number of Interface*/
0x00, /*bAlternateSetting: Alternate setting*/
0x02, /*bNumEndpoints*/
0x03, /*bInterfaceClass: HID*/
0x00, /*这个设为0*/
0x00, /*这个也设为0,非0情况一般用于键盘和鼠标启动/
0, /*iInterface: Index of string descriptor*/
下面是报告描述符的开端:
0x05, 0x01, /*Usage Page(Generic Desktop)*/
0x09,
// 0x06, /*Usage(键盘)*/
0x00, //从06改为00后,该设备就成为一个自定义的HID设备。
0xA1, /*Collection(Logical)*/
0x01,
在以下对“报告”组成的元素描述过程中,也不要出现与“特定用途页”相关的性质定义。具体格式如下:
0x15, 0x00, /*Logical Minimum(0)*/
0x25, 0x01, /*Logical Maximum(1)*/
0x19, 0x01, /*Usage Minimum(1)*/
0x29, 0x08, /*Usage Maximum(8)*/
0x95, 0x08, /*Report Count(8)*/
0x75, 0x01, /*Report Size(1)*/ //每个1位,加起来一个字节。
0x81, 0x02, /*Input(Variable)*/
如果是一个数据要占据8位,则逻辑最大值设为0xFF,报告大小设置为8位就行了。
“自定义HID设备”报告的发送和接收与“USB鼠标”、“USB键盘”类似,只是此时主机方对输入报告的处理、输出报告的发送就需要用户字节编写应用程序了。
二、主机应用程序的编写
1、目的
(1)应用程序能反映智林开发板上的按键的状态。
(2)应用程序能够控制开发板上的一个灯。
2、实现过程
我对于PC上的编程现在已经很生疏了,以前经常用VB编程,VC学过但没用过。我现在也没有学VC编程的计划,因此上位机编程就在“圈圈光盘上给的代码”基础上修改。
(1)需要修改点
我把VID设为8888,PID设为6666,PVN设为0200。
我的报告描述符:输入两个字节,第一个字节的每个位代表开发板按键状态,BIT0-4代表五向摇杆,BIT5代表PB2按键,PB6-7未用。第二个字节本来我想将开发板上电位器的采用数值发给主机显示,但是ADC的设置上要花费较多功夫,以后用到AD的时候再学习吧。
输出一个字节,就BIT0控制开发板上的灯,其它未用。
(2)默认厂商号、产品号的修改
//初始化VID、PID、PVN数据区
SetDlgItemText(IDC_VID_EDIT,"8888");
SetDlgItemText(IDC_PID_EDIT,"6666");
SetDlgItemText(IDC_PVN_EDIT,"0200");
这个在CMyUsbHidTestAppDlg::OnShowWindow(BOOL bShow, UINT nStatus)函数中,窗口显示前的设置。
(3)接收报告的处理,改为接收3个字节的报告
//如果字节数为9,则说明获取到了正确的9字节报告
if(Length==3)
{
//第一字节为报告ID,应该为0
if(ReadReportBuffer[0]==0)
{
//第二字节为按键状态,将其保存到KeyStatus中。
KeyStatus=ReadReportBuffer[1];
//刷新按键的情况。
pAppDlg->SetKeyStatus();
//第3、4、5、6字节为设备返回的发送次数值。计算出值后并显示。
Counter=0;
Counter=ReadReportBuffer[2];
pAppDlg->SetCounterNumber(Counter);
}
}
(4)发送报告的处理,每次发送2个数据,第一个字节为报告ID=0
//设置要发送报告的数据
WriteReportBuffer[0]=0x00; //报告ID为0
WriteReportBuffer[1]=LedStatus; //控制LED的状态。
//显示发送数据的信息
AddToInfOut("发送输出报告2字节");
Str="";
for(i=0;i<2;i++)
{
Str+=itos(WriteReportBuffer,16).Right(2)+" ";
}
AddToInfOut(Str,FALSE);
//调用WriteFile函数发送数据
Result=WriteFile(hWriteHandle, WriteReportBuffer, 2, NULL, &WriteOverlapped);
程序编译,运行,以下是按下“OK”键的效果,它的按键编号为“4”。实际为第5个按键。
<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />
文章评论(0条评论)
登录后参与讨论