2011年1月21日星期五

FW: [嘻嘻哈哈] USB接口的红外电脑遥控

USB接口的红外电脑遥控

USB接口的红外电脑遥控

摘要:本设计采用2262,2272一对无线控制芯片来实现红外的发射和硬件解码。而在USB控制模块则采用51+PDIUSBD12来实现USB设备的枚举和数据传送。

本次设计的要点在于USB键盘的实现,因为本次设计最终与主机进行通信是将USB设备枚举成USB键盘,从而获得操作系统的支持,实现免驱动安装的目的。

(一)方案的选择

1:红外的软件解码

此方案是通过软件的复杂化来简化硬件结构,此方案不仅要求对红外协议的熟悉,而且软件解码耗时较大,不适合进行实时性数据的传送。

2:红外的硬件解码

此方案通过一对无线发射和接受芯片2262,2272来实现红外的解码。其特点是红外传送的实时性好,简化软件编写量,且外围硬件电路并不复杂,故在本次设计中采用此方案。

3:采用LPC2148来实现USB的控制

此方案中,LPC2148是一款内置USB模块的微控制器。用其来实现USB的控制和传送可以最大化的简化外围电路和程序的稳定性,但其缺点是芯片价格高,需要另外学习ARM7系列的编程特点。



4:采用51+PDIUSBD12来实现USB的控制

PDIUSBD12是一款性价比很高的USB 器件它通常用作微控制器系统中实现与微控制器进行通信的高速通用并行接口它还支持本地的DMA 传输,支持USB1.1协议。虽然采用51+PDIUSBD12形式使硬件复杂,但由此换来的软件编写环境的熟悉和价格上的优势,故采用此方案。

(二)USB协议和HID键盘的实现

本设计是通过将此USB设备枚举成USB键盘来实现电脑的控制,所以必定设计到USB设备的枚举,故在此先对USB的枚举进行简单的论述。

枚举就是从设备读取一些信息,知道设备是什么样的设备,如何进行通信,这样主机就可以根据这些信息来加载合适的驱动程序。 在说枚举之前,先大概说说USB的一种传输模式――控制传输。这种传输在USB中是非常重要的,它要保证数据的正确性,在设备的枚举过程中都是使用控制传输的。控制传输分为三个阶段:①建立阶段。②数据阶段。③确认阶段。建立(setup)阶段都是由USB主机发起,它是一个setup数据包,里面包含一些数据请求的命令以及一些数据。如果建立阶段是输入请求,那么数据阶段就要输入数据;如果建立阶段是输出请求,那么数据阶段就要输出数据。如果在数据阶段,即便不需要传送数据,也要发一个0长度的数据包。数据阶段过后就是确认阶段。确认阶段刚好跟数据阶段相反,如果是输入请求,则它是一个输出数据包;如果是输出请求,则它是一个输入数据包。确认阶段用来确认数据的正确传输。



1:枚举过程
首先,USB主机检测到USB设备插入后,就会先对设备复位。设备复位后,USB主机就会对地址为0的设备发送获取设备描述符的标准请求。所有的USB设备在总线复位后其地址都为0,这样主机就可以跟那些刚刚插入的设备通过地址0通信。主机在建立阶段发出获取设备描述符的输入请求,设备收到该请求后,在数据阶段将设备描述符返回给主机。主机在成功获取到一个数据包的设备描述符后并且确认没有什么错误后(注意:有些USB设备的端点0大小不足18字节(但至少具有8字节),而标准的设备描述有18字节,在这种情况下,USB设备只能暂时按最大包将部分设备描述符返回,而主机在成功获取到前面一部分描述符后,就不会再请求剩下的设备描述符部分,而是进入设置地址阶段),就会返回一个0长度的确认数据包给设备。
然后主机再对设备复位一下,接下来就会进入到设置地址阶段。这时USB主机发出一个设置地址的请求,并在后面跟着一个0长度的数据输出包。地址包含在建立包中,具体的地址USB主机会负责管理,它会分配一个唯一的地址给新的设备。USB设备在收到地址后,返回0长度的应答包,设备在收到这个0长度应答包的ACK之后,就可以起用新的地址了。这样设备就分配到了一个唯一的设备地址,以后主机就通过它来进行访问该设备。
然后主机再次获取设备描述符,这次跟第一次可能有点不一样,这次需要获取完全部的18个字节的设备描述符。当然,如果你的端点0缓冲大于18字节的话,那就跟第一次的情形一样了。
接下来,主机就会获取配置描述符。配置描述符总共为9字节。主机在获取到配置描述符后,根据里面的配置集合总长度,再获取配置集合。配置集合包括配置描述符,接口描述符,端点描符等等。

