前言

USB接口作为PC上最流行和通用的接口,具备可连接多种类型的设备,连接简单,即插即用,支持热插拨,多数应用场景下不需要提供独立的电源,高传输速率,高可靠性等特点,被越来越多的产品作为首选接口作为接入PC的连接方式。为了简化USB设备的开发和接入到PC系统,微软开发了WinUSB,可以将Winusb.sys作为设备功能驱动程序安装,并提供WinUSB API供应用程序访问设备。一直以来,除了USB HID设备,其他类型的设备在WINDOWS环境下需要安装驱动程序才能工作。要实现USB设备免驱,就只能使用HID设备。而HID设备传输速度慢,在有些场合必须使用Bulk类型进行批量传输时,就必须使用第三方驱动或者自己开发一个驱动,使得项目开发非常麻烦。现在好了,自从微软推出了WinUSB,在微软的最新操作系统上实现简单的Bulk类型批量传输也变得非常的方便快捷,在研发过程当中或者一些对于差异化要求不高的场合,是非常适用且容易实现的。本文致力于实现一个最简单的WinUSB通信系统,以满足此类需求。

如何让嵌入式设备枚举成WinUSB设备

系统通过USB描述符来确定以何种USB Class类型来工作。如果希望WINDOWS能够将嵌入式设备识别为WinUSB设备,则其描述符至少应当包含以下字段:

1、支持 OS 字符串描述符:

为了让 USB 驱动程序堆栈了解设备支持扩展的特征描述符,设备必须定义存储在字符串索引 0xEE 处的 OS 字符串描述符。在枚举过程中,驱动程序堆栈查询字符串描述符。如果存在描述符,驱动程序堆栈会假定设备包含一个或多个 OS 特征描述符和检索这些特征描述符所需要的数据。检索的字符串描述符具有 bMS_VendorCode 字段值。该值为1表示USB驱动程序堆栈必须用来检索扩展特征描述符的供应商代码。

#define bMS_VendorCode              ( 0x01 )

// "MSFT100" : index : 0xEE : langId : 0x0000

const U8 OS_StringDescritpor[ ] =

{ 0x12,  0x03,  'M',  0,  'S',  0,  'F',  0,  'T',  0,  '1',  0,  '0',  0,  '0',  0,  bMS_VendorCode,  0 };

2、设置兼容ID特征描述符:

const U8 WINUSB_ExtendedCompatId_Descritpor[ ] =

0x28, 0x00, 0x00, 0x00,           // dwLength

0x00, 0x01,                             // bcdVersion

0x04, 0x00,                             // wIndex

0x01,                                       // bCount

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,       // Reserved[7]

0x00,                   // bFirstInterfaceNumber

0x01,                  // RESERVED ( 0x01 )

'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,       // compactiableID[8]

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // subCompactiableID[8]

0x00, 0x00, 0x00, 0x00, 0x00, 0x00   // Reserved[6]

};

注:WinUSB还支持复合设备,对于单一传输类型最简系统,我们忽略复合设备的要求即可。compatibleID字段必须指定 "WINUSB" 作为字段值。其他可以根据需求更改。

3、注册设备接口 GUID描述符:

该描述符用于区分不同的WinUSB设备。

const U8 WINUSB_ExtendedProperty_InterfaceGUID_Descritpor[ ] =

0x8E, 0x00, 0x00, 0x00,  // dwTotalSize = Header + All sections

0x00, 0x01,                 // bcdVersion

0x05, 0x00,                 // wIndex

0x01, 0x00,                 // wCount

0x84, 0x00, 0x00, 0x00,     // dwSize -- this section

0x01, 0x00, 0x00, 0x00,     // dwPropertyDataType

0x28, 0x00,               // wPropertyNameLength  'D',0,'e',0,'v',0,'i',0,'c',0,'e',0,'I',0,'n',0x00,'t',0,'e',0,'r',0,'f',0,'a',0,'c',0,'e',0, 'G',0,'U',0,'I',0,'D',0,0,0,

0x4E, 0x00, 0x00, 0x00,     // dwPropertyDataLength : 78 Bytes = 0x0000004E

'{',0,'1',0,'2',0,'3',0,'4',0, '5',0,'6',0,'7',0,'8',0,'-',0,'1',0,'2',0,'3',0,'4',0,'-',0,'1',0,'3',0,'4',0,'4',0,'-',0,'1',0,'2',0,'3',0,'4',0,'-',0,'1',0,'2',0,'3',0,'4',0,'5',0,'6',0,'7',0,'8',0,'9',0,'A',0,'B',0,'C',0,'}',0,0,0

};// bPropertyData : WCHAR : L"{12345678-1234-1234-1234-123456789ABC}"

