USB复合设备资料

电子 › 通讯协议 › USB 下载:0 浏览:2 时间:星期前
  • 文件大小:117.84MB
  • 运行平台:Windows
  • 开发工具:C
  • 下载鸟蛋:免费
提问 收藏 举报 0 0
  • 说明

图片.png


【 基于STM32 的USB程序开发笔记 】

目前市场上USB设备的种类繁多,但是这些设备会有一些共同的特性,根据这些特性可以把USB设备划分为不同的类,如显示设备、通信设备、音频设备、大容量存储设备、人机接口设备(HID)。

HID 类设备属于人机交互操作的设备。如 USB鼠标,USB键盘,USB游戏操纵杆,USB触摸板,USB轨迹球、电话拨号设备、VCR遥控等等设备。用于控制计算机操作的一些方面。(从Windows98操作系统开始,为HID类设备提供了通用的驱动程序,所以只要按照HID设备类的规范编写设备的固件程序,就能够让Windows系统自动识别设备,省去了复杂的驱动程序编写过程。)

使用HID 设备的一个好处就是,操作系统自带了HID 类的驱动程序,而用户无需去开发很麻烦的驱动程序,只要直接使用API 调用即可完成通信。所以很多简单的USB设备,喜欢枚举成HID 设备,这样就可以不用安装驱动而直接使用。

USB设备有4种传输方式与主机进行通信: 控制方式、中断方式、批量方式和同步方式。

 

HID只支持控制中断传输方式。如图2所示,HID设备必须要有默认的控制管道和一个中断输入端点;中断输出端点是可选的。

Ø 端点是地址,管道是路径;

图片.png

图2  HID类设备使用控制和中断传输方式

 

1. STM32 的参考手册,这对于设备底层 USB 的硬件配置以及事件驱动机制的了解尤为重     要,你需要了解各个寄存器的功能以及如何操作,比如 CNTR、ISTR、EPnR、DADDR 等     等,如果你想学习 USB,这个手册是必须的。

2. USB2.0 协议;第9章USB Device Framework 的详细理解对于你的 USB Device 固件     开发不可缺少(这里就是 STM32)。

3. ST提供的USB固件库,这个类库较为散乱,但不可不参考;

4. USB 设备(DEVICE)从来只是被动触发,USB 主机(HOST)掌握主动权,发送什么数据,    什么时候发送,是给设备数据还是从设备请求数据,都是由 USB 主机完成的,USB 设     备只是配合主机完成设备的枚举、数据方向和大小。根据数据特性再决定该不该回复该    如何回复、该不该接收该如何接收这些动作。

 

修改STM32的USB例程为自己所用

1. USB设备和主机的通信需要先建立virtual pipeline(管道),然后设备传回描述符给主    机。joystick属于HID设备,工作在中断方式。但并非通常单片机所谓的中断,而实     际上是查询的方式。

2. USB数据 是由 二进制数字串 构成的;

    二进制数字串  è 域(有七种)  è  包  è  事务(IN、OUT、SETUP) è  传输     (中断传输、并行传输、批量传输和控制传输)。

3. 而描述符就需要程序来提供了。

Ø usb_desc.c: 提供了设备、端点、接口、字符串、群组、制造商描述符;

Ø usb_prop.c: 提供了Device_Property(性能),Device_Table &USER_STANDARD_             REQUEST(请求)结构描述,这3个东西定义于usb_core.c;

 

Ø hw_config.c: 提供了实际硬件需要的操作函数,Joystick_Send()通过函数

                UserToPMABufferCopy 和 SetEPTxValid 将坐标值发给了USB端口。

Ø STM32f10x_it.c:里面有

 

我们想实现一个USB功能,可以拿例子来改那么具体要改哪些地方呢 ?】

Ø 首先要改各种描述符,然后是具体的数据处理。

我们拿USB摇杆鼠标范例è 改成USB键盘。

USB主机是通过请求设备的相关描述符来判断设备类型的,所以我们只需要修改相关描述符

就能实现我们想要设备类型。描述符的配置位于Descriptor.h和Descriptor.c文件中。

 

步骤一:设备描述符。范例中的USB设备描述符如下:
           /* USB Standard Device Descriptor */
