打印
[ZLG-ARM]

USB之: HID I/O(转)

[复制链接]
2831|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
粉色壁纸|  楼主 | 2012-1-13 17:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
其实我对USB还是很有感情的,第一个USB是2005年给航天智通的彩票机做一个客户显示系统,就是彩票机上那个给买彩票的人看的小显示器。之前他们用的是串口,后来很多机器串口少了,而且串口一般还要给POS机之类的其他终端使用,因此需要做这么一个模块。不过当时由于初次做USB, 而且还要写Linux和Windows下的驱动,当时觉得还是用自定义的设备,使用Bulk传输比较简单,最后在AN2131(Cypress)上做了这个项目,大概卖了一千多套,后来被人山寨了,前前后后也赚了点钱,也算是为清苦的研究生生活添加了一点精彩。
其实这个项目完全可以使用HID来实现,估计这样驱动的工作还会更简单些,至少不用下载WinDriver和DDK这种庞然大物了。其实很多MSP430和8051F的仿真器就有使用HID协议的,使用这个协议最大的优点就是不用写驱动,用Windows和Linux自带的驱动即可。其实HID的枚举方式和自定义的差别并不是很大,一般都是先Get Device Descriptor,然后是Get Configuration Descriptor,然后可能会发起多个重复的Device Descriptor和Configuration Descriptor,不过长度可能有点差异,总之就是从Descriptor开头取需要的长度返回就OK了。 如果有String的话还会发起Get String Descriptor。对于HID来讲,跟HID Class相关的是会发起Get HID Report的请求,其大概过程如下(........... 表示省略):
  20.0  CTL    80 06 00 02  00 00 ff 00                                                               Get Configuration Descriptor
  20.0  DI      09 02 29 00  01 01 00 a0  c8 09 04 00  ...........                            返回Configuration
                     00 0a 07 05  02 03 40 00  0a                                                        
  38.0  CTL    80 06 00 01  00 00 12 00                                                             Get Device Descriptor
  38.0  DI      12 01 10 01  00 00 00 40  12 c9 80 02  00 00 01 02  00 01         返回Descriptor
  38.0  CTL    80 06 00 02  00 00 09 00                                                             读取Configuration Descriptor前9个字节   
  38.0  DI      09 02 29 00  01 01 00 a0  c8                                                        返回前9个字节   
  38.0  CTL    80 06 00 02  00 00 29 00                                                             读取Configuration Descriptor前0x29个字节
38.0  DI       09 02 29 00  01 01 00 a0  c8 09 04 00  00 02 03  ..........            返回0x29字节(整个Descriptor)
                     00 0a 07 05  02 03 40 00  0a                                                              
  38.0  CTL    00 09 01 00  00 00 00 00                                                                  
  38.0  CTL    21 0a 00 00  00 00 00 00                                                                  
  20.0  CTL    80 00 00 00  00 00 02 00                                                                  
  20.0  DI      01 00                                                                                           读取Configuration Descriptor前0x29个字节
  38.0  CTL    80 06 00 02  00 00 29 00                                                                  
  38.0  USTS   00 00 01 c0                                                                              
  38.0  CTL     81 06 00 22  00 00 5b 00                                                           读取HID Report Descriptor      
  38.0  DI      09 02 29 00  01 01 00 a0  c8 09 04 00  00 02 03 .............         返回0x29字节(整个Descriptor)
                     00 0a 07 05  02 03 40 00  0a                                                              
  38.0  CTL    80 06 00 03  00 00 ff 00                                                         
  38.0  DI      05 01 09 00  a1 01 15 00  25 ff 19 01  29 08 95 ............. 02 c0  返回HID Report Descriptor
最后一行发完以后基本上就OK了,在设备管理器里面就应该能够看到HID-Compliant Device了
HID Report Descriptor应该是USB HID的最重要的部分了,俺的理解就是一个
Global
{
     Local
     {
        Main
      }
}
Global是全局的,一直起作用,直到被另外的Global代替
Local项目不作用于下一个Main

Main一般就是实际的定义了,比如多少I/O点之类的。还是国外论坛的一个老兄讲的比较清楚,在此引用一下:

相关帖子

沙发
粉色壁纸|  楼主 | 2012-1-13 17:52 | 只看该作者
比如俺的Report Descriptor就是这个样子的:
    0x05, 0x01, // USAGE_PAGE (Generic Desktop)
    0x09, 0x00, // USAGE (0)
    0xa1, 0x01, // COLLECTION (Application)
    0x15, 0x00, //     LOGICAL_MINIMUM (0)
    0x25, 0xff, //     LOGICAL_MAXIMUM (255)
    0x19, 0x01, //     USAGE_MINIMUM (1)
    0x29, 0x08, //     USAGE_MAXIMUM (8)
    0x95, 0x08, //     REPORT_COUNT (8)
    0x75, 0x08, //     REPORT_SIZE (8)
    0x81, 0x02, //     INPUT (Data,Var,Abs)
    0x19, 0x01, //     USAGE_MINIMUM (1)
    0x29, 0x08, //     USAGE_MAXIMUM (8)
    0x91, 0x02, //   OUTPUT (Data,Var,Abs)
    0xc0            // END_COLLECTION

其实就是定义了八个字节的输入和八个字节的输出而已。
当一切Descriptor都回复妥当以后,就需要测试一下了,使用的测试程序是Jan Axelson的测试程序,风别有VB6和VC6两个版本,对其进行了一点点修改,VB的增加了直接在界面输入Vendor ID和Product ID,把接收数据显示也改了一下,原版的显示光标在最后,给人感觉就像数据收错了。VC的把接收的ReportID在显示的时候去掉了,不然看起来比下位机发的多出了一个0x00,怪怪的,此外还把hid.lid,setupapi.lib以及几个头文件放在了包里面并做了部分修改,这样下载就可以直接编译了,如果遇到以下错误:
“DBT_DEVTYP_DEVICEINTERFACE, PDEV_BROADCAST_DEVICEINTERFACE, HDEVNOTIFY, DEVICE_NOTIFY_WINDOW_HANDLE undeclared”
则需要在stdafx.h里面增加#define WINVER 0x0500就OK了。
现在就可以进行测试了,在测试程序的VID和PID中输入正确的数字(16进制的),点击Once就可以看到一次收发了,如果TimeOut的话肯定是下位机有点问题,比如没有不断的往上传IN的数据,或者OUT数据没有读走阻塞住了。
测试程序及其源码下载地址:
VB6:http://download.csdn.net/source/2719482
VC6: http://download.csdn.net/source/2719489

使用特权

评论回复
板凳
tigershark00| | 2017-9-24 21:24 | 只看该作者
USB真的是很烦锁,我已经调试了 快一个月 没什么进展

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

121

帖子

1

粉丝