4、端点描述符:

按实际的需求的配置端点数量和类型,即可完成嵌入式设备的描述符配置了。

一般固件程序可以通过MCU厂家提供的范例程序进行修改,这里省略USB固件功能的说明。只要包含以上三个描述符中的必须的字段,就可以成功枚举成USB Device。枚举成功后在设备WINDOWS设备管理器中可看到类似设备,如下图1所示

图1 成功枚举为USB Device

如何编写PC应用程序与嵌入式设备进行USB通信

PC机软件相对来说比较简单,并且微软官方也给出了示例代码。唯一需要注意的是,对应的软件程序获取WinUSB设备句柄的GUID参数,需要与嵌入式设备的描述符中的GUID保持一致。GUID是WinUSB用以区分设备的唯一标志。GUID,是Globally Unique Identifier的简称,翻译为全局唯一标识符,是一种由算法生成的二进制数据,长度为128位的数字标识符。

具体实现步骤如下:

1、创建设备的文件句柄:

调用SetupDiGetClassDevs 获取设备信息集的句柄;

调用 SetupDiEnumDeviceInterfaces 枚举设备信息集中的设备接口并获取有关设备接口的信息;

调用 SetupDiGetDeviceInterfaceDetail 获取设备接口的详细信息,所获取的信息通过SP_DEVICE_INTERFACE_DETAIL_DATA结构返回。由于该结构大小无法提前获取,故需连续两次调用该函数,第二次调用时接口详细信息将填充到根据第一次调用返回值所确定大小的该缓冲区,通过缓冲内该结构的DevicePath成员中可获得“设备路径”。

2、获取设备的 WinUSB 接口句柄:

调用 WinUsb_Initialize通过传递在创建设备的文件句柄中创建的文件句柄。

3、查询设备以获取 USB 描述符:

接下来,查询设备以获取特定于 USB 的信息,如设备速度、接口描述符、相关端点及其管道。调用 WinUsb_QueryDeviceInformation 从设备的设备描述符请求信息。调用 WinUsb_QueryInterfaceSettings 并传递设备的接口句柄,以获得对应的接口描述符。调用 WinUsb_QueryPipe 获取有关每个接口每个终结点的信息。此步骤不是必须的,因为端点方向及传输特性由嵌入式设备描述符决定,是已知的。

4、向默认端点发送控制传输:

此步骤也不是必须的。一般都不通过默认端点发送有效载荷。

5、发送 I/O 请求:

将数据发送到设备的批量输入和批量输出端点,这些端点点可分别用于读取请求和写入请求。调用 WinUsb_ReadPipe 从设备的批量输入端点读取数据。调用 WinUsb_WritePipe 通过批量输出端点将数据写入设备。在嵌入式设备的输出端点内写入数据之后,就可以在PC端读出数据。反之,如果在PC端对嵌入式设备的输入端点写入数据,则嵌入式设备会产生一个USB端点写入事件,具体如何捕捉该事件,则由MCU厂家的产品硬件决定,产生相应的中断信息,供中断服务程序来判断。一般而言,芯片厂家会提供MCU的USB通信基础范例程序,在其基础上做简单的修改和适配即可。

6、释放设备句柄

在完成对设备的所有必要的调用之后,释放设备的文件句柄和 WinUSB 接口句柄。CloseHandle 释放由 CreateFile 创建的句柄。

WinUsb_Free 释放由 WinUsb_Initialize 返回的设备的 WinUSB 接口句柄。

至此,已经完成了嵌入式设备端固件的USB代码移植和PC端应用程序的编写,就可以实现USB免驱设备的通信方式了。

