一:HID协议
USB HID设备主要基于两种协议:报告协议(report protocol)和引导协议(boot protocol)。报告是从设备发送到主机的数据结构,也可以从主机发送到设备。当设备向主机发送报告时,通常包含状态变化信息,例如按键,鼠标移动等。当主机向设备发送报告时,通常包含用于配置设备的命令(set_report请求),例如在键盘上设置LED。这个协议依赖于标准的USB框架。USBHID设备使用中断传输进行通信,因为设备并不是一直在传输数据,但当设备传输数据时,主机需要软件有快速的响应。中断传输时传输的数据量通常很小。报告通常有两种类型,具体取决于协议类型。
HID报告协议基于“项目(item)”的概念,其数据结构在报告描述符中定义。引导协议要简单得多,并且遵循鼠标和键盘的标准结构。依据本次实验内容,此处将仅讨论引导协议。
二:USB键盘
USB 键盘使用报告与软件通信,就像其他 HID设备一样。通过接口描述符中的类字段(bInterfaceClass)3和协议字段(bInterfaceProtocol)来检测 USB键盘。
(1)报告格式
该报告必须由软件每隔固定时间使用一次中断传输请求,并且此间隔应在USB键盘的端点IN触发的中断中定义。USB键盘报告的大小可能高达8个字节,但这些字节不一定都被使用,如果只使用前三个或四个字节来实现正确的键码传输是可行的。此处描述键盘的完整报告机制。表15.75定义的报告数据结构仅适用于引导协议。
(2)按键机制
USB键盘在按下或释放键时发送中断。当用户按下一个键时,中断会在其中一个按键字段中带有一个扫描码值。当一个键被释放时,对应的按键字段在下一个数据包中返回零。为了更清楚地说明这一点并说明为什么有多个普通按键扫描码字段,让我们看以下示例。假设用户按下“A”键,即扫描码Ox04。返回的中断数据包为:
00 00 04 00 00 00 00 00 00
三:软件代码如下所示:
3.1 USB代码如下所示:
void usb_class_in()
{
BYTE key[8];
BYTE i;
if (DeviceState != DEVSTATE_CONFIGURED)
return;
if (!UsbInBusy && fKeyOK)
{
fKeyOK = 0;
key[0] = 0;
key[1] = 0;
key[2] = 0;
key[3] = 0;
key[4] = 0;
key[5] = 0;
key[6] = 0;
key[7] = 0;
switch (bKeyCode)
{
case 0xfe: key[2] = 0x1e; break;
case 0xfd: key[2] = 0x1f; break;
case 0xfb: key[2] = 0x20; break;
case 0xf7: key[2] = 0x21; break;
case 0xef: key[2] = 0x22; break;
case 0xdf: key[2] = 0x23; break;
case 0xbf: key[2] = 0x24; break;
case 0x7f: key[2] = 0x25; break;
}
EUSB = 0;
UsbInBusy = 1;
usb_write_reg(INDEX, 1);
for (i=0; i<8; i++)
{
usb_write_reg(FIFO1, key[i]);
}
usb_write_reg(INCSR1, INIPRDY);
EUSB = 1;
}
}3.2 按键扫描函数
void scan_key()
{
BYTE key;
P0M0 = 0x00;
P0M1 = 0x00;
key = 0;
P0 = 0xff;
P06 = 0;
_nop_();
_nop_();
key |= P0 & 0x0f;
P06 = 1;
P07 = 0;
_nop_();
_nop_();
key |= (P0 & 0x0f) << 4;
P07 = 1;
if (key != bKeyCode)
{
bKeyCode = key;
bKeyDebounce = 20;
}
else
{
if (bKeyDebounce)
{
bKeyDebounce--;
if (bKeyDebounce == 0)
{
fKeyOK = 1;
}
}
}
}3.3 在主程序中进行扫描即可
while (1)
{
usb_class_in();
if (f1ms)
{
f1ms = 0;
scan_key();
}
}四:实验验证如下:


我要赚赏金
