现在很多电脑已经不带232了,特别是手提电脑。这使很多使用手提在外调试人员非常不方便。或许你可以买一条市面上usb转232转换线,但这些线抗干扰不是太好,在一些干扰大的地方会发生连接中断的问题,所以往往要加光耦隔离器。在一些高端的单片机一般带USB接口,如果可以使用这些接口做一个USB的虚拟com口将会非常实用,但是使用USB一般要编写上位机驱程。没有windows驱程编写基础的朋友一般很为难。其实微软的CDC类中含有这一类USB转com的类,Windows也自带这方面的驱程。就像市面上的usb鼠标,u盘一样,windows里面已经有了他们的驱动函数库,只要我们按照windows的CDC描述来配置USB就可以了。

  关于CDC的类描述类容请参考 Universal Serial Bus Class Definitions for Communication Devices 的PDF文件。它是下面所有内容的纲领。

下面讲解下制作步骤: 
1:把对应的描述符发送出去:下面是发送内容

const USB_DEVICE_DESCRIPTOR DeviceDescr =
{
    // device descriptor
    0x12,
    DESC_DEVICE,
    LE_WORD(0x0101), // bcdUSB 

    0x02, // bDeviceClass
    0x00, // bDeviceSubClass
    0x00, // bDeviceProtocol 

    MAX_PACKET_SIZE0, // bMaxPacketSize 

    //设备ID
    LE_WORD(0xFFFF), // idVendor
    LE_WORD(0x0005), // idProduct
    LE_WORD(0x0100), // bcdDevice 

    /* 不要使用原来的ID
    0x71,0x04, // PHILIPS公司的设备ID         Vendor ID = PHILIPS Semiconductor,Inc.
    0x78,0x23, // 设备制造商定的产品ID         Product ID
    0x00,0x01, // 设备系列号                   Device release number in binary-coded decimal
    */ 

    0x01, // iManufacturer
    0x02, // iProduct
    0x03, // iSerialNumber
    0x01, // bNumConfigurations
}; 

const USB_DESCRIPTOR usb_descr =
{
    // configuration descriptor
    {
        0x09,
        DESC_CONFIGURATION,
        LE_WORD(), // wTotalLength
        0x02, // bNumInterfaces
        0x01, // bConfigurationValue
        0x00, // iConfiguration
        0xC0, // bmAttributes
        0x32 // bMaxPower
    }, 

    // control class interface
    {
        0x09,
        DESC_INTERFACE, // 4
        0x00, // bInterfaceNumber
        0x00, // bAlternateSetting
        0x01, // bNumEndPoints
        0x02, // bInterfaceClass
        0x02, // bInterfaceSubClass
        // 0x01, // bInterfaceProtocol, linux requires value of 1 for the cdc_acm module
        0x00, // bInterfaceProtocol, linux requires value of 1 for the cdc_acm module
        0x00 // iInterface
    }, 

    // header functional descriptor
    0x05,
    CS_INTERFACE,
    0x00,
    LE_WORD(0x0110), 

    // call management functional descriptor
    0x05,
    CS_INTERFACE,
    0x01,
    0x01, // bmCapabilities = device handles call management
    0x01, // bDataInterface 

    // ACM functional descriptor
    0x04,
    CS_INTERFACE,
    0x02,
    0x02, // bmCapabilities 

    // union functional descriptor
    0x05,
    CS_INTERFACE,
    0x06,
    0x00, // bMasterInterface
    0x01, // bSlaveInterface0 

    // notification EP
    0x07,
    DESC_ENDPOINT,
    INT_IN_EP, // bEndpointAddress
    0x03, // bmAttributes = intr
    LE_WORD(), // wMaxPacketSize
    0x0A, // bInterval 

    // data class interface descriptor
    0x09,
    DESC_INTERFACE,
    0x01, // bInterfaceNumber
    0x00, // bAlternateSetting
    0x02, // bNumEndPoints
    0x0A, // bInterfaceClass = data
    0x00, // bInterfaceSubClass
    0x00, // bInterfaceProtocol
    0x00, // iInterface 

    // data EP OUT
    0x07,
    DESC_ENDPOINT,
    BULK_OUT_EP, // bEndpointAddress
    0x02, // bmAttributes = bulk
    LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize
    0x00, // bInterval 

    // data EP in
    0x07,
    DESC_ENDPOINT,
    BULK_IN_EP, // bEndpointAddress
    0x02, // bmAttributes = bulk
    LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize
    0x00, // bInterval 

    // string descriptors
    0x04,
    DESC_STRING,
    LE_WORD(0x0409), 

    0x0E,
    DESC_STRING,
    , , , , , , 

    0x14,
    DESC_STRING,
    , , , , , , , , , 

    0x12,
    DESC_STRING,
    , , , , , , , , 

    // terminating zero 

}; 