如果在设备描述符中定义了字符串描述符,而主机还需要获取字符串描述符。字符串描述符的长度不固定,可由程序员自行确定。
而在此设计中,由于键盘是一种HID设备,故主机还需要获取HID设备类描述符。HID设备类描述符包括HID描述符、报告描述符、物理描述符三种,其中报告描述符是必须的,而另外两种则为可选描述符。

主机得到各种正确的描述符,则为枚举成功,主机加载合适的驱动,即可进行通讯。

2:各种描述符

一个USB设备有一个设备描述符,设备描述符里面决定了该设备有多
少种配置,每种配置描述符对应着配置描述符;而在配置描述符中又定义
了该配置里面有多少个接口,每个接口有对应的接口描述符;在接口描
述符里面又定义了该接口有多少个端点,每个端点对应一个端点描述符;
端点描述符定义了端点的大小,类型等等。由此我们可以看出,USB的
描述符之间的关系是一层一层的,最上一层是设备描述符,下面是配置
描述符,再下面是接口描述符,再下面是端点描述符。在获取描述符时,
先获取设备描述符,然后再获取配置描述符,根据配置描述符中的配置
集合长度,一次将配置描述符、接口描述符、端点描述符一起一次读回。
其中可能还会有获取设备序列号,厂商字符串,产品字符串等。


每种描述符都有自己独立的编号,如下:
DEVICE_DESCRIPTOR 0x01 //设备描述符
CONFIGURATION_DESCRIPTOR 0x02 //配置描述符
STRING_DESCRIPTOR 0x03 //字符串描述符
INTERFACE_DESCRIPTOR 0x04 //接口描述符
ENDPOINT_DESCRIPTOR 0x05 //端点描述符

设备描述符



BYTE blength; //设备描述符的字节数大小
BYTE bDescriptorType; //设备描述符类型编号
WORD bcdUSB; //USB版本号
BYTE bDeviceClass; //USB分配的设备类代码
BYTE bDeviceSubClass; //USB分配的子类代码
BYTE bDeviceProtocol; //USB分配的设备协议代码
BYTE bMaxPacketSize0; //端点0的最大包大小
WORD idVendor; //厂商编号
WORD idProduct; //产品编号
WORD bcdDevice; //设备出厂编号
BYTE iManufacturer; //设备厂商字符串的索引
BYTE iProduct; //描述产品字符串的索引
BYTE iSerialNumber; //描述设备序列号字符串的索引
BYTE bNumConfigurations; //可能的配置数量

配置描述符

BYTE bLength; //配置描述符的字节数大小
BYTE bDescriptorType; //配置描述符类型编号
WORD wTotalLength; //此配置返回的所有数据大小
BYTE bNumInterfaces; //此配置所支持的接口数量
BYTE bConfigurationValue; //配置值
BYTE iConfiguration; //描述该配置的字符串索引值
BYTE bmAttributes; //供电模式的选择
BYTE MaxPower; //设备从总线提取的最大电流



