搜索
bottom↓
回复: 23

CDC 虚拟com口

[复制链接]

出0入0汤圆

发表于 2009-4-10 18:13:33 | 显示全部楼层 |阅读模式
现在很多电脑已经不带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(67),                                // 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(8),                                        // 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,
        'L', 0, 'P', 0, 'C', 0, 'U', 0, 'S', 0, 'B', 0,

        0x14,
        DESC_STRING,
        'U', 0, 'S', 0, 'B', 0, 'S', 0, 'e', 0, 'r', 0, 'i', 0, 'a', 0, 'l', 0,

        0x12,
        DESC_STRING,
        'D', 0, 'E', 0, 'A', 0, 'D', 0, 'C', 0, '0', 0, 'D', 0, 'E', 0,

// terminating zero
        0

};

这里要注意的是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

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2009-4-10 18:15:01 | 显示全部楼层
必须支持.一楼顶 【楼主位】 spxwh .

出0入0汤圆

 楼主| 发表于 2009-4-10 19:48:50 | 显示全部楼层
忘了一点重要内容,补充下

4:命令响应
req=21,20,0,0,0,0,7,0,   set_line_coding
req=a1,21,0,0,0,0,7,0,   get_line_coding
req=21,22,0,0,0,0,0,0,   set_control_line_state
上面是我们使用虚拟出来的COM端口,当改变com参数时发生的事件。单片机要对这3中请求进行正确响应才能使用com口。

set_line_coding 表示要对COM进行设置,如波特率。上位机先发送req=21,20,0,0,0,0,7,0命令,然后会把波特率等配置参数通过step_ write(控制写)将配置数据送过来;配置数据的格式如下
Table 50: Line Coding Structure
Offset Field Size Value Description
0  dwDTERate 4 Number Data terminal rate, in bits per second.
4  bCharFormat 1 Number Stop bits
0 - 1 Stop bit
1 - 1.5 Stop bits
2 - 2 Stop bits
5   bParityType 1 Number Parity
0 - None
1 - Odd
2 - Even
3 - Mark
4 - Space
6   bDataBits 1 Number Data bits (5, 6, 7, 8 or 16).

例如:step_ write=80,25,0,0,0,1,7,
0x2580=9600 , 1 Stop bit ,Odd,,8bit

get_line_coding表示将设置参数返回,如果设备通过set_line_coding 配置为step_ write=80,25,0,0,0,1,7,那么只要返回这一串配置参数就可以了ANS=80,25,0,0,0,1,7,

set_control_line_state不怎么重要,用来配置DTR,DTE信号,你可以返回一个空数据包。你也可以返回信号,具体参考Universal Serial Bus Class Definitions for Communication Devices。


step_ packet
req=a1,21,0,0,0,0,7,0,
ANS=80,25,0,0,0,1,7,
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,20,0,0,0,0,7,0,
step_ write=80,25,0,0,0,1,7,
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=
step_ packet
req=21,20,0,0,0,0,7,0,
step_ write=80,25,0,0,0,1,7,
FUN=0 ,
ANS=
ANS=
step_ packet
req=a1,21,0,0,0,0,7,0,
ANS=80,25,0,0,0,0,8,
ANS=
step_ packet
req=21,22,1,0,0,0,0,0,
ANS=
ANS=

出0入0汤圆

 楼主| 发表于 2009-4-10 19:50:14 | 显示全部楼层
点击此处下载 ourdev_435265.doc(文件大小:78K) (原文件名:HID编写.doc)

出0入20汤圆

发表于 2009-4-10 20:01:48 | 显示全部楼层
不错啊

出0入0汤圆

发表于 2009-4-10 23:52:05 | 显示全部楼层
很好,是精品啊。

出0入0汤圆

发表于 2009-4-11 00:55:10 | 显示全部楼层
不错 谢谢

出0入70汤圆

发表于 2009-4-11 01:29:16 | 显示全部楼层
mark

出0入4汤圆

发表于 2009-4-11 09:11:26 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-4-11 15:24:58 | 显示全部楼层
噢, 谢谢!

出0入0汤圆

发表于 2009-4-11 23:19:59 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-4-11 23:24:13 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-2-27 13:37:09 | 显示全部楼层
USB HID编写资料 ourdev_435236.rar——有毒?

USB HID编写资料 ourdev_435236.rar――有毒?.PNG (原文件名:USB HID编写资料 ourdev_435236.rar――有毒?.PNG)

出0入0汤圆

发表于 2010-8-12 08:41:27 | 显示全部楼层
看不懂,不过先mark. 谢谢楼主。

出0入0汤圆

发表于 2010-8-18 18:56:50 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-8-19 01:24:36 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-8-19 09:18:17 | 显示全部楼层
此贴很有料。

出0入0汤圆

发表于 2010-8-19 09:44:35 | 显示全部楼层
mark

出0入9汤圆

发表于 2010-8-19 10:26:32 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-8-19 10:38:02 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-10-27 22:12:59 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-11 16:10:58 | 显示全部楼层
不知道  spxwh 最近还研究不??
我现在的设备枚举已经成功了 驱动也装好,设备管理器也显示串口号,但无法用调试助手打开,提示已被占用。

另外,我用分析仪捕捉,看到主机不停的IN 输入端点,是不是正是由于这个原因才导致无法打开串口???
谢谢

出0入0汤圆

发表于 2010-12-11 22:33:13 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-16 11:58:46 | 显示全部楼层
记号
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-6-11 16:51

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表