这里要注意的是USB_DEVICE_DESCRIPTOR里面的设备ID不要使用原来的厂家ID,按照上面给出的,这个值对应INF文件里的: 
[GSerialDeviceList] 
%GSERIAL%=GSerialInstall, USB\VID_FFFF&PID_0005 
PID和VID

每种USB设备都有一个PID和VID。VID是生产商的代号,PID是产品的代号,每个代号都是一个双字节的整数。PID和VID不能随意设置,它是由USB标准协会进行分配的,就像IP地址的分配一样。一个USB的PID/VID许可需要花费1500美元,在很多情况下,特别对小公司是一个很大的费用。针对这种情况,有免费的PID/VID对,分别适用于HID类、CDC类和通用类设备,使用AVRUSB的用户可以免费使用它们,这样对于大多数应用来说就不用再自己去申请PID/VID了。 
PID和VID在驱动程序和用户程序中都将用到,它是windows识别USB设备的关键参数,用户程序也需要通过PID和VID来查找相应的USB设备。 
它是windows用来识别usb设备,和查找对应驱程的标识号。如果枚举成功,它会提示安装驱程。

它是windows用来识别usb设备,和查找对应驱程的标识号。如果枚举成功,它会提示安装驱程。

所以要识别为CDC类设备,请使用上面给出的ID,而不要使用厂商ID。可能你不想改变原来USB设备的ID,而把INF文件的[GSerialDeviceList]改为和原来的厂商ID,这样我也试过,可以识别出设备,

但是不能在com8里面出现com的参数设置项。(下面的端口设置不会出现),而且出现的COM8不能操作,就是不能在串口助手使用com8.

使用程序给出的配置符才能识别为com,而且出现的端口才能使用。我的解释是这个ID对应CDC的免费PID和VID,所以windows能正确配置设备。

关于枚举过程,你可以参考我给出的资料,或者自己搜索,这里我不再叙述。调试过程可以使用bus_hound进行一步步跟踪调试,或者在单片机程序加入printf语句(通过232口)来跟踪单片机的USB和window的通信数据流。 
下面是我采用第二种方法,在单片机固件程序安插printf语句,使用串口助手截获的数据,供大家参考用。 
step_ packet表示收到step包;req代表上位机发来的请求数据,ANS表示返回数据,如果ANS=为空代表返回一个空包。

