为您推荐:
精华内容
最热下载
问答
  • 5星
    680KB zb12138 2021-03-15 16:34:59
  • 5星
    5.25MB weixin_43096877 2021-05-29 15:37:02
  • 5星
    21KB ZCY5202015 2021-04-22 14:21:09
  • 5星
    5.22MB GJZGRB 2021-03-10 14:25:58
  • 5星
    43KB ZCY5202015 2021-04-22 14:26:38
  • 5星
    65.2MB guoruibin123 2021-05-11 06:06:48
  • 5星
    317.93MB qq_41740659 2021-07-09 11:12:04
  • 5星
    8.29MB qq_44526422 2021-02-19 17:01:30
  • 5星
    4.33MB GZXGYZ 2021-04-17 09:07:00
  • 5星
    8.36MB wangliang0633 2020-11-19 15:12:18
  • 22.49MB u012572552 2018-08-18 13:07:09
  • 11.25MB brick409 2015-04-21 11:40:49
  • 154KB niu_88 2019-01-08 22:56:33
  • 3星
    10MB bxshtx 2018-05-27 23:57:24
  • 5星
    2.07MB fuguy 2016-10-28 14:38:54
  • 4星
    8.78MB suole48 2015-10-24 14:47:13
  • Linux内核中usb设备侧驱动程序分成3个层次:UDC驱动程序、Gadget API和Gadget驱动程序。UDC驱动程序(USB控制器)直接访问...Gadget驱动程序具体控制USB设备功能的实现,使设备表现出“U盘”、“虚拟串口”等特性。简...

    Linux内核中usb设备侧驱动程序分成3个层次:UDC驱动程序、Gadget API和Gadget驱动程序。UDC驱动程序(USB控制器)直接访问硬件,控制USB设备和主机间的底层通信,向上层提供与硬件相关操作的回调函数。Gadget API是UDC驱动程序回调函数的简单包装,这部分程序内核都已经写好。Gadget驱动程序具体控制USB设备功能的实现,使设备表现出“U盘”、“虚拟串口”等特性。

    简单看个usb 虚拟串口例子

    Overview

    --------

    The gadget serial driver is a Linux USB gadget driver, a USB device

    side driver.  It runs on a Linux system that has USB device side

    hardware; for example, a PDA, an embedded Linux system, or a PC

    with a USB development card.

    The gadget serial driver talks over USB to either a CDC ACM driver

    or a generic USB serial driver running on a host PC.

    Host

    -------------------------------------- | Host-Side   CDC ACM       USB Host   | | Operating |   or        | Controller |   USB | System    | Generic USB | Driver     |-------- | (Linux or | Serial      | and        |        | | Windows)    Driver        USB Stack  |        | --------------------------------------         | | | | Gadget                                         | --------------------------------------         | | Gadget                   USB Periph. |        | | Device-Side |  Gadget  | Controller  |        | | Linux       |  Serial  | Driver      |-------- | Operating   |  Driver  | and         | | System                   USB Stack   | --------------------------------------

    On the device-side Linux system, the gadget serial driver looks

    like a serial device.

    On the host-side system, the gadget serial device looks like a

    CDC ACM compliant class device or a simple vendor specific device

    with bulk in and bulk out endpoints, and it is treated similarly

    to other serial devices.

    The host side driver can potentially be any ACM compliant driver

    or any driver that can talk to a device with a simple bulk in/out

    interface.  Gadget serial has been tested with the Linux ACM driver,

    the Windows usbser.sys ACM driver, and the Linux USB generic serial

    driver.

    With the gadget serial driver and the host side ACM or generic

    serial driver running, you should be able to communicate between

    the host and the gadget side systems as if they were connected by a

    serial cable.

    The gadget serial driver only provides simple unreliable data

    communication.  It does not yet handle flow control or many other

    features of normal serial devices.

    内核版本:3.15                    硬件:ATMEL  SAMA5D3            编译环境:ubuntu 12.04

    1、配置内核

    这里之所以都选择为模块的形式,是为了调试方便,有些模块,比如U盘加载时还需要提供介质,就是说加载模块时还需要参数,否则加载不上

    Device Drivers  --->

    [*] USB support  --->

      USB Gadget Support  --->

      USB Gadget Drivers

    < >     USB functions configurable through configfs

    < >     Gadget Zero (DEVELOPMENT)

    < >     Ethernet Gadget (with CDC Ethernet support)

    < >     Network Control Model (NCM) support

    < >     Gadget Filesystem

    < >     Function Filesystem

    < >     Mass Storage Gadget

    < >     USB Gadget Target Fabric Module

        Serial Gadget (with CDC ACM and CDC OBEX support)

    < >     Printer Gadget

    保存退出,编译内核。在drivers/usb/gadget目录下会生成以下驱动文件

    -rw-rw-r-- 1 a_tu a_tu  9710  3月  5 15:14 ./g_serial.ko

    -rw-rw-r-- 1 a_tu a_tu 49319  3月  5 15:14 ./libcomposite.ko

    -rw-rw-r-- 1 a_tu a_tu 11473  3月  5 15:14 ./usb_f_acm.ko

    -rw-rw-r-- 1 a_tu a_tu  9485  3月  5 15:14 ./usb_f_obex.ko

    -rw-rw-r-- 1 a_tu a_tu  8011  3月  5 15:14 ./usb_f_serial.ko

    -rw-rw-r-- 1 a_tu a_tu 15970  3月  5 15:14 ./u_serial.ko

    2、操作开发板

    把编译好的内核烧入开发板,加载生成的驱动文件,注意加载顺序,否则会出现错误。

    insmod  u_serial.ko

    insmod  libcomposite.ko

    insmod   usb_f_serial.ko

    insmod  usb_f_obex.ko

    insmod  usb_f_acm.ko

    insmod  g_serial.ko

    出现内核信息如下:

    [   27.310000] --------file=composite.c-------usb_composite_probe------1830

    [   27.320000] ------------402

    [   27.320000] -----usb_gadget_probe_driver------411

    [   27.330000] -------udc_bind_to_driver-----342

    [   27.330000] g_serial gadget: Gadget Serial v2.4

    [   27.340000] g_serial gadget: g_serial ready

    [   18.960000] g_serial gadget: high-speed config #2: CDC ACM config

    说明加载成功。

    此时你打开设备管理器会发现多了一个串口设备,

    ELMO GMAS(COM10)

    0818b9ca8b590ca3270a3433284dd417.png

    Win7操作系统可以自动加载基于udc标准的serial驱动。

    对于WinXP操作系统,要使用ACM串口,需要WindowsXP机器上有gserial.inf和usbser.sys这两个文件,其中gserial.inf的配置如下:

    [Version] Signature='$Windows NT$' Class=Ports ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} Provider=%LINUX% DriverVer=08/17/2004,0.0.2.0 ; Copyright (C) 2004 Al Borchers (alborchers@steinerpoint.com) [Manufacturer] %LINUX%=GSerialDeviceList [GSerialDeviceList] %GSERIAL%=GSerialInstall, USB\VID_0525&PID_A4A7 [DestinationDirs] DefaultDestDir=10,System32\Drivers [GSerialInstall] CopyFiles=GSerialCopyFiles AddReg=GSerialAddReg [GSerialCopyFiles] usbser.sys [GSerialAddReg] HKR,,DevLoader,,*ntkern HKR,,NTMPDriver,,usbser.sys HKR,,EnumPropPages32,,'MsPorts.dll,SerialPortPropPageProvider' [GSerialInstall.Services] AddService = usbser,0x0002,GSerialService [GSerialService] DisplayName = %GSERIAL_DISPLAY_NAME% ServiceType = 1 ; SERVICE_KERNEL_DRIVER StartType = 3 ; SERVICE_DEMAND_START ErrorControl = 1 ; SERVICE_ERROR_NORMAL ServiceBinary = %10%\System32\Drivers\usbser.sys LoadOrderGroup = Base [Strings] LINUX = 'Linux' GSERIAL = 'Gadget Serial' GSERIAL_DISPLAY_NAME = 'USB Gadget Serial Driver'

    安装成功后,在设备管理器中可以看到 “Gadget Serial (COM11) '这个端口。

    开发板的/dev/下会出现/dev/ttyGS0这个设备。当然如果你怕这个设备重名,可以更改这个设备节点。操作如下:

    cat /proc/devices

    Character devices: 1 mem 2 pty 3 ttyp 4 /dev/vc/0 4 tty 4 ttyS 5 /dev/tty 5 /dev/console 5 /dev/ptmx 7 vcs 10 misc 13 input 90 mtd 128 ptm 136 pts 153 spi 251 ttyGS

    mknod /dev/usb_serial c 254 0

    以后可以直接按照串口通讯的方式打开该节点 /dev/usb_serial,进行数据读写操作。

    3、通信测试

    开发板上执行命令  cat /dev/usb_serial(当然你也可以编写程序,打开设备读写),这里只是简单的测试设备通信是否正常 ,pc机上打开串口调试助手,打开com10,通过字符串输入框发送数据。此时发现开发板没有收到数据,而串口助手却收到自己发送的数据。这让我很是纳闷,折腾了2天,终于睡醒了。

    又测试了另一通路:开发板给pc发。echo 12345 > /dev/usb_serial

    这是完全正常的,通过串口助手收到的数据来看。每次收到的数据都有换行现象,会不会是数据没有从缓冲区中刷出来?我就换了数据格式,发送简单文件

    111111111111111111

    222222222222222222

    222222222222222222

    444444444444444444

    此时开发板收到数据

    # cat /dev/usb_serial

    111111111111111111

    222222222222222222

    222222222222222222

    444444444444444444

    原来真的是 "\n" 在作怪!!!,如果你的文件只有一行,且没有换行。那么你的开发板是收不到数据的,这些数据并没有丢失,而是存储在串口的缓冲区中,直到遇到 "\n",才会把数据一股脑发出来。

    至此测试完毕。

    本人水平有限,文章仅代表个人观点,如有错误,请指正!!!

    展开全文
    weixin_42363501 2021-05-13 10:27:13
  • 7.34MB weixin_38506182 2021-04-21 22:20:46
  • 2.93MB weixin_38997187 2018-04-13 12:15:54
  • USB虚拟串口提供了绕过这个问题的一个简单的解决方案。         为了让USB被视为一个COM端口,USB设备必须根据通信设备类(CDC)规范来实现两个接口: 1.抽象控制模型通信,在端点中有1个中断...

            在现代个人电脑的USB是几乎所有外设的标准通信端口。然而许多工业应用软件仍然使用经典的串口(UART)。USB虚拟串口提供了绕过这个问题的一个简单的解决方案。

            为了让USB被视为一个COM端口,USB设备必须根据通信设备类(CDC)规范来实现两个接口:

    1.抽象控制模型通信,在端点中有1个中断:在我们的实现中,这个接口在描述符中声明,但是相关的端点(端点2)不被使用。

    2.抽象控制模型数据,具有1个bulk in端点和一个bulk out 端点,这个接口在实际中由端点1(in)和端点3(out)表示。端点1用于通过USB将从UART接收到的数据发送到PC。端点3用于接收来自PC的数据并通过UART发送。

    为了实现虚拟COM端口,该设备支持以下类特定请求:

    ● SET_CONTROL_LINE_STATE:

    RS-232信号用于告诉设备数据终端设备现在是存在的.该请求总是在Virtual_Com_Port_NoData_Setup() 函数中返回一个USB_SUCCESS(usb_prop.c中 )。

    ● SET_COMM_FEATURE:

    控制特定通信功能的设置。这个请求总是在Virtual_Com_Port_NoData_Setup() 函数中返回一个USB_SUCCESS(usb_prop.c中 )。

    ● SET_LINE_CODING:

    发送设备的配置。它包括波特率、停止位、奇偶校验和字符位数。所接收的数据存储在一个特定的数据结构中,称为“linecoding”,用于更新UART参数。

    ● GET_LINE_CODING:

    此命令要求获取设备当前波特率、停止位、奇偶校验和字符位数。该设备用存储在“linecoding”结构中的数据做出响应。

     

    硬件配置接口

    在虚拟COM端口中的硬件配置接口(hw _ config.c)管理以下程序:

    ●配置的系统和外设(USB和USART)时钟和中断

    ●USART默认值初始化

    ●用通过SET_LINE_CODING命令收到的参数配置串口

    ●把收到的数据发送到PC,通过USB串口通讯

    ●发送收到的数据通过USB串口通讯

     

    1、USB标准规范类型

        USB规范大致可分为以下三类:

    1)、标准规范

        标准规范为最基础的规范,主要有USB1.0、USB1.1、USB2.0和USB3.0等等。

    2)、USB设备类规范

        设备类规范主要是针对于具体的USB设备而推出的类规范,有Mass Storage、Audio Device、Video Device等等设备相关规范。

    3)、USB HOST控制器规范

        主要有OHC和UHC等

    1、标准规范

         USB是通用串行总线的英文缩写,是Intel公司开发的总线架构,使得在计算机上添加串行设备非常容易。只须将设备插入计算机的USB端口中,系统会自动识别和配置。根据时代发展,USB接口标准经历了一代USB、第二代USB 2.0和第三代USB 3.0。

        USB规格第一次是于1995年,由Intel、IBM、Compaq、Microsoft、NEC、Digital、North Telecom等七家公司组成的USBIF(USB Implement Forum)共同提出,USBIF于1996年1月正式提出USB1.0规格,频宽为1.5Mbps.不过因为当时支持USB的周边装置少的可怜,所以主机板商不太把USB Port直接设计在主机板上。

        USB2.0技术规范是有由Compaq、Hewlett Packard、Intel、Lucent、Microsoft、NEC、Philips共同制定、发布的,规范把外设数据传输速度提高到了480Mbps,是USB 1.1设备的40倍!2000年制定的USB 2.0标准是真正的USB 2.0,被称为USB 2.0的高速(High-speed)版本,理论传输速度为480 Mbps.

        USB 3.0是最新的USB规范,该规范由英特尔等公司发起,USB3.0的最大传输带宽高达5.0Gbps(640MB/s),USB3.0 引入全双工数据传输。5根线路中2根用来发送数据,另2根用来接收数据,还有1根是地线。也就是说,USB 3.0可以同步全速地进行读写操作。

    USB版本

    最大传输速率

    速率称号

    最大输出电流

    推出时间

    USB1.0

    1.5Mbps(192KB/s)

    低速(Low-Speed)

    5V/500mA

    1996年1月

    USB1.1

    12Mbps(1.5MB/s)

    全速(Full-Speed)

    5V/500mA

    1998年9月

    USB2.0

    480Mbps(60MB/s)

    高速(High-Speed)

    5V/500mA

    2000年4月

    USB3.0

    5Gbps(500MB/s)

    超高速(Super-Speed)

    5V/900mA

    2008年11月

    USB 3.1

    10Gbps(1280MB/s)

    超高速+(Super-speed+)

    20V/5A

    2013年12月

    这是从时间维度上来看的,但是每一代USB接口针对不同的设备又细分出来具体的型号,如USB Type A/B/C/Mini/Micro。下面是USB2.0和USB3.0标准下的各类接口示意图:

    一、USB系统的结构

        USB系统是由三个逻辑层组成:功能层、USB设备层和USB总线接口层。并且每一层都是由主机和USB设备不同的功能模块组成,如下图所示:

    1、功能层(接口)

        功能层是由客户软件和设备方的功能单元组成,其能够实现USB设备传输的特定功能。通过功能层可直观地理解USB传输的数据内容。其中,客户软件通过USB系统软件来与USB设备进行通信。功能单元对于客户软件,可视为接口的集合。

     

    2、USB设备层 (端点)

        USB设备层是由USB系统软件和USB设备的USB逻辑设备组成,其实现主机和USB设备之间传输的具体配置。USB逻辑设备对于USB系统软件,可视为端点的集合。

     

    3、USB总线接口层

        USB总线接口层是由主机的USB主控制器和设备的USB总线接口组成。其实现主机和USB设备实际的数据传输。

     

    4、主机部分

        USB主机部分由客户软件、USB系统软件和USB总线接口组成。

    4.1 客户软件

        客户软件负责和USB设备的功能单元进行通信,以实现特定的功能。客户软件不能直接与USB设备相连接,必须通过USB系统软件和USB总线接口才能实现连接。客户软件包括USB设备驱动程序和界面应用程序两部分。

     

    4.2 USB系统软件

        USB系统软件负责和USB逻辑设备进行配置通信,并管理客户软件启动的数据。一般包括USB总线驱动程序、USB主控制驱动程序和非USB主机软件三个部分,这部分会由系统提供。

     

    4.3 USB总线接

        USB总线接口包括主控制器和跟集线器两部分。其中,主控制器是负责完成主机和USB设备间的数据实际传输。根集线器是为USB系统连接起点。

     

    5、设备部分

        USB设备部分由三个功能模块组成,分别是USB总线接口、USB逻辑设备和功能单元。

        功能单元看作是一个接口的集合;USB 逻辑设备被USB系统软件看作一个端点的集合;USB总线接口是USB设备中的串行接口引擎(SIE)。

     

        当客户程序通过USB管道发送或接收数据时,它首先调用Win32 APl,调用最终将使功能驱动程序收到一个IRP。而驱动程序的工作就是把客户的请求引导到有正确端点的管道上。它把请求提交到总线驱动程序,总线驱动程序再把请求分解成多个事务,然后这些事务被送往总线。总线上的信息流以每毫秒一帧数据的形式流动。总线驱动程序必须安排好多个事务以使它们能被装入同一帧中。

     

    二、USB的拓扑结构

        USB是一种主从结构的系统。主机叫Host,从机叫做Device(也叫设备)。通常所说的主机具有一个或者多个USB主控制器(host  controller)和根集线器(root hub)。主控制器主要负责数据处理,而跟集线器则提供一个连接主控制器与设备之间的接口和通路。

        通常情况下,PC机上有多个主控器和多个USB口,一个主控器下有一根集线器,一根集线器通常具有一个或者几个USB接口。通常集线器可以通过USB集线器来扩展USB接口,只是带宽是不能够拓宽的,因为带宽是共享一个USB主控器的。

        了解上面的信息后,再来看USB的拓扑结构如下图:

    USB的拓扑结构看起来是一个金字塔形的结构,具体构成如下:

        塔顶是USB的主控器和根集线器,下面接USB集线器,USB集线器将一个USB口扩展为多个USB口,多个USB口同样可以通过USB集线器扩展出更多的接口。不过USB口并不能通过USB集线器无止境的扩展,他是有限制的,例如在USB2.0规定它最多扩展6次。

        理论上一个USB主控器最多可接127个设备,这是因为协议规定每个USB设备具有一个7bit地址(取值范围为0~127,地址用于给主机识别是哪个设备,其中0地址值得注意,是给刚接入未初始化的设备使用的)。

     

    三、USB的设备架构

        设备架构认为设备是由一些配置、接口和端点构成的。其中配置和接口是USB功能的抽象,实际的数据传输由端点来完成。其对应关系如下图所示:

    1.设备

        设备代表USB设备,它由一个或多个配置组成。设备描述符用于说明设备的总体信息,并指出其所包含配置的个数。

     

    2.配置 

        在使用USB设备前,必须为其选择一个合适的配置。如USB设备的低功耗模式和高功耗模式分别对应一个配置。配置描述符用于说明USB设备中各个配置的特性。

     

    3.接口 

        一个配置可以包含一个或多个接口。接口是一个端点的集合。接口描述符用于说明USB设备中各个接口的特性。 

     

    4.端点 

        端点是USB设备中的实际物理单元,USB数据传输就是在主机和USB设备各个端点之间进行的。

        

    5、管道

        管道,是主机软件(数据缓冲区)和USB设备的各个端点之间的数据传输链接,它是两者之间通信流的抽象。然而,实际的数据传输是由USB总线接口层来完成的。管道和USB设备中的端点一一对应,并且各个管道的数据传输是相互独立的。

        管道有两种类型:流管道和消息管道。其中最为重要的消息管道是“缺省控制管道”,这个管道在设备开始上电后就存在了,它用于提供设备的配置与状态等信息。主机与设备之间的联络就是通过消息管道实现的。

     

    四、USB枚举与通信的具体过程

    1、USB接头

        下图是一个USB接头的结构图:

        由图可以看出,标准的USB链接线使用4芯电缆:5V电源线(Vbus)\差分数据线负(D-)、差分数据线正(D+)和地线(GND)。

        在hub端,数据线D+和D-都有一个阻值在14.25k到24.8k的下拉电阻Rpd,而在设备端,D+(全速,高速)和D-(低速)上有一个1.5k的上拉电阻Rpu。当设备插入到hub端口时,有上拉电阻的一根数据线被拉高到幅值的90%的电压(大致是3V)。hub检测到它的一根数据线是高电平,就认为是有设备插入,并能根据是D+还是D-被拉高来判断到底是什么设备(全速/低速)插入端口。

     

    2、USB通信过程

        主机和USB设备可以相互传输数据,其具体过程如下(以主机箱设备传输为例):

    step1:客户软件首先将要传输的数据放入缓冲区,同时向USB总线驱动程序发出IRPS,请求数据传输。(客户软件)step2:USB总线驱动接收到程序接收请求,并对数据进行处理,转化为具有USB格式的事务处理。(USB系统软件)

    step3:USB主控制器驱动程序将这些事务处理建立成事务列表,同时要求不能超过USB带宽。(USB系统软件)

    step4:USB主控制器读取到事务列表并将事务转化为信息包,发送到USB总线上。(USB总线接口)

    step5:USB设备收到这些信息后,SIE(USB总线接口是USB设备中的串行接口引擎)将其解包后放入指定端点的接收缓冲区内,由芯片固件对其进行处理。

     

    用框图表示如下:

    3、USB枚举通信具体过程

         枚举就是从设备读取一些信息,知道设备是什么样的设备,如何进行通信,这样主机就可以根据这些信息来加载合适的驱动程序。调试USB设备,很重要的一点就是USB的枚举过程,只要枚举成功了,那么就已经成功大半了。

     

    枚举通信过程具体如下:

    step1:检测电压变化,报告主机

        首先,USB设备上电后,一直监测USB设备接口电平变化HUB检测到有电压变化,将利用自己的中断端点将信息反馈给主控制器有设备连接。

     

    Step2:主机了解连接设备

        主机在知道有设备接入后会发送一个Get_Port_Status请求(request)给hub以了解此次状态改变的确切含义。

     

    Step3:Hub检测所插入的设备是高速还是低速

        hub通过检测USB总线空闲(Idle)时差分线的高低电压来判断所连接设备的速度类型,当host发来Get_Port_Status请求时,hub就可以将此设备的速度类型信息回复给host。USB 2.0规范要求速度检测要先于复位(Reset)操作。

     

    Step4:hub复位设备

        主机一旦得知新设备已连上以后,它至少等待100ms以使得插入操作的完成以及设备电源稳定工作。然后主机控制器就向hub发出一个 Set_Port_Feature请求让hub复位其管理的端口(刚才设备插上的端口)。hub通过驱动数据线到复位状态(D+和D-全为低电平 ),并持续至少10ms。当然,hub不会把这样的复位信号发送给其他已有设备连接的端口,所以其他连在该hub上的设备自然看不到复位信号,不受影响。

     

    Step5: Host检测所连接的全速设备是否是支持高速模式

        因为根据USB 2.0协议,高速(High Speed)设备在初始时是默认全速(Full Speed )状态运行,所以对于一个支持USB 2.0的高速hub,当它发现它的端口连接的是一个全速设备时,会进行高速检测,看看目前这个设备是否还支持高速传输,如果是,那就切到高速信号模式,否则就一直在全速状态下工作。

        同样的,从设备的角度来看,如果是一个高速设备,在刚连接bub或上电时只能用全速信号模式运行(根据USB 2.0协议,高速设备必须向下兼容USB 1.1的全速模式)。随后hub会进行高速检测,之后这个设备才会切换到高速模式下工作。假如所连接的hub不支持USB 2.0,即不是高速hub,不能进行高速检测,设备将一直以全速工作。

     

    Step6:Hub建立设备和主机之间的信息通道

        主机不停地向hub发送Get_Port_Status请求,以查询设备是否复位成功。Hub返回的报告信息中有专门的一位用来标志设备的复位状态。

           当hub撤销了复位信号,设备就处于默认/空闲状态(Default state),准备接收主机发来的请求。设备和主机之间的通信通过控制传输,默认地址0,端点号0进行。此时,设备能从总线上得到的最大电流是100mA。(所有的USB设备在总线复位后其地址都为0,这样主机就可以跟那些刚刚插入的设备通过地址0通信。)

     

    Step7:主机发送Get_Descriptor请求获取默认管道的最大包长度

         默认管道(Default Pipe)在设备一端来看就是端点0。主机此时发送的请求是默认地址0,端点0,虽然所有未分配地址的设备都是通过地址0来获取主机发来的请求,但由于枚举过程不是多个设备并行处理,而是一次枚举一个设备的方式进行,所以不会发生多个设备同时响应主机发来的请求。

          设备描述符的第8字节代表设备端点0的最大包大小。虽然说设备所返回的设备描述符(Device Descriptor)长度只有18字节,但系统也不在乎,此时,描述符的长度信息对它来说是最重要的,其他的瞄一眼就过了。当完成第一次的控制传输后,也就是完成控制传输的状态阶段,系统会要求hub对设备进行再一次的复位操作(USB规范里面可没这要求)。再次复位的目的是使设备进入一个确定的状态。

     

    Step8:主机给设备分配一个地址

         主机控制器通过Set_Address请求向设备分配一个唯一的地址。在完成这次传输之后,设备进入地址状态(Address state),之后就启用新地址继续与主机通信。这个地址对于设备来说是终生制的,设备在,地址在;设备消失(被拔出,复位,系统重启),地址被收回。同一个设备当再次被枚举后得到的地址不一定是上次那个了。

     

    Step9:主机获取设备的信息

        主机发送 Get_Descriptor请求到新地址读取设备描述符,这次主机发送Get_Descriptor请求可算是诚心,它会认真解析设备描述符的内容。设备描述符内信息包括端点0的最大包长度,设备所支持的配置(Configuration)个数,设备类型,VID(Vendor ID,由USB-IF分配), PID(Product ID,由厂商自己定制)等信息。

        之后主机发送Get_Descriptor请求,读取配置描述符(Configuration Descriptor),字符串等,逐一了解设备更详细的信息。事实上,对于配置描述符的标准请求中,有时wLength一项会大于实际配置描述符的长度(9字节),比如255。这样的效果便是:主机发送了一个Get_Descriptor_Configuration 的请求,设备会把接口描述符,端点描述符等后续描述符一并回给主机,主机则根据描述符头部的标志判断送上来的具体是何种描述符。

          接下来,主机就会获取配置描述符。配置描述符总共为9字节。主机在获取到配置描述符后,根据里面的配置集合总长度,再获取配置集合。配置集合包括配置描述符,接口描述符,端点描符等等。

         如果有字符串描述符的话,还要获取字符串描述符。另外HID设备还有HID描述符等。

     

    Step10: 主机给设备挂载驱动(复合设备除外)

        主机通过解析描述符后对设备有了足够的了解,会选择一个最合适的驱动给设备。  然后tell the world(announce_device)说明设备已经找到了,最后调用设备模型提供的接口device_add将设备添加到 usb 总线的设备列表里,然后 usb总线会遍历驱动列表里的每个驱动,调用自己的 match(usb_device_match) 函数看它们和你的设备或接口是否匹配,匹配的话调用device_bind_driver函数,现在就将控制权交到设备驱动了。   

         对于复合设备,通常应该是不同的接口(Interface)配置给不同的驱动,因此,需要等到当设备被配置并把接口使能后才可以把驱动挂载上去。

     

    Step11:设备驱动选择一个配置

        驱动(注意,这里是驱动,之后的事情都是有驱动来接管负责与设备的通信)根据前面设备回复的信息,发送Set_Configuration请求来正式确定选择设备的哪个配置(Configuration)作为工作配置(对于大多数设备来说,一般只有一个配置被定义)。至此,设备处于配置状态(Configured),当然,设备也应该使能它的各个接口(Interface)。

        对于复合设备,主机会在这个时候根据设备接口信息,给它们挂载驱动。

    一、端点概念。

        端点(Endpoint),是主机与设备之间通讯数据的接收或来源。主机与设备之间通信时最终会总用于设备上的各个端点,它是主机与设备间通信流的一个逻辑终端。一系列相互独立的端点在一起构成了USB逻辑设备,在系统结构中,位于下方红色方框内:

    二、端点的分类

        每个USB设备都有一个唯一的设备地址,设备地址是设备连接上主机时由主机分配的,主机主要依靠这个设备地址对USB设备进行访问。但是在设备内部地址会被分的更细,设备会分出一些端点来,每个端点在设备都会有唯一的端点号,这个端点号是设计设备时给定的。如端点0,端点1等。一个设备最多可以包含16个端点,每个端点的地址为0-15。(网上也有说几十个的,有待考究)    

        其中每个端点地址对应一个方向。例如端点3-IN,端点3-OUT,这两个含义完全不同。但是需要注意其中的一个特殊端点--端点0,每个USB设备必须要有一个端点0,其作用为对设备枚举和对设备进行一些基本的控制功能,端点0也被称为控制端点。并且它与其他的端点还有一个不同之处在于端点0的数据传输方向是双向的,即端点0既可以给主机发送数据,也可以接收主机发送过来的数据,而其它端点均为单向。

        虽然有16个端点,但通常我们只用到3个,如下:

         1)、EP0:做传输配置和控制信息;

         2)、EP1:做数据输入IN_EP;

         3)、EP2:做数据输出OUT_EP。

     

    注意:除了端点0,其余的端点在设备配置之前不能与主机通信,只有向主机报告这些端点的特性并被确认后才能被激活。

     

    三、端点的特性

        一个端点的特性决定了它与客户软件进行传送的类型。一个端点具有以下一些特性:

       ·端点的总线访问频率要求

       ·端点的总线延迟要求

       ·端点的带宽要求

       ·端点的端点号

       ·对错误处理的要求

       ·端点能接收或发送的包的最大长度

       ·端点的传送类型

       ·端点与主机的数据传送方向

     

    四、端点描述符

        USB设备中端点描述符描述了端点信息,端点描述符格式如下:

    typedef struct _USB_ENDPOINT_DESCRIPTOR_

    {

        BYTE        bLength,

        BYTE        bDescriptorType,

        BYTE        bEndpointAddress,

        BYTE        bmAttributes,

        WORD      wMaxPacketSize,

        BYTE        bInterval

    }USB_ENDPOINT_DESCRIPTOR;

    各变量具体释义如下:

    bLength : 描述符大小.固定为0x07.

    bDescriptorType : 接口描述符类型.固定为0x05.

    bEndpointType : USB设备的端点地址.Bit7,方向,对于控制端点可以忽略,1/0:IN/OUT.Bit6-4,保留.BIt3-0:端点号.

    bmAttributes : 端点属性.Bit7-2,保留.BIt1-0:00控制,01同步,02批量,03中断.

    wMaxPacketSize : 本端点接收或发送的最大信息包大小.

    bInterval : 轮训数据传送端点的时间间隔.对于批量传送和控制传送的端点忽略.对于同步传送的端点,必须为1,对于中断传送的端点,范围为1-255。

     

    五、端点与管道

    1、管道的概念

        管道是主机软件(数据缓存区),和USB设备各各端点之间的数据传输连接,他是两者之间通信流的抽象(实际上数据传输是USB总线接口完成)。管道与USB设备中的端点逐个对应,并且各个管道的数据传输是相互独立的。

     

    2、管道的格式分类

        管带的通信格式分为两种,一种为流,另一种为消息,这两种通信格式不同且互斥。

    1)、“流”指不具有USB定义格式的数据流,流通道中的数据是流的形式,也就是该数据内容不具有USB要求的结构。数据从流通道一端流进的顺序与它们从流通道另一端流出时的顺序是一样的(先进先出),并且流通道中的通信流总是单向的。

    2)、“消息”指具有某种USB定义格式的数据流。消息通道与端点的关系同流通道与端点的关系是不同的。首先,主机向USB设备发出一个请求;接着,就是数据的传送;最后,是一个状态阶段(这部分即一次命令请求的过程)。为了能够容纳请求/数据/状态的变化,消息通道要求数据有一个格式,此格式保证了命令能够被可靠地传送和确认。消息通道允许双方向的信息流。

     

    六、端点的传输类型

        一个具体的端点只能属于四个传输模式下中的一种。数据传输类型分为四种分别是:控制传输、批量传输、同步传输和中断传输。一般情况下,通常把工作在什么模式下的端点就叫什么端点,例如:控制端点、批量端点、同步端点和中断端点。

        端点0,是设备的默认控制端点,在设备上电后就存在并可以使用,在Set Config之前所有的传输都是通过端点0传输的。

    USB控制传输分为以下四种:

    • 批量传输:批量传输一般用于批量的和非实时的数据传输,通俗的来说就是用于数据量大但对时间要求又不高的场合的一种传输方式,类似用于USB打印机和USB扫描仪等等。
    • 中断传输:中断传输一般用于小批量的和非连续的数据传输,通俗的来说就是用于数据量小的数据不连续的但实时性高的场合的一种传输方式,类似用于USB鼠标和USB键盘等等。
    • 等时传输:等时传输也有“同步传输”的叫法,一般用于要求数据连续、实时且数据量大的场合,其对传输延时十分敏感,类似用于USB摄像设备,USB语音设备等等。
    • 控制传输:控制传输是一种特殊的传输方式,且传输过程相对以上三种而言更复杂一些,但也十分重要。当USB设备初次连接主机时,用控制传输传送控制命令等对设备进行配置。同时设备接入主机时,需要通过控制传输去获取USB设备的描述符以及对设备进行识别,在设备的枚举过程中都是使用控制传输进行数据交换。

     

    一、控制传输的结构

        一次完整控制传输可以分为三个阶段:初始设置阶段--->数据阶段(不必须)--->状态信息阶段。下面的

     

    1、初始设置阶段

        初始设置阶段用于固定建立SETUP事务,标志一次控制传输的开始。初始设置阶段为一个SETUP事务,同样分为三个阶段如下:

    令牌包阶段:

        主机会发送一个SETUP令牌包,如下:

    相当于告诉设备,我要跟你进行通讯请你做好准备。

     

    数据包阶段:

        发送DATA0数据包(注意SETUP只能使用DATA0包,8字节),让设备接收。例如发送获取设备描述符命令包:

    相当于告诉设备,请将设备描述符的内容发给我。

     

    握手包阶段:

        设备自动应答。

     

    结合上面的过程可以用下图表示初始设置阶段。

     

    2、数据阶段

        初始设置阶段中命令如果要求读/写数据,数据阶段就会在这一阶段来具体交换数据(如果没有数据交换要求则可省去该步骤,具体有SETUP事务标准请求命令决定)。在此需要做一些说明:传输控制在前言有说到控制传输的用途是获取设备信息与对设备进行配置。所以这些数据操作分为以下三类:

    1)、控制读传输;

    2)、控制写传输;

    3)、无数据控制传输。

     

        一次控制传输必定为上面三种中的其中一种,所以数据阶段中的数据事务也是根据该规则来决定数据事务的。

        此处还应该注意的是数据阶段是由一到多个IN/OUT事务组成。这是由于有时候存在一个事务传不完的数据,所以可能存在多个连续IN/OUT事务的情况。这也就决定了,在同一次数据传输阶段中事务类型必定相同(IN/OUT事务)。

     

    2.1、传输格式

        综上所述,所以从传输控制的不同类型来讲述数据阶段的格式会更好理解。

    1)、控制读传输

        控制读传输时数据阶段在整个传输的格式如下图蓝框部分:

     

    数据方向为:设备 —> 主机 (读取USB描述符)

        这里每个数据包是DATA0和DATA1交替出现的。需要注意的是当最后一个包刚好为允许的最大数据包大小时需要再传一个0长度的数据包,表示传输的结束。

     

    控制读传输的数据过程IN事务的三个阶段如下:

    令牌包阶段:

        主机会发送一个IN令牌包,触发设备产生IN包中断,如下:

    数据包阶段:

        设备回复主机请求,回应数据。例如回复设备描述符命令请求:

    握手包阶段:

        主机自动应答。

    2)、控制写传输

        控制写传输时数据阶段在整个传输的格式如下下图蓝框部分:

    数据方向为:主机 —> 设备(配置USB设备)

     

    传输过程和规则基本与读取相似,不多做赘述。

     

     

    3)、无数据控制

        控制传输不一定要传输很多数据,有些控制可能只是告诉设备要做一件事,这个命令包含在建立阶段的建立事务的8字节数据中即可,设备只需回复主机收到命令与否即可,所以就跳过数据阶段直接进入到状态阶段。无数据控制的格式如下图:

    所以注意在无数据控制传输时,是无数据阶段的!

     

     

    3、状态信息阶段

        状态信息阶段是要返回数据传输的成功与否,具体也需要看控制传输的类型。需要注意的是,状态信息的数据传输方向与数据阶段方向相反。例如,数据阶段为IN事务则状态信息阶段为OUT事务。

     

    3.1、控制读传输

        在控制读传输时,该阶段则为OUT事务,其中的数据包固定为DATA1数据包。返回数据成功与否以有以下情况:

        1)、读数据成功                      主机发送OUT令牌包(ping令牌包,高速情况下),主机发送0长度数据包,设备ACK。

        2)、数据传输出错                   主机发送OUT令牌包(ping令牌包,高速情况下),主机发送0长度数据包,设备STALL。

        3)、设备忙(比如正在写数据)   主机发送OUT令牌包(ping令牌包,高速情况下),主机发送0长度数据包,设备NAK。 

     

    控制读传输的状态信息阶段OUT事务的三个阶段如下(以ACK为例):

    令牌包阶段:

        主机会发送一个OUT令牌包,如下:

    数据包阶段:

        主机发送0字节数据包,作为状态正常信息回应:

    握手包阶段:

        设备自动应答。

    3.2、控制写传输

        在控制读传输时,该阶段则为IN事务,其中的数据包固定为DATA1数据包。返回数据成功与否以有以下情况:

        1)、写数据成功                      主机发送IN令牌包,主机发送0长度数据包,设备回复ACK。

        2)、数据传输出错                   主机发送IN令牌包,设备回复STALL。

        3)、设备忙(比如正在写数据)   主机发送IN令牌包,设备回复NAK。 

     

    控制读传输的状态信息阶段IN事务过程与读类似。

     

    3.3、无数据控制传输

        该阶段则为IN事务,其规则与控制写传输相似。

     

    至此,一次控制传输完成,整个过程结束。

     

    STM32F103 的 MCU 自带 USB 从控制器,符合 USB 规范的通信连接;PC 主机和微控制器
    之间的数据传输是通过共享一专用的数据缓冲区来完成的,该数据缓冲区能被 USB 外设直接访
    问。这块专用数据缓冲区的大小由所使用的端点数目和每个端点最大的数据分组大小所决定,
    每个端点最大可使用 512 字节缓冲区(专用的 512 字节,和 CAN 共用),最多可用于 16 个单
    向或 8 个双向端点。USB 模块同 PC 主机通信,根据 USB 规范实现令牌分组的检测,数据发送
    /接收的处理,和握手分组的处理。整个传输的格式由硬件完成,其中包括 CRC 的生成和校验。
    每个端点都有一个缓冲区描述块,描述该端点使用的缓冲区地址、大小和需要传输的字节
    数。当 USB 模块识别出一个有效的功能/端点的令牌分组时,(如果需要传输数据并且端点已配
    置)随之发生相关的数据传输。USB 模块通过一个内部的 16 位寄存器实现端口与专用缓冲区的
    数据交换。在所有的数据传输完成后,如果需要,则根据传输的方向,发送或接收适当的握手
    分组。在数据传输结束时,USB 模块将触发与端点相关的中断,通过读状态寄存器和/或者利用
    不同的中断来处理。
    USB 的中断映射单元:将可能产生中断的 USB 事件映射到三个不同的 NVIC 请求线上:
    1、USB 低优先级中断(通道 20):可由所有 USB 事件触发(正确传输,USB 复位等)。固件
    在处理中断前应当首先确定中断源。
    2、USB 高优先级中断(通道 19):仅能由同步和双缓冲批量传输的正确传输事件触发,目
    的是保证最大的传输速率。
    3、USB 唤醒中断(通道 42):由 USB 挂起模式的唤醒事件触发

    ST 提供的 USB 驱动库,可以在: http://www.stmcu.org/document/detail/index/id-213156 这里
    下载到(STSW-STM32121)

     

    ST 不但提供源码,还提供了说明文件:CD00158241.pdf(UM0424),专门讲解 USB 库怎
    么使用。有了这些资料对我们了解 STM32F103 的 USB 会有不少帮助,尤其在不懂的时候,看
    看 ST 的例程,会有意想不到的收获。本实验的 USB 部分就是移植 ST 的 Virtual_COM_Port 例
    程相关部分而来,完成一个 USB 虚拟串口的功能。
    硬件设计

    53.3 软件设计
    代码移植自 ST 官方例程:

    有了这个官方例程做指引,我们就知道具体需要哪些文件,从而实现本例程。
    首先,在工程文件夹下面,新建 USB 文件夹,
    并拷贝官方 USB 驱动库相关代码到该文件夹下,即拷贝STM32_USB-FS-Device_Lib_V4.0.0Libraries 文件夹下的 STM32_USB-FS-Device_Driver 文件夹到该文件夹下面。然后,在 USB 文件夹下,新建 CONFIG 文件夹存放 Virtual COM 实现相关代码,即:STM32_USB-FS-Device_Lib_V4.0.0ProjectsVirtual_COM_Portsrc 文件夹下的部分代码:
    hw_config.c、usb_desc.c、usb_endp.c、usb_istr.c、usb_prop.c 和 usb_pwr.c 等 6 个.c 文件,同时
    拷贝:STM32_USB-FS-Device_Lib_V4.0.0ProjectsVirtual_COM_Portinc 文件夹下面的:
    hw_config.h、platform_config.h、usb_conf.h、usb_desc.h、usb_istr.h、usb_prop.h 和 usb_pwr.h 等
    7 个头文件到 CONFIG 文件夹下,最后 CONFIG 文件夹下的文件如图

    之后,根据 ST 官方 Virtual_COM_Port 例程,在我们本章例程的基础上新建分组添加相关
    代码,具体细节,这里就不详细介绍了,添加好之后,如图  所示: 

    移植时,我们重点要修改的就是 CONFIG 文件夹下面的代码,USB_CORE 文件夹下的代
    码一般不用修改。现在,我们先来简单介绍一下 USB_CORE 文件夹下的几个.c 文件。

    usb_regs.c 文件,该文件主要负责 USB 控制寄存器的底层操作,里面有各种 USB 寄存器
    的底层操作函数。
    usb_init.c 文件,该文件里面只有一个函数:USB_Init,用于 USB 控制器的初始化,不过对
    USB 控制器的初始化,是 USB_Init 调用用其他文件的函数实现的,USB_Init 只不过是把他们
    连接一下罢了,这样使得代码比较规范。
    usb_int.c 文件,该文件里面只有两个函数 CTR_LP 和 CTR_HP,CTR_LP 负责 USB 低优先
    级中断的处理。而 CTR_HP 负责 USB 高优先级中断的处理。
    usb_mem.c 文件,该文件用于处理 PMA 数据,PMA 全称为 Packet memory area,是 STM32
    内部用于 USB/CAN 的专用数据缓冲区,该文件内也只有 2 个函数即: PMAToUserBufferCopy
    和 UserToPMABufferCopy,分别用于将 USB 端点的数据传送给主机和主机的数据传送到 USB
    端点。
    usb_croe.c 文件,该文件用于处理 USB2.0 协议。
    usb_sil.c 文件,该文件为 USB 端点提供简化的读写访问函数。
    以上几个文件具有很强的独立性,除特殊情况,不需要用户修改,直接调用内部的函数即
    可。接着我们介绍 CONFIG 文件夹里面的几个.c 文件。
    hw_config.c 文件,该文件用于硬件的配置,比如初始化 USB 时钟、USB 中断、低功耗模
    式处理等。
    usb_desc.c 文件,该文件用于 Virtual Com 描述符的处理。
    usb_endp.c 文件,该文件用于非控制传输,处理正确传输中断回调函数。
    usb_pwr.c 文件,该文件用于 USB 控制器的电源管理;
    usb_istr.c 文件,该文件用于处理 USB 中断。
    usb_prop.c 文件,该文件用于处理所有 Virtual Com 的相关事件,包括 Virtual Com 的初始
    化、复位等等操作。
    另外官方例程用到 stm32_it.c 来处理 USB 相关中断,包括两个中断服务函数,第一个是:
    USB_LP_CAN1_RX0_IRQHandler 函数,我们在该函数里面调用 USB_Istr 函数,用于处理 USB
    发生的各种中断。另外一个就是 USBWakeUp_IRQHandler 函数,我们在该函数就做了一件事:
    清除中断标志。为了方便,我们直接将 USB 中断相关代码,全部放到 hw_config.c 里面,所以,
    本例程直接用不到 stm32_it.c。
    USB 相关代码,就给大家介绍到这里,详细的介绍,请大家参考:CD00158241.pdf 这个文
    档。
    注意,以上代码,有些是经过修改了的,并非完全照搬官方例程。接着我们在工程文件里
    面新建 USB_CORE 和 USB_CONFIG 分组,分别加入 USB\ STM32_USB-FS-Device_Driver\src
    下面的代码和 USB\CONFIG 下面的代码,然后把 USB\STM32_USB-FS-Device_Driver\inc 和
    USB\CONFIG 文件夹加入头文件包含路径。
    最后修改 main.c 里面代码如下:
    int main(void)
    {
    u16 t; u16 len;
    u16 times=0; u8 usbstatus=0;
    delay_init(); //延时函数初始化
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置 NVIC 中断分组 2
    uart_init(115200); //串口初始化为 115200
    LED_Init(); //初始化与 LED 连接的硬件接口

    LCD_Init(); //初始化 LCD
    POINT_COLOR=RED; //设置字体为红色
    LCD_ShowString(30,50,200,16,16,"WarShip STM32");
    LCD_ShowString(30,70,200,16,16,"USB Virtual USART TEST");
    LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
    LCD_ShowString(30,110,200,16,16,"2015/1/28");
    LCD_ShowString(30,130,200,16,16,"USB Connecting...");//提示 USB 开始连接
    delay_ms(1800);
    USB_Port_Set(0); //USB 先断开
    delay_ms(700);
    USB_Port_Set(1); //USB 再次连接
    Set_USBClock();
    USB_Interrupts_Config();
    USB_Init();
    while(1)
    {
    if(usbstatus!=bDeviceState)//USB 连接状态发生了改变.
    {
    usbstatus=bDeviceState;//记录新的状态
    if(usbstatus==CONFIGURED)
    {
    POINT_COLOR=BLUE;
    LCD_ShowString(30,130,200,16,16,"USB Connected "); //连接成功
    LED1=0;//DS1 亮
    }else
    {
    POINT_COLOR=RED;
    LCD_ShowString(30,130,200,16,16,"USB disConnected "); //提示断开
    LED1=1;//DS1 灭
    }
    }
    if(USB_USART_RX_STA&0x8000)
    {
    len=USB_USART_RX_STA&0x3FFF;//得到此次接收到的数据长度
    usb_printf("\r\n 您发送的消息为:%d\r\n\r\n",len);
    for(t=0;t<len;t++)
    {
    USB_USART_SendData(USB_USART_RX_BUF[t]);//按字节发送给 USB
    }
    usb_printf("\r\n\r\n");//插入换行
    USB_USART_RX_STA=0;
    }else
    {

    times++;
    if(times%5000==0)
    {
    usb_printf("\r\n 战舰 STM32 开发板 USB 虚拟串口实验\r\n");
    usb_printf("正点原子@ALIENTEK\r\n\r\n");
    }
    if(times%200==0)usb_printf("请输入数据,以回车键结束\r\n");
    if(times%30==0)LED0=!LED0;//闪烁 LED,提示系统正在运行.
    delay_ms(10);
    }
    }
    }
    在此部分代码用于实现我们在硬件设计部分提到的功能,USB 的配置通过三个函数完成:
    USB_Interrupts_Config()、Set_USBClock()和 USB_Init(),第一个函数用于设置 USB 唤醒中断和
    USB 低优先级数据处理中断,Set_USBClock 函数用于 配置 USB 时钟,也就是从 72M 的主频
    得到 48M 的 USB 时钟(1.5 分频)。最后 USB_Init()函数用于初始化 USB,最主要的就是调用
    了 Virtual_Com_Port_init 函数,开启了 USB 部分的电源等。这里需要特别说明的是,USB 配置
    并没有对 PA11 和 PA12 这两个 IO 口进行设置,是因为,一旦开启了 USB 电源(USB_CNTR
    的 PDWN 位清零)PA11 和 PA12 将不再作为其他功能使用,仅供 USB 使用,所以在开启了 USB
    电源之后不论你怎么配置这两个 IO 口,都是无效的。要在此获取这两个 IO 口的配置权,则需
    要关闭 USB 电源,也就是置位 USB_CNTR 的 PDWN 位,我们通过 USB_Port_Set 函数来禁止/
    允许 USB 连接,在复位的时候,先禁止,再允许,这样每次我们按复位电脑都可以识别到 USB
    鼠标,而不需要我们每次都拔 USB 线。USB_Port_Set 函数在 hw_config.c 里面实现,代码请参
    考本例程源码。
    USB 虚拟串口的数据发送,我们通过函数:USB_USART_SendData 来实现,该函数在
    hw_config.c 里面实现,该函数代码如下:
    //发送一个字节数据到 USB 虚拟串口
    void USB_USART_SendData(u8 data)
    {
    uu_txfifo.buffer[uu_txfifo.writeptr]=data;
    uu_txfifo.writeptr++;
    if(uu_txfifo.writeptr==USB_USART_TXFIFO_SIZE)//超过 buf 大小了,归零.
    {
    uu_txfifo.writeptr=0;
    }
    }
    该函数实现发送 1 个字节到虚拟串口,这里,我们用到了一个 uu_txfifo 的结构体,该结构
    体是我们在 hw_config 里面定义的一个 USB 虚拟串口发送数据 FIFO 结构体,定义如下:
    //定义一个 USB USART FIFO 结构体
    typedef struct
    {
    u8 buffer[USB_USART_TXFIFO_SIZE]; //buffer
    vu16 writeptr; //写指针

    vu16 readptr; //读指针
    }_usb_usart_fifo;
    extern _usb_usart_fifo uu_txfifo; //USB 串口发送 FIFO
    该结构体用于处理 USB 串口要发送的数据,所有要通过 USB 串口发送的数据,都将先存
    放在该结构体的 buffer 数组(FIFO 缓存区)里面,USB_USART_TXFIFO_SIZE 定义了该数组
    的大小,通过 writeptr 和 readptr 来控制 FIFO 的写入和读出,该结构体 buffer 数据的写入,是
    通过 USB_USART_SendData 函数实现,而 buffer 数据的读出(然后发送到 USB)则是通过端
    点 1 回调函数:EP1_IN_Callback 函数实现,该函数在 usb_endp.c 里面实现,代码如下:
    void EP1_IN_Callback (void)
    {
    u16 USB_Tx_ptr;
    u16 USB_Tx_length;
    if(uu_txfifo.readptr==uu_txfifo.writeptr) return; //无任何数据要发送,直接退出
    if(uu_txfifo.readptr<uu_txfifo.writeptr) //没有超过数组,读指针<写指针
    {
    USB_Tx_length=uu_txfifo.writeptr-uu_txfifo.readptr; //得到要发送的数据长度
    }else //超过数组了 读指针>写指针
    {
    USB_Tx_length=USB_USART_TXFIFO_SIZE-uu_txfifo.readptr;//发送的数据长度
    }
    if(USB_Tx_length>VIRTUAL_COM_PORT_DATA_SIZE) //超过 64 字节?
    {
    USB_Tx_length=VIRTUAL_COM_PORT_DATA_SIZE; //此次发送数据量
    }
    USB_Tx_ptr=uu_txfifo.readptr; //发送起始地址
    uu_txfifo.readptr+=USB_Tx_length; //读指针偏移
    if(uu_txfifo.readptr>=USB_USART_TXFIFO_SIZE) //读指针归零
    {
    uu_txfifo.readptr=0;
    }
    UserToPMABufferCopy(&uu_txfifo.buffer[USB_Tx_ptr], ENDP1_TXADDR, USB_Tx_
    length);
    SetEPTxCount(ENDP1, USB_Tx_length);
    SetEPTxValid(ENDP1);
    }
    这个函数由 USB 中断处理相关函数调用,将要通过 USB 发送给电脑的数据拷贝到端点 1
    的发送区,然后通过 USB 发送给电脑,从而实现串口数据的发送。因为 USB 每次传输数据长
    度不超过 VIRTUAL_COM_PORT_DATA_SIZE,所以 USB 发送数据长度:USB_Tx_length 的最
    大值只能是 VIRTUAL_COM_PORT_DATA_SIZE。
    以上,就是 USB 虚拟串口的数据发送过程,而 USB 虚拟串口数据的接收,则是通过端点
    3 来实现的,端点 3 的回调函数为 EP3_OUT_Callback,该函数也是在 usb_endp.c 里面定义,代
    码如下:
    void EP3_OUT_Callback(void)

    {
    u16 USB_Rx_Cnt;
    USB_Rx_Cnt = USB_SIL_Read(EP3_OUT, USB_Rx_Buffer);
    //得到 USB 接收到的数据及其长度
    USB_To_USART_Send_Data(USB_Rx_Buffer, USB_Rx_Cnt);
    //处理数据(其实就是保存数据)
    SetEPRxValid(ENDP3); //时能端点 3 的数据接收
    }
    该函数也是被 USB 中断处理调用,该函数通过调用 USB_To_USART_Send_Data 函数,实
    现 USB 接收数据的保存,USB_To_USART_Send_Data 函数在 hw_config.c 里面实现,代码如下:
    //用类似串口 1 接收数据的方法,来处理 USB 虚拟串口接收到的数据.
    u8 USB_USART_RX_BUF[USB_USART_REC_LEN];
    //接收缓冲,最大 USART_REC_LEN 个字节.
    //接收状态
    //bit15, 接收完成标志
    //bit14, 接收到 0x0d
    //bit13~0, 接收到的有效字节数目
    u16 USB_USART_RX_STA=0; //接收状态标记
    //处理从 USB 虚拟串口接收到的数据
    //databuffer:数据缓存区
    //Nb_bytes:接收到的字节数.
    void USB_To_USART_Send_Data(u8* data_buffer, u8 Nb_bytes)
    {
    u8 i;
    u8 res;
    for(i=0;i<Nb_bytes;i++)
    {
    res=data_buffer[i];
    if((USB_USART_RX_STA&0x8000)==0) //接收未完成
    {
    if(USB_USART_RX_STA&0x4000) //接收到了 0x0d
    {
    if(res!=0x0a)USB_USART_RX_STA=0;//接收错误,重新开始
    else USB_USART_RX_STA|=0x8000; //接收完成了
    }else //还没收到 0X0D
    {
    if(res==0x0d)USB_USART_RX_STA|=0x4000;
    else
    {
    USB_USART_RX_BUF[USB_USART_RX_STA&0X3FFF]=res;
    USB_USART_RX_STA++;
    if(USB_USART_RX_STA>(USB_USART_REC_LEN-1))
    USB_USART_RX_STA=0;//接收数据错误,重新开始接收

    }
    }
    }
    }
    }
    该函数接收数据的方法,同第九章串口通信实验的串口中断接收数据方法完全一样,在这
    里就不详细介绍了,请参考第九章相关内容即可。USB_To_USART_Send_Data 函数类似于串口
    通信实验的串口中断服务函数(USART1_IRQHandler),完成 USB 虚拟串口的数据接收。

    展开全文
    cjianeng 2020-10-26 16:48:28
  • stm32usb虚拟串口驱动是针对win7 64位系统打造的专用驱动程序,该驱动主要用于解决在运行一些设备是提示无示使用的问题,安装后就可以正常使用了,有需要的朋友快快下载吧。驱动安装说明usb虚拟串口缺失文件和驱动X...

    stm32usb虚拟串口驱动是针对win7 64位系统打造的专用驱动程序,该驱动主要用于解决在运行一些设备是提示无示使用的问题,安装后就可以正常使用了,有需要的朋友快快下载吧。

    驱动安装说明

    usb虚拟串口缺失文件和驱动X64位系统用

    安装驱动前先不要连接usb线,将下载的文件解压:

    将mdmcpq.inf复制到c:/windows/inf/里面去

    将usbser.sys复制到C:/windows/system32/drivers/里面去

    安装驱动软件VCP_V1.3.1_Setup_x64.exe,64位机安装X64

    然后重新插入usb线,并在设备管理器界面右键选更新驱动

    使用说明

    首先打开官方demo我们开始进行移植,第一步复制我们可用的文件,操作如下:

    Projects\Virtual_COM_Port文件夹下,复制红线部分

    5b299f6ed515ebd2cb2c340c644fe2a0.png10b021de6d40a68e84addbebd7094748.png

    我为了方便演示统放在usb/src文件夹下:

    349509386ddded7aa04896b29765f1e3.png

    现在复制USB的库文件,这些文件不需要我们修改:

    d1c3157c255e5cb78d4242fba2f7d352.png

    上图中的文件统一放在usb/lib文件夹下:

    c865e4752d8f613166b7d0334aa896c9.png

    好了现在所需要的文件我们以复制完了。这里先讲一下DEMO程序的主要工作流程:

    df086b1c93eb6af1de173a9327b2c350.png

    由上图可知,PC通过虚拟串口发送数据到STM32 usb口,STM32再通过usart1发送数据到PC串口。我们做项目时,只用USB虚拟串口即可。所以我们现在需要把串口发送部分删除。把USB做为一个COM口来使用。我们要如何使用这个USB口呢?demo中是把USB发送数据做了一个缓存,先把要发送的数据存入缓存中,然后由USB自动发送出去。而接收部分是直接通过串口透传。我们在应用时就需要用到两个FIFO,1是发送,这个和demo方式是样;2是接收,接收也做一个缓存,我们通过查询来判断是否收到新数据。

    使用教程作者:Hiker天下

    展开全文
    weixin_33272515 2021-05-14 15:38:12
  • 5.84MB chun_love_shuo 2019-04-17 15:31:05
  • 1. USB虚拟串口简介 USB虚拟串口属于USB通信设备类。在物理层通过USB总线,采用虚拟串口的方式为主机提供一个物理串口。在系统内部,USB控制器提供了一个批量传输IN端点和一个批量传输的OUT端点,用于数据的接收和...

    1. USB虚拟串口简介

    USB虚拟串口属于USB通信设备类。在物理层通过USB总线,采用虚拟串口的方式为主机提供一个物理串口。在系统内部,USB控制器提供了一个批量传输IN端点和一个批量传输的OUT端点,用于数据的接收和发送,模拟串口的RX和TX线。另外USB控制器还提供中断IN端点,发送当前串口的状态,实现对串口传输的控制。串口设备的数据,由系统的串口采集,在芯片内完成USB包的封装,通过USB总线上传至主机,再由相应的串口应用程序进行处理。对用户来说,看到的是基于串口的数据采集和传输,而实际上实现的是基于USB协议包的数据传输。

    1.1      USB CDC协议简介

    USB的CDC类是USB通信设备类(Communication Device Class)的简称。CDC类是USB组织定义的一类专门给各种通信设备(电信通信设备和中速网络通信设备)使用的USB子类。根据CDC类所针对通信设备的不同,CDC类又被分成以下不同的模型:USB传统纯电话业务(POTS)模型,USB ISDN模型和USB网络模型,其中USB传统纯电话业务模型又可分为直线控制模型(Direct Line Control Model)、抽象模型、电话模型,如图 1.1所示。本文讨论的虚拟串口就属于USB 传统纯电话业务模型下的抽象控制模型。

    图 1.1 CDC分类

    1.2      Linux下USB虚拟串口框架

    如图 1.2所示,Linux实现了gadget.h定义的统一接口,然后上层的各种gadget driver(如serial.c等)调用这一套统一的接口可以去实现不同类型的功能,如USB串口、U盘、USB以太网等等。

    图 1.2 USB虚拟串口框架

    在Linux中通过USB虚拟的其他设备都需要经过Gadget层的绑定,最终与虚拟的相关设备进行绑定。有关Gadget的绑定流程在之前的文档中已做过详细介绍,在此不做过多阐述。

    展开全文
    Best_Ccc 2017-11-24 15:00:46
  • weixin_30368405 2021-02-04 21:33:51
  • dsanmux 2015-09-10 17:02:43
  • 152KB weixin_38723559 2020-12-13 15:12:59
  • 5.9MB weixin_38548231 2021-04-21 22:42:44
  • 23.82MB flyincunt 2020-08-18 14:12:28
  • 16.57MB WANGMIN_AASG 2020-09-25 15:16:33
  • 13KB asasd_000 2016-11-16 19:02:29
  • 142KB weixin_38516270 2020-08-18 10:45:25
  • RootCode 2018-12-06 16:35:34
  • weixin_31633071 2021-02-04 21:34:11
  • weixin_30938397 2021-05-13 10:25:54
  • aqwtyyh 2019-08-22 14:10:36
  • d1w2jsw 2021-01-04 22:52:26
  • sz189981 2017-03-25 20:50:26
  • qq_21158221 2018-05-28 13:18:26

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,722
精华内容 3,088
关键字:

usb模拟串口pc软件