const u8 Joystick_DeviceDescriptor[JOYSTICK_SIZ_DEVICE_DESC]=
{
 0x12,                       /*bLength */
 USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/
 0x00,                       /*bcdUSB */
 0x02,
 0x00,                       /*bDeviceClass*/
 0x00,                       /*bDeviceSubClass*/
 0x00,                       /*bDeviceProtocol*/
 0x40,                       /*bMaxPacketSize40*/
 0x83,   (低字节)  /*idVendor (0x0483)   VID*/
 0x04,  (高字节)
 0x10,                       /*idProduct = 0x5710  PID*/
 0x57,
 0x00,                       /*bcdDevice rel. 2.00*/
 0x02,
 1,   /*Index of string descriptor describing  manufacturer */
 2,  /*Index of string descriptor describing  product*/
 3,       /*Index of string descriptor describing the device serial number */
 0x01               /*bNumConfigurations*/
};   

修改:修改这里的idVendor(即VID)和idProduct(即PID)即可。它们是用来供电脑端       识别设备以加载驱动用的,所以必须不能跟现有的设备相冲突。

VID和PID都是两字节,低字节在前,高字节在后。像这里的VID为0x0483,写在里面就是0x83,0x04。我们将VID改成0x1234,将PID改成0x4321,即: 0x34, 0x12, 0x21, 0x43。

 

步骤二:配置描述符集合

配置描述符集合包括配置描述符、接口描述符、类特殊描述符(这里是HID描述符)、以及端点描述符。

如果你需要增加端点,那么在最后增加就行了,注意要记得修改JOYSTICK_SIZ_CONFIG_DESC的值为配置描述符集合的长度。

第一部分为配置描述符。通常这里不需要修改,除非你要改成该配置有多个接口(USB复合         设备),那么应该修改bNumInterfaces,需要多少个就改成多少个,这里只有一          个接口,所以值为1。

 

第二部分为接口描述符,在接口描述符中决定该接口所实现的功能,例如HID设备,或者是        大容量存储设备等等。

bInterfaceNumber):为该接口的编号,从0开始。这里只有一个接口,所以它的值为0,   如果又更多的接口,则依次编号。注意一个接口完整结束(包括该接口下的类特殊描述    符和端点描述符)后,才可以开始一个新的接口。

bNumEndpoints):为该接口所使用的端点数目(不包括端点0),原来的程序是实现鼠标    功能的,所以只有一个输入端点。我们这里增加一个输出端点,用来控制LED(键盘上    有大写字母锁定、小键盘数字键锁定等指示灯),因此将bNumEndpoints改为2。
bInterfaceClass):为接口所使用的,这里指定为HID设备,USB键盘和鼠标都是HID     设备,这里不用修改,如果你要实现其它设备,请根据USB协议所规定的类来修改。

bInterfaceSubClass):为接口所使用的子类,在HID设备类下规定了两种子类,系统引     导时能用的不能用的,这里为1,表示系统引导时能使用。

bInterfaceProtocol):为接口的协议,原来为鼠标,这里改为1,键盘。

 

第三部分为HID描述符,只有HID设备才有,如果你要修改成其它设备,则用其它设备的类         特殊描述符代替或者没有,在这里不用做修改。

 

第四部分为输入端点1的端点描述符,原来代码中,设置的端点最大包长度(wMaxPacketS ize)为4字节,我们将其改成8字节。另外,我们再增加一个输出端点1,将最后的输入端点1描述符复制一份,然后修改地址(bEndpointAddress)为0x01,这表示该端点为输出端点,地址为1。由bEndpointAddress的最高位表示方向,1为输入,0为输出,最后4位表示地址。最后,要记得在usb_desc.h文件中修改JOYSTICK_SIZ_CONFIG_DESC的长度为41,因为我们增加了7字节。

 (实际修改好的配置)描述符集合如下:

/* USB Configuration Descriptor */
/* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
const u8 Joystick_ConfigDescriptor[JOYSTICK_SIZ_CONFIG_DESC] =
{
 //以下为配置描述符
 0x09, /* bLength: Configuation Descriptor size */
 USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
 JOYSTICK_SIZ_CONFIG_DESC,
 /* wTotalLength: Bytes returned */
 0x00,
 0x01,         /*bNumInterfaces: 1 interface*/
 0x01,         /*bConfigurationValue: Configuration value*/
 0x00,         /*iConfiguration: Index of string descriptor describing
               the configuration*/
 0xC0,         /*bmAttributes: self powered */
 0x32,         /*MaxPower 100 mA: this current is used for detecting Vbus*/

 //以下为接口描述符
 /************** Descriptor of Joystick Mouse interface ****************/
 /* 09 */
 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*/
 0x01,         /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
 0x01,         /*bInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
 0,            /*iInterface: Index of string descriptor*/

 //以下为HID描述符
 /******************** Descriptor of Joystick Mouse HID ********************/
 /* 18 */
 0x09,         /*bLength: HID Descriptor size*/
 HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
 0x00,         /*bcdHID: HID Class Spec release number*/
 0x01,
 0x00,         /*bCountryCode: Hardware target country*/
 0x01,         /*bNumDescriptors: Number of HID class descriptors to follow*/
 0x22,         /*bDescriptorType*/
 JOYSTICK_SIZ_REPORT_DESC,/*wItemLength: Total length of Report descriptor*/
 0x00,
 
 //以下为输入端点1描述符
 /******************** Descriptor of Joystick Mouse endpoint *****************/
 /* 27 */
 0x07,          /*bLength: Endpoint Descriptor size*/
 USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/
 0x81,          /*bEndpointAddress: Endpoint Address (IN)*/
 0x03,          /*bmAttributes: Interrupt endpoint*/
 0x08,          /*wMaxPacketSize: 8 Byte max */
 0x00,
 0x20,          /*bInterval: Polling Interval (32 ms)*/

 //以下为输出端但1描述符
 /* 34 */
 0x07,          /*bLength: Endpoint Descriptor size*/
 USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/
 0x01,          /*bEndpointAddress: Endpoint Address (OUT)*/
 0x03,          /*bmAttributes: Interrupt endpoint*/
 0x08,          /*wMaxPacketSize: 8 Byte max */
 0x00,
 0x20,          /*bInterval: Polling Interval (32 ms)*/
/* 41 */
};

 

步骤三:报告描述符,报告描述符比较复杂,直接给出修改好的报告描述符如下:
const u8 Joystick_ReportDescriptor[JOYSTICK_SIZ_REPORT_DESC] =
{
 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
 0x09, 0x06, // USAGE (Keyboard)
 0xa1, 0x01, // COLLECTION (Application)
 0x05, 0x07, //     USAGE_PAGE (Keyboard/Keypad)
 0x19, 0xe0, //     USAGE_MINIMUM (Keyboard LeftControl)
 0x29, 0xe7, //     USAGE_MAXIMUM (Keyboard Right GUI)
 0x15, 0x00, //     LOGICAL_MINIMUM (0)
 0x25, 0x01, //     LOGICAL_MAXIMUM (1)
 0x95, 0x08, //     REPORT_COUNT (8)
 0x75, 0x01, //     REPORT_SIZE (1)
 0x81, 0x02, //     INPUT (Data,Var,Abs)
 0x95, 0x01, //     REPORT_COUNT (1)
 0x75, 0x08, //     REPORT_SIZE (8)
 0x81, 0x03, //     INPUT (Cnst,Var,Abs)
 0x95, 0x06, //   REPORT_COUNT (6)
 0x75, 0x08, //   REPORT_SIZE (8)
 0x25, 0xFF, //   LOGICAL_MAXIMUM (255)
 0x19, 0x00, //   USAGE_MINIMUM (Reserved (no event indicated))
 0x29, 0x65, //   USAGE_MAXIMUM (Keyboard Application)
 0x81, 0x00, //     INPUT (Data,Ary,Abs)
 0x25, 0x01, //     LOGICAL_MAXIMUM (1)
 0x95, 0x05, //   REPORT_COUNT (5)
 0x75, 0x01, //   REPORT_SIZE (1)
 0x05, 0x08, //   USAGE_PAGE (LEDs)
 0x19, 0x01, //   USAGE_MINIMUM (Num Lock)
 0x29, 0x02, //   USAGE_MAXIMUM (Caps Lock)
 0x91, 0x02, //   OUTPUT (Data,Var,Abs)
 0x95, 0x01, //   REPORT_COUNT (1)
 0x75, 0x06, //   REPORT_SIZE (6)
 0x91, 0x03, //   OUTPUT (Cnst,Var,Abs)
 0xc0        // END_COLLECTION
};