接口描述符
BYTE bLength; //接口描述符的字节数大小
BYTE bDescriptorType; //接口描述符的类型编号
BYTE bInterfaceNumber; //该接口的编号
BYTE bAlternateSetting; //备用的接口描述符编号
BYTE bNumEndpoints; //接口使用的端点数不包括端点0
BYTE bInterfaceClass; //接口类型
BYTE bInterfaceSubClass; //接口子类型
BYTE bInterfaceProtocol; //接口遵循的协议
BYTE iInterface; //描述该接口的字符串索引值



端点描述符
BYTE bLegth; //端点描述符字节数大小
BYTE bDescriptorType; //端点描述符类型编号
BYTE bEndpointAddress; //端点地址及输入输出属性
BYTE bmAttributes; //端点的传输类型属性
WORD wMaxPacketSize; //端点收、发的最大包大小
BYTE bInterval; //主机查询端点的时间间隔



字符串描述符



字符串描述符包括设备厂家描述符、产品描述符、设备序列号描述符。其作用主要是打上自己的商标,防止与其它厂家或其它产品一样,或者被其它厂家倒版,这一块有自己定义,长度也是由自己设定。

基本格式为:

BYTE bLegth; //字符串描述符字节数大小(N+2)
BYTE USB_STRING_DESCRIPTOR_TYPE //字符串类型编码

下面的数据有自己定义 //自己定义,长度为N


HID设备类描述符



通过上面的描述,主机可得到USB设备的大概信息,但如果仅只有以上那些的话,USB设备是不能和主机进行通信的。因为在上面的描述符中根本就没有定义USB设备的具体功能和传递信息的数据格式,而这就需要类描述符。

而因为本设计中的USB键盘所属的为人机接口类(HID),所以我们主要就叙述HID设备类描述符。



HID设备类描述符中自行定义了3种类描述符,分别为HID描述符、报告描述符和物理描述符,其中HID描述符和物理描述符不是必须的。

而报告描述符,是描述一个报告以及报告里面的数据是用来干什么用的。
通过它,USB HOST可以分析出报告里面的数据所表示的意思。它通过控制输入端点0返回,主机使用获取报告描述符命令来获取报告描述符,注意这个请求是发送到接口的,而不是到设备。一个报告描述符可以描述多个报告,不同的报告通过报告ID来识别,报告ID在报告最前面,即第一个字节。当报告描述符中没有规定报告ID时,报告中就没有ID字段,开始就是数据。

以下为普通USB键盘的报告描述符(不支持多媒体功能)
0x05, 0x01, //USAGE_PAGE (Generic Desktop)用途页为通用桌面设备 0x09, 0x06, //USAGE (Keyboard) 用途为键盘
0xa1, 0x01, //COLLECTION (Application)集合开始 0x05, 0x07, //USAGE_PAGE (Keyboard) 用途页为按键
0x19, 0xe0, //USAGE_MINIMUM (Keyboard LeftControl)用途最小值
0x29, 0xe7, //USAGE_MAXIMUM (Keyboard Right GUI)用途最大值
0x15, 0x00, //LOGICAL_MINIMUM (0) 逻辑最小值为0
0x25, 0x01, //LOGICAL_MAXIMUM (1) 逻辑最大值为1
0x75, 0x01, //REPORT_SIZE (1) 报告大小(即这个字段的宽度)为1bit
0x95, 0x08, //REPORT_COUNT (8) 报告的个数为8,即总共有8个bits
//输入用,变量,值,绝对值。像键盘这类一般报告绝对值
0x81, 0x02, // INPUT (Data,Var,Abs)
/*上面这这几项描述了一个输入用的字段,总共为8个bits,每个bit表示一个按键,分别从左ctrl键到右GUI键。这8个bits刚好构成一个字节,它位于报告的第一个字节。它的最低位,即bit-0对应着左ctrl键,如果返回的数据该位为1,则表示左ctrl键被按下,否则,左ctrl键没有按下。最高位,即bit-7表示右GUI键的按下情况。中间的几个位,需要根据HID协议中规定的用途页表(HID Usage Tables)来确定。这里通常用来表示特殊键,例如ctrl,shift,del键等 */
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x03, // INPUT (Cnst,Var,Abs)

