我介绍一种直接通过Windows库函数,实现对USB端口的访问,这是一种更底层的操作,当然用起来也就更加灵活,上周刚刚测试成功,也让我对USB有了更深刻的理解。
forum.jpg
USB驱动
在嵌入式系统里,USB相对于其它如串口,SPI等外设,要复杂的多,不过随着USB的应用越来越广,学会使用USB是非常重要的。现在USB设备都是即插即用的(Plug and Play, PnP)设备。那么PC机是怎么知道插入的设备是什么,又如何实现与USB设备的读写的呢?
为了保证内容的连惯性。先简单介绍一下USB描述符。简单的说,描述符就是一些连接存储的数据结构,通过第一个结构,可以解析出第二个结构的信息,通过第二个结构,可以解析出第三个结构的信息,如此下去。由此可见,USB描述符是逐个解析的过程。每个描述符的第一个字节是说明了本结构的字节数,第二个字节说明了本结构的类型,从第三字节开始是具体数据。这些描述符定义了USB的所有信息,包含厂家及主机如何与之通信。常用的几种描述符如下:
forum.jpg
描述符
1.USB设备描述符
每个USB设备都定义了一个自己的设备描述符,它是第一个描述符。我们在电脑设备管理器里看到的信息,都在这个结构里定义。下面是一个PIC单片机的设备描述符结构。
typedef struct _USB_DEVICE_DESCRIPTOR {
  • UCHAR bLength;//本结构字节数
  • UCHAR bDescriptorType;//本结构类型
  • USHORT bcdUSB;//版本2.0,3.0?
  • UCHAR bDeviceClass;//设备类型
  • UCHAR bDeviceSubClass;//子类型
  • UCHAR bDeviceProtocol;//通信协议
  • UCHAR bMaxPacketSize0;
  • USHORT idVendor;//厂家代码
  • USHORT idProduct;//产品代码
  • USHORT bcdDevice;//版本
  • UCHAR iManufacturer;
  • UCHAR iProduct;
  • UCHAR iSerialNumber;
  • UCHAR bNumConfigurations;//配置描述符数量
  • } USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;
  • 复制代码
    设备插入时,PC机会自动读取这个结构值,通过解析这个结构,PC会知道设备的类型(块设备、通信设备等)、VID(厂家代码)、PID(产品代码)及配置描述符的数量。
    forum.jpg
    设备描述符
    2.配置描述符
    每个设备都至少有一个配置描述符。主要功有二个,一是指明本配置有几个接口(即虚拟设备数量,如一个USB可以多个串口,但是同一时候只能打开其中一个),很多时候只有一个接口。二是说明本设备在些配置下的功耗。
    typedef struct _USB_CONFIGURATION_DESCRIPTOR {
  • UCHAR bLength;
  • UCHAR bDescriptorType;//类型
  • UORT wTotalLength;//配置总字节数
  • UCHAR bNumInterfaces;//接口数量
  • UCHAR bConfigurationValue;//本配置索引
  • UCHAR iConfiguration;//字索引数量
  • UCHAR bmAttributes;//位信息
  • UCHAR MaxPower;//功耗
  • } USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR;
  • 复制代码
    当有多个配置时,主机通过bConfigurationValue可以选择启用哪一个配置,进一步可以选哪一个接口。至少有一个接口。
    3.接口描述符
    紧随上面的结构,是接口描述符。
    typedef struct _USB_INTERFACE_DESCRIPTOR {
  • UCHAR bLength;
  • UCHAR bDescriptorType;
  • //本接口的索引
  • UCHAR bInterfaceNumber;
  • //本接口设置索引
  • UCHAR bAlternateSetting;
  • //端点数量
  • UCHAR bNumEndpoints;
  • //类型
  • UCHAR bInterfaceClass;
  • //子类型
  • UCHAR bInterfaceSubClass;
  • //通信协议
  • UCHAR bInterfaceProtocol量
  • UCHAR iInterface;
  • } USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR;
  • 复制代码
    这个结构指明具体功能。包括端点的数量 ,功能类型(有些在设备描述符中定义,但是这里的信息更加具体)。
    4.端点描述符
    每个端点都有一个这个结构。指明端点的地址(即端点号),缓冲区大小,传输方式。
    typedef struct _USB_ENDPOINT_DESCRIPTOR {
  • UCHAR bLength;
  • UCHAR bDescriptorType;
  • UCHAR bEndpointAddress;
  • UCHAR bmAttributes;
  • //缓冲大小
  • USHORT wMaxPacketSize;
  • //主机查询间隔
  • UCHAR bInterval;
  • } USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR;
  • 复制代码
    注意,USB传输是主从模式,都是由主机发起的。传输方向也是相对主机而言的。这些描述符是层次递进的关系。上一层结构除了说明自身的信息外,还指明了下一个结构是什么。
    本文是为C#调用Window库函数作一个技术准备,因为后面的函数里要用到这些概念。