该报告描述符说明输入报告为8字节,第一字节为特殊键,用位图表示,第二字节保留,第三至第八字节为普通按键。我们将原来的摇杆功能改成键盘上的4个方向键,中键选择键为回车键,另外KEY2和KEY3分别做大写字母锁定键和数字锁锁定键。输出报告为1字节,其中最低两位分别为Num Lock灯和Caps Lock灯。

 

 

Joystick_StringLangID描述符不用修改,Joystick_StringVendor(卖主)、Joystick_StringProduct分别为厂商字符串和设备字符串,不改也可以,但是显示出来就是原来的内容,最好还是自己修改下。这里使用的是Unicode编码,可以直接使用圈圈以前写小程序自动生成该描述符,该工具的地址为:http://computer00.21ic.org/user1/2198/archives/2007/42769.html。Joystick_StringSerial为产品序列号,它也是Unicode编码,这里可以不用修改,当然你修改也可以。这里我将厂商字符串改成“电脑圈圈的家当”,产品字符串改成“电脑圈圈修改的简易USB键盘”。好了,描述符改完了。

 

步骤四:修改数据处理。我们启用了一个新的端点,端点1输出,原来的程序中并未对它进行初始化,所以我们需要先增加对端点1输出的初始化。在usb_prop.c文件中,找到

void Joystick_Reset(void)函数,该函数是负责初始化端点的。原来对端点1输入的初始化设置为4字节,我们将它改成8字节。并增加对端点输出的初始化,

最终修改的代码部分如下:

  /* Initialize Endpoint In 1 */
  SetEPType(ENDP1, EP_INTERRUPT);       //初始化为中断端点类型
  SetEPTxAddr(ENDP1, ENDP1_TXADDR);   //设置发送数据的地址
  SetEPTxCount(ENDP1, 8);                 //设置发送的长度
//  SetEPRxStatus(ENDP1, EP_RX_DIS);
  SetEPTxStatus(ENDP1, EP_TX_NAK);      //设置端点处于忙状态
 
  /* Initialize Endpoint Out 1 */
  SetEPRxAddr(ENDP1, ENDP1_RXADDR);     //设置接收数据的地址
  SetEPRxCount(ENDP1, 1);  //设置接收长度


  SetEPRxStatus(ENDP1, EP_RX_VALID);      //设置端点有效,可以接收数据

                                 需要在usb_conf.h中增加对ENDP1_RXADDR的定义:
#define ENDP1_RXADDR        (0xD8)

 

步骤五:修改原来在main函数中发送数据的处理。