0x95, 0x05, // REPORT_COUNT (5)
0x75, 0x01, // REPORT_SIZE (1)
0x05, 0x08, // USAGE_PAGE (LEDs) 控制键盘上的LED用的
0x19, 0x01, // USAGE_MINIMUM (Num Lock) 数字键锁定灯
0x29, 0x05, // USAGE_MAXIMUM (Kana)
//输出,用来控制LED。变量,值,绝对值。1表示灯亮,0表示灯灭
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x03, // REPORT_SIZE (3)
0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
//由于要按字节对齐,而前面控制LED的只用了5个bit,
//所以后面需要附加3个不用bit,设置为常量
0x95, 0x06, // REPORT_COUNT (6)
0x75, 0x08, // REPORT_SIZE (8)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0xFF, // LOGICAL_MAXIMUM (255)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data,Ary,Abs)
/*以上定义了6个8bit宽的数组,每个8bit(即一个字节)用来表示一个 按键,所以可以同时有6个按键按下。没有按键按下时,全部返回0。如果按下的键太多,导致键盘扫描系统无法区分按键时,则全部返回0x01,即6个0x01。如果有一个键按下,则这6个字节中的第一个字节为相应的键值(具体的值参看HID Usage Tables),如果两个键按下,则第1、2两个字节分别为相应的键值,以次类推。*/

USB HID设备传送数据有两种方式:

一是通过报告来给传送数据,报告有输入报告和输出报告。输入报告是USB设备发送给主机的,例如USB鼠标将鼠标移动和鼠标点击等信息返回给电脑,键盘将按键数据数据返回给电脑等;输出报告是主机发送给USB设备的,例如键盘上的数字键盘锁定灯和大写字母锁定灯等。报告是一个数据包,里面包含的是所要传送的数据。输入报告是通过中断输入端点输入的,而输出报告有点区别,当没有中断输出端点时,可以通过控制输出端点0发送,当有中断输出端点时,通过中断输出端点发出。在USB2.0协议中提出不提倡通过这种方式来进行传送数据。

二是通过端点的中断传送进行传递数据,在本设计中就是通过端点2的中断来进行与主机的数据交换。

(三)无线电脑遥控实现

本设计是通过2262配合红外发射头来进行发送数据,用与之相匹配的2267(地址,频率匹配)和红外接收头来接收数据。在单片机每次的定时器0中断的时候进行读取数据,通过每次的端点2的中断将数据传递至主机,从而实现对主机的相应控制。

具体实现为:在每一次2262的有按键按下的同时使2262工作,将数据传送至2272,而2272将从2262解码出数据,等待单片机的读取。若2262没有按键按下,则2272的数据为0。在定时器0中断的中断服务程序中,读出2272解码出来的其中的按键信息,将其变换成控制相应按键的USB键盘数据流,通过PDIUSBD12的端点2将数据传递至主机,从而实现一次相应的控制。因为端点2的中断和定时器0的中断是循环不断的进行,所以也就能实时地读取到键盘的信息,完成无线电脑遥控的目的。



05 01 // USAGE_PAGE (Generic Desktop)
09 03 //USAGE
a1 01 //collection

09 01 //USAGE
15 00 //最小值
26 ff 00

75 08 ,//REPORT_SIZE (8)
95 08 //报告的个数为8
81 00 //输入
15 00 //最小值
25 01 //最大值


95 40 //报告长度64
75 01 ,//每个段大小为3bits
05 08 //USAGE_PAGE (Generic Desktop)
19 01 //用途最小值
29 40 //用途最大值
91 02 //报告相对值
c0

HID报告描述符_百度文库
http://blog.sina.com.cn/s/blog_4cd5d2bb0100f72p.html

--
Best Regards



--
Kimi 于 1/21/2011 05:01:00 上午 发布在 嘻嘻哈哈 <http://joke-xixihaha.blogspot.com/2011/01/usb.html> 上