教程:实现WinUSB通信系统的最简单的方式相关推荐

  1. mysql 实例复制_MYSQL教程MySQL 复制详解及简单实例

    <MysqL教程MysqL 复制详解及简单实例>要点: 本文介绍了MysqL教程MysqL 复制详解及简单实例,希望对您有用.如果有疑问,可以联系我们. MysqL 复制详解及简单实例 主 ...

  2. 怎么把线稿提取出来_PS教程:提取线稿如此简单?三种方法总有一种适合你

    原标题:PS教程:提取线稿如此简单?三种方法总有一种适合你 部落窝教育,每天学习PS独家原创视频 在PS出现之前,如果我们喜欢某个动漫角色大概只能通过临摹的方式将人物线条勾勒出来,但PS的出现将提取线 ...

  3. .NET轻量级MVC框架:Nancy入门教程(二)——Nancy和MVC的简单对比

    在上一篇的.NET轻量级MVC框架:Nancy入门教程(一)--初识Nancy中,简单介绍了Nancy,并写了一个Hello,world.看到大家的评论,都在问Nancy的优势在哪里?和微软的MVC比 ...

  4. unity c 语言教程,程序丨Unity教程:如何用最简单的方式创建Simplex噪声?

    原标题:程序丨Unity教程:如何用最简单的方式创建Simplex噪声? 翻译:刘甜甜(青悠) 审校:周伟杰 (Senser) 在本篇教程中,你将学会创建Value噪声与Perlin噪声的替代噪声,即 ...

  5. devexpress控件教程 开发workflow设计器这么简单

    如果你的项目的OA,尤其是政府部门的OA,那么一定会涉及工作流这个功能.这个模块说大不大.说小不大,最头疼的就是它的设计器,一直没有合适的.虽然微软出了工作流的3.5和4.0版本,但也没有配套的设计器 ...

  6. 平板android怎么升级版本,[原创]最简单的方式为华硕平板电脑EeePad TF101升级Android 3.1教程...

    [原创]最简单的方式为华硕平板电脑EeePad TF101升级Android 3.1教程 (2011-06-23 22:43:52) 标签: 杂谈 Android 3.1上市了,华硕EeePad TF ...

  7. arm rtx教程_【RTX操作系统教程】第5篇 RTX操作系统库方式移植(超级简单).pdf

    武汉安富莱电子有限公司 武汉安富莱电子有限公司 WWW.ARMFLY.COM 安富莱STM32-V4开发板RTX教程 WWW.ARMFLY.COM 安富莱STM32-V4开发板RTX教程 第5章 RT ...

  8. 微软更新后,桌面出现“无法打开这个应用 请去windows应用商店”的问题最简单解决方式

    解决微软更新后,桌面出现"无法打开这个应用 请去windows应用商店"的问题最简单解决方式 网上的解决方法复杂而且不好用,所以根据自己的经验总结了一下,不一定对应你的问题,但对电 ...

  9. 最简单的方式构建 Tkinter 图形界面

    大家好,我是征哥,今天分享如何用最简单的方式,为你的 Python 程序穿上漂亮的衣服,行话是用 Python 构建漂亮的 GUI,GUI 就是 graphical user interface 的简 ...

最新文章

  1. linux 进程 内存 换入换出,linux - 在从bash进程替换完成输入后,如何继续发送到stdin? - 堆栈内存溢出...
  2. RedHat linux inittab详解
  3. 如何计算一年总共有多少周_美国计算机CS专业一年需要多少留学费用?
  4. Spring Boot 2.x基础教程:配置元数据的应用
  5. EOS绑定以太坊地址
  6. mysql表操作_MySQL表操作语句用法百科
  7. 计算机网络中对等层,【计算机网络】两个网络模型——OSI参考模型和TCP/IP模型...
  8. Sql为什么连接不上服务器上的数据库
  9. python 太灵活_Python中的灵活参数
  10. 美股数据获取 python_python3+tesseract获取美股PEG图像上的数据
  11. Mac 安装和配置 Maven
  12. 换热站实际应用程序:西门子200smart PLC与威纶通触摸屏换热站程序
  13. Arx常用代码《转》
  14. 服务器共享文档只读不可复制,局域网共享文件只读不存、共享文件只读不能复制设置法...
  15. AODV=DSR+DSDV
  16. 一个神奇的分布式计算框架:jini
  17. 2022最新酒桌小游戏小程序源码(附带流量主)
  18. kali linux 2.0安装教程,kali linux2.0安装vega
  19. Android 无障碍服务自动点击
  20. C/C++描述 LeetCode周赛 5473. 灯泡开关 IV

热门文章

  1. 互联网创业新思路,桔子拓客帮您一键解决流量难题
  2. 解决报错Cannot connect to the Maven process. Try again later. If the problem persists, check the
  3. go语言操作mongoDB之mgo
  4. C#大恒相机采集图片时图片上下对称折叠了
  5. 深度:戴尔中国十年之变
  6. 组合数有关的公式及常用求和【数学--排列组合】
  7. AMD完成对ATI并购 07年推CPU/GPU集成平台
  8. pycharm异常问题之Unable to save settings: Failed to save settings. Please restart PyCharm
  9. 大数据基础篇~JavaSE第一章
  10. 登录失败:用户帐户限制。可能的原因包括不允许空密码,登录时间限制,或强制的策略限制。 ...