这里我们使用圈圈前几天写的按键及摇杆驱动(见http://blog.ednchina.com/computer00/142610/message.aspx)。
修改主循环中的内容如下:
  while (1)
  {
    DelayXms(5);            //延时5ms
    KeyScan();              //扫描一次键盘
    if (KeyUp||KeyDown)
    {
      Joystick_Send(KeyPress); //发送按键
      KeyUp="0";               //清除事件
      KeyDown="0";
    }
  }

 

步骤六:在hw_config.c中修改Joystick_Send函数,根据不同的按键来发送按键情况,具体怎么修改这里就不说了,最后使用函数UserToPMABufferCopy将缓冲区中的数据复制到端点1的输出缓冲中,再使用函数SetEPTxValid(ENDP1)使端点1数据有效,从而发送出去。
对于输出,我们还需要增加一个回调函数来处理,因为原来的输出端点1的回调函数是个空函数。在usb_conf.h中找到#define  EP1_OUT_Callback NOP_Process 一行,它将端点1输出回调函数定义为空处理函数。我们将它删除,换成我们自己的回调处理函数:void EP1_OUT_Callback(void);。然后回到main.c中增加该函数的实际代码,它主要用来控制LED的状态。在使用LED之前,当然要记得初始化这些IO口为输出状态,以及使能PC口的时钟,还有前面的键盘扫描也要增加对相应的IO口初始化,这些初始化代码在void Set_System(void)函数中处理。LED连接在PC口上,在stm32f10x_conf.h文件中,将#define _GPIOC宏使能,原本该宏是被注释掉的,这样会提示GPIOC没有定义。

处理接收数据的回调函数发送数据的函数代码分别如下:

void EP1_OUT_Callback(void)
{
 u8 DataLen; //保存接收数据的长度
 u8 DataBuffer[64]; //保存接收数据的缓冲区
 
 DataLen = GetEPRxCount(ENDP1); //获取收到的长度
 PMAToUserBufferCopy(DataBuffer, ENDP1_RXADDR, DataLen); //复制数据
 SetEPRxValid(ENDP1); //设置端点有效,以接收下一次数据
 
 if(DataLen==1) //收到一字节的输出报告
 {
  //D0位表示数字键盘灯,D1位表示大写字母锁定灯
  if(DataBuffer[0]&0x01)  //数字键盘灯亮
  {
   GPIOC->BSRR=(1<<6); //亮LED3
  }
  else
  {
   GPIOC->BRR=(1<<6); //灭LED3
  }
  if(DataBuffer[0]&0x02) //大写字母锁定键
  {
   GPIOC->BSRR=(1<<7); //亮LED2
  }
  else
  {
   GPIOC->BRR=(1<<7); //灭LED2
  }  }  }


void Joystick_Send(u8 Keys)
{
  u8 Buffer[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  u8 i;
  i="2";
        //对各个按键进行处理。注意,由于这里的摇杆5个按键
        //不可能同时按下,所以返回的普通键数量不会超过6个。
        //如果你的键盘同时按下的普通键能够超过6个的话,就需要做
        //点特殊处理了,将后面6字节全部设置为0xFF,表示按键无法识别。
  if(Keys&KEY_UP)
  {
   Buffer[i]=0x52; //Keyboard UpArrow
   i++;
  }
  if(Keys&KEY_DOWN)
  {
   Buffer[i]=0x51; //Keyboard DownArrow
   i++;
  }
  if(Keys&KEY_LEFT)
  {
   Buffer[i]=0x50; //Keyboard LeftArrow
   i++;
  }
  if(Keys&KEY_RIGHT)
  {
   Buffer[i]=0x4F; //Keyboard RightArrow
   i++;
  }
  if(Keys&KEY_2)
  {
   Buffer[i]=0x39; //Keyboard Caps Lock
   i++;
  }
  if(Keys&KEY_3)
  {
   Buffer[i]=0x53; //Keypad Num Lock and Clear
   i++;
  }
  if(Keys&KEY_SEL)
  {
   Buffer[i]=0x28; //Keyboard Return (ENTER)
  }
           /*copy mouse position info in ENDP1 Tx Packet Memory Area*/
  UserToPMABufferCopy(Buffer, GetEPTxAddr(ENDP1), 8);
           /* enable endpoint for transmission */
  SetEPTxValid(ENDP1);
}

 

程序运行后,可在设备管理器中看到新增加的USB人体学输入设备和一个键盘设备。如下图:

图片.png 

 

【 初涉USB,初学者USB入门总结——枚举

USB】

1. 不但固件程序需要编写;  

2. PC端的驱动也要编写;

3. 而且驱动写好了还要写个上机位才能看出效果;

这样调试起来十分困难,建议从USB的键盘,鼠标开始做,了解清楚了,再做自己的协议就比较简单了。

 

------------------------------------(第一)设备插入-------------------------------------------------------------

1) 主机会轮回查询各个USB端口,主机检测到D+与D-之间有电压差,就认为有新的设置接     入。主机等待100ms后发出复位请求。设备接到复位请求后将产生一个外部中断信号。

 

-----------------------------------(第二)枚举过程(检测到设备插入以后)---------------------------------

2) 主机这时候只是知道有新的设备插入了,但是不知道插进来个什么东西,所以就开始询问它是什么设备,怎么用,负荷能力怎么样。这个时侯就进入了枚举过程

步骤1:(设备描述符)

地址:因为刚刚插入的设备没有分配地址,就用默认地址0;

主机:首先发送一个Get_deor(获取设备描述符)指令包;

设备:设备接到包后就开始解析包(其实就是你在固件程序里判断处理),然后按固定格式       返回自己设备的设备描述符

目的:这一步主要是让主机知道你的USB设备的基础属性,比如支持的传输数据长度,电流      负荷多少,支持那个USB版本,以后方便电脑找驱动的PID,VID。

步骤2:(配置描述符)

分配地址:主机知道设备的数据长度和电流大小后,然后就是给设备分配一个属于它的地址;

主机:给设备一个地址后,就开始询问设备的具体配置(配置描述符)。 首先发送一个试探      性的设备配置请求Get_configuration(要求固定返回9个设备配置字)指令包;