step_ packet 
req=80,6,0,1,0,0,40,0, 
ANS=12,1,1,1,2,0,0,40,ff,ff,5,0,0,1,1,2,3,1, 
ANS= 
step_ packet 
req=0,5,1,0,0,0,0,0, 
ANS= 
ANS= 
step_ packet 
req=80,6,0,1,0,0,12,0, 
ANS=12,1,1,1,2,0,0,40,ff,ff,5,0,0,1,1,2,3,1, 
ANS= 
step_ packet 
req=80,6,0,2,0,0,9,0, 
ANS=9,2,43,0,2,1,0,c0,32, 
ANS= 
step_ packet 
req=80,6,0,3,0,0,ff,0, 
step_ packet 
req=80,6,0,2,0,0,ff,0, 
ANS=9,2,43,0,2,1,0,c0,32,9,4,0,0,1,2,2,0,0,5,24,0,10,1,5,24,1,1,1,4,24,2,2,5,24,6,0,1,7,5,81,3,8,0,a,9,4,1,0,2,a,0,0,0,7,5,2,2,c0,0,0,7,5,82,2, 
ANS=c0,0,0,4,3,9,4,e,3,4c,0,50,0,43,0,55,0,53,0,42,0,14,3,55,0,53,0,42,0,53,0,65,0,72,0,69,0,61,0,6c,0,12,3,44,0,45,0,41,0,44,0,43,0,30,0,44,0,45,0,0, 
ANS= 
step_ packet 
req=80,6,0,3,0,0,ff,0, 
step_ packet 
req=80,6,0,3,0,0,ff,0, 
step_ packet 
req=80,6,0,1,0,0,12,0, 
ANS=12,1,1,1,2,0,0,40,ff,ff,5,0,0,1,1,2,3,1, 
ANS= 
step_ packet 
req=80,6,0,2,0,0,9,1, 
ANS=9,2,43,0,2,1,0,c0,32,9,4,0,0,1,2,2,0,0,5,24,0,10,1,5,24,1,1,1,4,24,2,2,5,24,6,0,1,7,5,81,3,8,0,a,9,4,1,0,2,a,0,0,0,7,5,2,2,c0,0,0,7,5,82,2, 
ANS=c0,0,0,4,3,9,4,e,3,4c,0,50,0,43,0,55,0,53,0,42,0,14,3,55,0,53,0,42,0,53,0,65,0,72,0,69,0,61,0,6c,0,12,3,44,0,45,0,41,0,44,0,43,0,30,0,44,0,45,0,0, 
ANS= 
step_ packet 
req=0,9,1,0,0,0,0,0, 
ANS= 
ANS= 
step_ packet 
req=a1,21,0,0,0,0,7,0, 
ANS=80,25,0,0,0,1,7, 
ANS= 
step_ packet 
req=21,22,0,0,0,0,0,0, 
ANS= 
ANS=

2:关于inf文件和sys驱动 
.inf文件可用提供模板进行快速定制。 文件格式非常简单,大多数Windows程序员都能快速读懂。 即使对于不太熟悉的人,也可以很快识别中文件由不同部分组成,每个部分的标题包含在方括号中,在相应部分内有一或多个由参数名称和参数值组成的正文。 在整个文件中,只能少数几个部分需要用户定制,包括: 
  •[Device List] 部分包括从USB-IF获得(许可)的公司和应用独有的VID/PID号码对以及其它信息。 
•[Strings]部分包含操作系统在即插即用阶段在不同的对话框中使用的不同字符串和标识,以及在硬件管理器中标识设备的字符串和标识。

本文提供的inf文件不需要进行修改,但用户可以对•[Strings]部分进行修改,可以改变设备列表的设备描述字符串。 
[Strings] 
LINUX = "spxwh" 
GSERIAL = "FX2N PLC COM" 
GSERIAL_DISPLAY_NAME = " FX2N PLC COM " 
上面会把制造商显示为spxwh, 设备描述为FX2N PLC COM   (三菱PLC仿真COM口)

.sys文件要从C:\WINDOWS\Driver Cache\i386的.cab file导出(因为windows已带这个CDC类的驱程了),但是为了方便我直接给出来了usbser.sys,注意名字不要改变,应为在inf文件内已经进行了设置。

3:安装inf文件 
如果一切顺利(第一次插入会提示安装驱程,安装提供的INF文件),此时即插即用已经完成了安装过程,一个新的串行设备就会出现在硬件管理器中。 系统会自动使用下一个可用的端口号为它指定一个名称(例如,已经安装了COM2和COM1,就会出现COM3)。 用户可以使用已经编写好用来访问实际COMx端口的程序来访问这个端口(如所有Windows软件中的超级终端程序)。 连接好后,除了通讯速度提高了,功能上没有什么区别。

参考文章与资料: 
1. Universal Serial Bus Class Definitions for Communication Devices 
2. 将串行应用移植到USB接口的简便方法 
3.   AVRUSB技术探讨

点击此处下载 ourdev_435236.rar(文件大小:7.57M) (原文件名:USB HID编写资料.rar)

参考里面的    HID编写.doc