设备:接到指令包后就开始发送9字节的设备配置字,其中包括设备的配置字的总长度;

主机:这样主机就知道设备的配置到底有多长,然后再发一次设备配置请求指令包;

设备:这时设备就开始上传所有的配置字

主机:这个时侯主机就已经很明白你的工作方式和各种特性,然后就可以正常工作了;

目的:配置(以后章节详细说明)要求说明自己的名字什么的,这里还要上传字符串描述符;      如果是鼠标或者键盘还要上传报告描述符。

 

----------------------------------------------(第三)正常数据阶段-------------------------------------------------

这个时侯你已经被主机正式接受并且注册了,你可以通过自己写测试驱动或通用驱动与电脑进行通讯了。

对于USB的工作我这里做个比方:

     主机好比一个公司,你就是USB设备,要进入公司首先要面试(枚举),你到了面试现场(第一次插入设备),面试官首先了解到你的外表,性别已经你要应聘的岗位(设备描述符),然后给你一个号,以后就开始按号叫人,当你被叫到就开始问你的专业知识,性格等(配置描述符),如果你比较合适(通过了枚举)你就会录取了,并且注册一个你的信息到公 司(驱动安装,并且写入注册表)。等你下次来公司,只要把工号(PID,VID)报上,就知道是你来了。

【 初涉USB,初学者USB入门总结——设备固件程序

主机:主机给设备设置地址,主机会通过固定的通道(point 0)发送一个“设定地址”包;

设备:设备主控接到包后会产生中断,并且把响应的状态保存在相应的寄存器中;

目的:我们只要在中断程序中判断各个寄存器就能完成主机的任务。

 

【 初涉USB,初学者USB入门总结——数据包阐述

步骤一:了解USB上传的什么东西,以什么格式传数据;

1) 各种总线(USB也是一种总线)的数据传输都是以固定的层次协议进行的;

2) 所谓的层次是表达一种依附关系,上层要依赖于底层,上层以底层为基础,上层只需要关心自己的东西就行了;

3) 要实现两个机器(机器的范围比较广,可以是电脑,交换机,单片机)的通信总是要有一个载体才可以,对于机器当然是电平高低为载体

具体的说:机器甲要告诉机器乙一件事情(比如说一条指令),那么机器甲可以通过一根线     (串行数据总线)连到机器乙的一个IO口上,甲发送一个个的高低电平,乙固定时间    检测自己的这个IO口,然后逐个记录下放到自己的缓冲里,这样乙就收到甲送的数据了。

这里也打个比方:比如人与人进行交流,我们当然是通过说话了,物理层就是空气和传输的声波,数据链路层就是我们说的每一个字,物理层就是空气,负责把我们说的话转换成声波传给对方,数据链路层负责让对方能正确的听到每个字,如果听的不清可以告诉对方重新说一遍。经过上述的两个底层,就可以保证每一位数据可以正确的传到对方那里去。

 

步骤二:解析数据代表了什么,一般来说,数据都是以一串数为单位,一般称为一个包,          机器间传输都是以一个以包为单位传出的,就像人们说话都是以一句话为单位输          出一样。每一个包包含有许多位数据,这些数据又分段表示不同的意义。

如图 一,这是一个USB令牌阶段的包:(数据包 è 数据位 è每段数据位的意义)

   1. Sync是同步数据(相当于说话时先打个招呼,告诉对方要跟他说话了);

   2. PID是包标示(告诉对方这个包是干什么用的);

   3. ADDR是对方的地址(叫对方的名字);

   4. ENDP是用端点几通讯(----------);

   5. CRC5是校验位(判断这个包是否在传输中出错),EOP是包结束。

       |--------------------------------------------------------|

       |   Sync  |  PID  |  ADDR  |  ENDP  |  CRC5  |  EOP      |

       |________________________________________________________|

 图一
USB 的数据包又分为三种,一个是令牌包,一个是数据包,另一个是握手包

一、 每一次的USB通讯事务处理都是以令牌包开头,告诉对方要跟谁说话,这句话是干嘛的。

二、 如果要求有数据传输,则下一步就是数据包,

三、 另外如果要求对方要有反馈,则会发出握手包。

四、 令牌包又简单的包括OUTINSTEP三种类型;

   (1).OUT是用于主机告诉设备主机要向USB设备发送数据,

   (2).IN是用于主机告诉设备要上传数据,

   (3).而STEUP是用于主机向USB设备发送配置信息,在枚举过程中会用到。

Ø 另外数据包和握手包的具体格式什么的,可以参照详细的协议。

Ø 可以看到在所以的通讯过程中,主机都是发起者,不管是主机发送数据到USB设备还是USB设备发送数据到主机,都必须受主机控制。

 

图二为一次事务的过程:

        令牌阶段   ——》        数据阶段     ——》     握手阶段

                                图二

 

这个过程可以这样描述,甲和乙对话,甲是老板,乙是职员。第一节已经讲过了,乙面试就是枚举,在这个过程中,甲多段的发送STEP令牌包给乙,乙收到后如果要反馈数据,就发数据包给甲,甲正确接收后,跟甲握握手,表示这次对话成功。
乙被录取后,甲会分派任务(OUT),这时甲对乙说有任务给你(令牌阶段),然后乙就开始听,甲说你的任务就是记录数据并且上报(这段话就是数据包),乙说好的(握手包)。乙开始正式工作,并且记录数据。过了一段时间,甲开始要求提交数据(IN),乙把数据报告给甲(数据阶段),甲说好(握手成功)。这里乙不能主动的去向老板汇报,只能被动的干活。

 

【 初涉USB,初学者USB入门总结——USB通讯设备快速开发(固件,驱动

经过上述三节的描述,对USB应该已经有了初步的认识,其中具体的协议(比如各个描述符的定义什么的)这里不做描述了。下面我以一个实例来详细说明快速开发USB设备的步骤。

一、设定规划

凡事预则立,不预则废,所以开发一个小小的USB也要稍微规划一下,比如想象要实现什么功能,传输的数据协议什么的。

 

二、固件编程

固件编程说白了就是写单片机程序,要实现USB一般可以使用带USB功能的单片机,再就是加一个专用的USB芯片。这里以内部集成USB功能单片机为例:

固件的USB开发一般就是先使能USB,使能USB时钟,使能各个USB控制中断(挂起,复位,标准请求,写入,写出等)然后USB就能正常工作了,这时候不如不写别的东西,电脑就可以检测出有USB设备插入了,具体的反应是在设备管理器里会发现闪了一下说明发现了新的USB设备,接下来电脑会发送各种标准请求,因为这个时候你的程序还没写完整,对这些请求不会有反应,所以电脑不可能识别出是什么东西。

接下来的工作就是 在中断中 响应电脑传来的各种标准请求。当必要的请求都被正确的响应的话,这个时候如果电脑里有正确的驱动,电脑就会去加载这个驱动,如果是第一次插入这个设备,还要把驱动安装一下,然后设备就进入正常工作了,电脑会显示“这个USB已经成功安装并可以应用了”。

 

【端点(endpoint)的概念】

一般一个USB设备都会有数个端点端点就是一个数据缓冲控制区(FIFO),每一个缓冲区相当于有一个出口一个进口的池子,数据通过进口进入到池子,然后你再在固件里去用这些数据。固件往电脑写数据,也是把数据先放到池子里,然后打开出口,就可以干自己的事情,不用一个个的把数据发出了,池子的出口自动把数据流出。

一般的端口0是用来做标准请求响应用的,也就是在枚举阶段用到。我一般把端口1定义为出(OUT),端口2定义为入(IN)(注意,这个OUT和IN是相对与电脑的,也就是说OUT是数据从电脑出去到设备,IN是设备的数据进入电脑)。这些定义也是在标准请求中去告诉电脑的。接下来就可以实现与电脑的通讯了,你把数据放到相应的池子里就行了。

下面就可以自己定义通讯的数据格式了。比如控制开发板上的8个LED的第一个灯亮,那么上位机发送数据0x55,0x01,0x80,0xaa。我们就可以规定第一个数据是启示位,遇到这个表明开始一次控制指令,0x01表示这个是控制灯亮暗的指令,0x80表示LED的控制数据,最高位是1,表示第一个亮,其他位是0,表示都暗。最后一个数据是0xaa,表示这是结束。其实所谓的数据协议不过就是自己定义的一套让通讯双方都能正确理解对方的数据格式。

端点(endpoint):位于 USB 设备或主机上的一个数据缓冲区,用来存放和发送 USB 的各                  种数据,每一个端点都有惟一的确定地址。

上行、下行:设备到主机为上行,主机到设备为下行

A. 数据在 USB 线里传送是由低位到高位发送的。

B. USB 数据是由二进制数字串构成的,首先数字串构成域(有七种),域再构成包,包再构成事务(IN、OUT、SETUP),事务最后构成传输(中断传输、并行传输、批量传输和控制传输)。

 

上位机是指人可以直接发出操控命令的计算机,一般是PC,屏幕上显示各种信号        变化(液压,水位,温度等)。

下位机是直接控制设备获取设备状况的计算机,一般是PLC/单片机之类的。

1. 上位机发出的命令首先给下位机,

2. 下位机再根据此命令解释成相应时序信号直接控制相应设备。下位机不时读取设备状态数据(一般为模拟量),转换成数字信号反馈给上位机。

Ø 简言之如此,实际情况千差万别,但万变不离其宗上下位机都需要编程,都有   专门的开发系统

 

二、USB HID类可采用的通信管道

  所有的HID设备通过USB的控制管道(默认管道,即端点0)和中断管道与主机通信。

表1、USB HID规范定义的HID设备可用端点



管道

要求

说明

控制(端点0)

必须

传输USB描述符、类请求代码以及供查询的消息数据等

中断输入

必须

传输从设备到主机的输入数据

中断输出

可选

传输从主机到设备的输出数据

  控制管道主要用于以下3个方面:

· 接收/响应USB主机的控制请示及相关的类数据

· 在USB主机查询时传输数据(如响应Get_Report请求等)

· 接收USB主机的数据

 

  中断管道主要用于以下两个方面:

· USB主机接收USB设备的异步传输数据

· USB主机发送有实时性要求的数据给USB设备

从USB主机到USB设备的中断输出数据传输是可选的,当不支持中断输出数据传输时,USB主机通过控制管道将数据传输给USB设备。

 

HID设备的描述符除了5个USB的标准描述符(设备描述符、配置描述符、接口描述符、端点描述符、字符串描述符,还包括3个HID设备类特定描述符:HID描述符、报告描述符、实体描述符。

 

 除了HID的三个特定描述符组成对HID设备的解释外,5个标准描述符中与HID设备有关的部分有:

1. 设备描述符中bDeviceClass、bDeviceSubClass和bDeviceProtocol三个字段的值必须为零。

2. 接口描述符中bInterfaceClass的值必须为0x03;

bInterfaceSubClass的值为0或1,为1表示HID设备符是一个启动设备(Boot Device,一般对PC机而言才有意义,意思是BIOS启动时能识别并使用您的HID设备,且只有标准鼠标或键盘类设备才能成为Boot Device。如果为0则只有在操作系统启动后才能识别并使用您的HID设备),bInterfaceProtocol的取值含义如下表所示:

表2、HID接口描述符中bInterfaceProtocol的含义


bInterfaceProtocol的取值(十进制)

含义

0

NONE

1

键盘

2

鼠标

3~255

保留

 

USB 的重要关键字 :

1、端点:位于 USB 设备或主机上的一个数据缓冲区,用来存放和发送 USB 的各种         数据,每一个端点都有惟一的确定地址,有不同的传输特性(如输入端、输        出端点、配置端点、批量传输端点)

2、数据是如何在 USB 传输线里面传送的 ?

答: 数据在 USB 线里传送是由低位到高位发送的。

 

USB固件库

USB 设备(DEVICE)从来只是被动触发,USB 主机(HOST)掌握主动权,发送什么数据,什么时候发送,是给设备数据还是从设备请求数据,都是由 USB 主机完成的,

USB 设备只是配合主机完成设备的枚举、数据方向和大小。根据数据特性再决定该不该回复该如何回复、该不该接收该如何接收这些动作。

 

HID接口固件设计与实现

  该设备采用C8051F120微控制器和PDIUSBD12芯片来实现,如图3所示。

图片.png

 

USB OTG:由于USB是主从模式,设备与设备之间、主机与主机之间不能互连,为了          解决这个问题,扩大USB的使用范围,就出现了USB OTG(On The Go)。

 

 


  • 目录
    • 相关问题
    评论(0)
    评论
    • 还没有评论,发表第一个评论吧

    0 0 15 0 2
    提问 回答 资料 博客 粉丝
    近期下载
    • 暂无下载记录