CDC 虚拟com口的更多相关文章

  1. Windows系统添加虚拟串口及CanToolApp功能1的实现

    项目开始尝试用com0com添加虚拟串口,但是遇到了问题,系统中可以看到添加的虚拟串口,但是用C#无法获取串口.经过多次尝试后,决定换用Virtual Serial Port Driver添加虚拟串口 ...

  2. 痞子衡嵌入式:飞思卡尔i.MX RTyyyy系列MCU硬件那些事(2.1)- 玩转板载OpenSDA,Freelink调试器

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是飞思卡尔i.MX RTyyyy系列EVK上板载调试器的用法. 本文是i.MXRT硬件那些事系列第二篇,第一篇痞子衡给大家整体介绍了i.M ...

  3. 织女星开发板调试器升级为Jlink固件

    前言 为了能使用板载的FreeLink调试器来调试RISC-V内核,我们需要把默认的CMSIC-DAP固件,升级为JLink固件,固件升级之后,通过选择使用不同的驱动程序,来支持ARM内核还是RISC ...

  4. UP Board 串口使用心得

    前言 原创文章,转载引用务必注明链接. 本文使用Markdown写成,为获得更好的阅读体验和正常的图片.链接,请访问我的博客: http://www.cnblogs.com/sjqlwy/p/up_s ...

  5. iOS homekit使用说明

    本文由CocoaChina翻译组成员iBenjamin_Go和浅夏@旧时光翻译自苹果开发文档:HomeKit Developer Guide,敬请勘误. 本文档内容包括 第一部分:简介 第二部分:启用 ...

  6. 把USB打印机映射到LPT端口

    把USB打印机映射到LPT端口(pos小票机测试成功)2010-12-23 18:11:00| 分类: 編程 | 标签: |字号大中小 订阅 注释:在DOS命令行下运行以下命令(以下为示例,根据实际情 ...

  7. [SAM4N学习笔记]UART的使用

    一.准备工作:      将上一节搭建的工程复制一份,命名为"3.uart".这一节主要讲如何使用SAM4N的UART功能,实现串口的收发. 二.程序编写: 细心看数据手册的朋友也 ...

  8. 彻底解决COM端口被占用(在使用中)问题的办法

    今天就遇到这个问题了串口调试的时候发现usb转串口使用的是COM8而串口调试助手里面只有COM1到4,我想去该COM口发现COM1到7都在使用中,找了好多办法都不行,后面在网上找到这篇解决办法的文章, ...

  9. [svc]linux下网桥-docker网桥

    网桥和交换机 2口交换机=网桥 交换机: 工作在数据链路层,根据源mac学习(控制层),目的mac转发(数据层). linux的网卡 vmware workstation中的桥接 参考: http:/ ...

随机推荐

  1. 用PHP操作http中Etag、lastModified和Expires标签

    http://blog.hehehehehe.cn/a/10994.htm 客户端通过浏览器发出第一次请求某一个URL时,根据 HTTP 协议的规定,浏览器会向服务器传送报头(Http Request ...

  2. solr-tomcat 中文乱码

    <Connector URIEncoding="UTF-8" port="8080" protocol="HTTP/1.1" conn ...

  3. IOS- 最简单的反向传值- block

    block 常用于反向传值 声明 返回值类型 (^block)(参数列表) 调用 闭包的名字=^(参数列表){}: 闭包的名字(): 如: void(^aaaaa)(int num,NSString ...

  4. 记个maven无法识别JAVA_HOME的问题 Error: JAVA_HOME is not defined correctly.

    Error: JAVA_HOME is not defined correctly. We cannot execute /Library/Java/JavaVirtualMachines/jdk1. ...

  5. Java实战之02Hibernate-03Session中的常用方法

    九.Session中的常用方法 1.save方法 都是临时态————>持久态 2.persist方法 作用: 持久化临时态对象. 与save方法的区别: 开始了事务:persist和save没有 ...

  6. Container容器控件的使用、Hbox与Vbox布局管理器的使用、以及AjaxAction前后台事件响应

    1.由于有前后台交互功能,需要在Spring上下文中注册一个用于提供服务的bean,对于这个bean使用Spring提供的@Component标注,如果需要使用@Component注解,需要在项目中W ...

  7. NOIP201501&&02

    NOIP201501金币 试题描述 国王将金币作为工资,发放给忠诚的骑士.第一天,骑士收到一枚金币:之后两天(第二天和第三天) ,每天收到两枚金币:之后三天(第四.五.六天) ,每天收到三枚金币:之后 ...

  8. poj3190 stall revertation

                                                                                                Stall Re ...

  9. MFC: Create Directory

    Original link: How to check if Directory already Exists in MFC(VC++)? MSDN Links: CreateDirectory fu ...

  10. SSD论文优秀句子

    1. Nonvolatile memory(e.g., Phase Change Memory) blurs the boundary between memory and storage and i ...