单片机外围模块漫谈之五,USB开发,别犯这个错误
1.
概述我们已经对USB硬件和数据的四种传输类型有了一个基本的了解。
控制传输(Control Transfers)
批量传输(Bulk Data Transfers)
中断传输(Interrupt Data Transfers)
同步传输(Isochronous Data Transfers):
下面我们通过一个例子看一下USB的具体工作过程。在此我们用一个比较实用的例子,就是把我们的板子用USB连接至PC,然后在PC端出现一个模拟串口,通过串口助手打开这个串口,然后实现数据的双向传输。最后我们聊一下很多工程师都会忽视的USB认证问题。
2. 例程
我们打开ST的Cube库中的CDC例程:
STM32Cube_FW_F1_V1.8.0\Projects\STM3210C_EVAL\Applications\USB_Device\CDC_Standalone\MDK-ARM\Project.uvprojx
这个例程用到USB的同时还会用到USART,USB从PC端收到数据后会转发到USART,从USART接收到消息会上传至PC。我们可以把USART的TX和RX短接,这样从PC端下发的数据会原样回传给PC端。
这个例程使用的硬件是STM3210C-EVAL,原理图可以在stmcu.org.cn找到。如果我们使用的是其它板子,就需要在这个工程基础上做一些改动。比如现在我们使用STM32F105RBT6,8M晶振,串口用PTA2,PTA3,那么我们的要做如下修改:
首先,修改使用的MCU:
然后修改时钟初始化部分。下图为STM32F105时钟模块示意图。USB工作需要48MHz的时钟。
(STM32F105xx Datasheet)
如果板子的晶振是8M,那么参数需要做如下配置:
(OSC IN = 8M)
PREDIV1SRC = 0b0, HSE oscillator clock selected as PREDIV1 clock entry
PREDIV1 = 0b0, PREDIV1 input clock not divided
PLLSRC = 0b1, Clock from PREDIV1 selected as PLL input clock
PLLMUL = 0b0111, PLL input clock x 9
(PLLCLK = 72M)
SW = 0b10, PLL selected as system clock
PLLVCO = 2*PLLCLK = 144M
USBPRE = 0, PLL clock is divided by 1.5 (or PLLVCO/3)
USB Clock = = PLLCLK/1.5 = 72M/1.5 = 48M
例程中的对应代码修改:
最后修改使用的串口引脚:
stm32f1xx_hal_msp.c
//AFIOCOMx_REMAP(0); // Remap USART2 to PTD5/6
usbd_cdc_interface.h
/* Definition for USARTx Pins */
//#define USARTx_TX_PIN GPIO_PIN_5
//#define USARTx_TX_GPIO_PORT GPIOD
//#define USARTx_RX_PIN GPIO_PIN_6
//#define USARTx_RX_GPIO_PORT GPIOD
#define USARTx_TX_PIN GPIO_PIN_2
#define USARTx_TX_GPIO_PORT GPIOA
#define USARTx_RX_PIN GPIO_PIN_3
#define USARTx_RX_GPIO_PORT GPIOA
终于可以编译运行了,用USB线把板子连到PC的USB口,记得把板子的PTA2和PTA3引脚短接起来。在设备管理器我们看到多出来一个串口,看它的属性会看到它的VID,PID跟我们程序中设置的一致。
用串口助手打开此串口,发送字符串,会看到返回同样的字符串。
下面我们来看一下具体的工作过程。
3. USB枚举(Enumeration)
当我们给设备上电,程序控制芯片内集成的上拉电阻连接至USBDP时,USB主机(PC端)会检测到这一变化并向设备供电。此时设备处于Powered状态。
主机等待100ms设备稳定后复位并使能此端口,此时设备可以从Vbus获取不超过 100mA 的电流,其默认地址是0,处于Default状态。
主机通过0地址向该设备发送Get_Descriptor标准请求,获取设备的描述符。主机再次复位该PORT,并发送标准请求Set_Address给设备分配一个地址,之后的通信都是用此地址,设备进入Address状态。
主机通过新地址向设备再次发送Get_Descriptor标准请求,获取设备描述符。发送Get_Configuration请求,获取配置描述符。一个设备可以有多个配置,主机选择合适配置,通过 Set_Configuration请求对设备而进行配置,设备进入Configured状态。
USB的枚举过程是标准的,所以库里也有对应的标准处理代码。我们可以不用关心。好了,现在可以开始数据的双向传输了。
4. 数据传输
我们已经了解所有USB传输都是由USB主机(Host)发起的,作为USB设备只能是被动的等待。当Host下发请求时会在设备中产生各种中断,设备完成各种中断的处理就行了。其中需要特别关注的有两个:
OEPINT(Output Endpoint Int),表明主机下发了数据。
IEPINT(Output Endpoint Int)。表明主机请求设备上传数据。
那么用户在代码里如何收发USB数据的呢?
我们在usbd_cdc_interface.c里关注下面这些就够了:
uint8_t UserRxBuffer[APP_RX_DATA_SIZE]; //USB下发数据缓冲区
uint8_t UserTxBuffer[APP_TX_DATA_SIZE]; //需要发给USB上位机的数据缓冲区
下面这个函数是用户用来处理接收缓冲区数据的,在初始化时需要传递给USB驱动,然后驱动收到USB下发的数据后会回调此函数。在例程中此函数把接收数据转发给了USART2。当然你也可以什么都不做。
static int8_t CDC_Itf_Receive(uint8_t * Buf, uint32_t * Len);
那么如果有数据需要发给上位机呢?我们可以用下面这个函数:
USBD_CDC_TransmitPacket(&USBD_Device);
注意此数据是先放入IN端点,然后等待IEPINT中断发生时才被取走发送。
5. 一个重要又容易被忽视的问题
至此好像万事大吉了。
等等,如果产品这样发出去,你可能给公司惹麻烦了!
还有一个很重要的问题我们千万不要忽视,就是VID和PID,即厂商识别符(Vendor ID)和产品识别符(Product ID)。我们例程中使用的是VID 0x0483, PID 0x5740。这个VID是专门分配给ST的,虽然我们用这个号程序也能运行,但是不符合规范的。我们的可以在 usb.org/developers 网站查到当前为所有USB厂商分配的VID。如果我们要开发USB设备,还要向USB组织申请自己的VID,之后还要做微软徽标认证,就可以畅行无阻了。
参考资料:
UM1734 STM32Cube USB device library
USB Specification 2.0
Universal Serial Bus Class Definitions for Communications Devices 1.2
STM32F105xx Datasheet
STM32F105xx RM
如何完整开发一个USB设备?专家手把手带你入门
第2章 我们需要做什么
前面已经初步介绍了USB的基础知识,是时候开始着手USB设备开发了。我们先来看看完整开发一个USB设备需要做些什么,这有助于从宏观上建立USB设备开发的概念,如图2.1所示。
图2.1 完整的USB设备开发流程
USB设备开发的首要步骤便是对系统需求进行分析,它的目的就是解决这样一个问题:你打算采用什么方案来开发USB设备呢?不同方案的实现,其复杂程度与开发周期会完全不一样,这需要结合自己的项目来决定,包括设备类型、功能、数据传输类型与速率、硬件资源、成本、功耗等。
既然是进行USB设备的开发,必然最终会有一个能够拿在手里(实实在在)的东西,这就属于硬件范畴。例如,USB鼠标内部通常会有印制电路板模块(Printed Circuit Board Assembly, PCBA),上面安装了一些“采集滚轮位置与轻触按键状态信息并发送到主机”的电路,也就是我们讨论的硬件,而系统需求分析的最后落点就在于USB接口芯片的选型。
现如今市面上的USB接口芯片总体上可以分为单纯的USB接口芯片与带USB接口的单片机两大类,它们在硬件层面的区别如图2.2所示。
图2.2 两种USB接口芯片在硬件层面的区别
单纯的USB接口芯片只负责与USB主机进行通信,通常仅包含直接与外部电信号打交道的物理层(Physical Layer, PHY),以及处理底层USB协议的单元,所以还需要另一个处理器实现其他更高层面的协议处理与数据交换,如菲利浦公司(Philips)生产的PDIUSBD12芯片(现已停产)。这类芯片提供了一些接口供处理器进行控制,不同厂商的USB接口芯片在USB协议上会有着不同程度的支持。所谓的“支持”,是指USB协议由软件还是硬件来实现,因为USB协议在逻辑上分为很多层,具体的实现方法可以是硬件或软件。接口芯片的硬件实现层面越多,成本越高,但速度会更快,软件编程方面也会更简单。带USB接口的单片机则将USB接口芯片集成到了单片机中,将其作为一个USB控制器挂在内部总线,这样我们就可以像访问单片机中其他诸如SPI(Serial Peripheral Interface)、I2C(Inter-Integrated Circuit)等总线控制器一样,只需要访问为其分配的一些寄存器或缓冲区即可,是不是很简单!相应的典型芯片是由赛普拉斯公司(Cypress)生产的基于51内核的CY7C68013。简单地说,带USB接口的单片机属于单芯片解决方案。
那么实际进行USB设备应用开发时选择哪种好一些呢?主要考虑因素还是成本。单纯的USB接口芯片成本低,接口使用也方便,即使现有产品需要重新设计时也不需要做很大的改变,非常有利于整合与重用现有资源。例如,你们公司所有产品如果都在使用某几款基于51内核的单片机,那么在进行新的USB设备开发时,肯定也希望能够重用它们,这样有利于共享其他资源,而且开发工程师对相应单片机已经非常熟悉,也就能够缩短开发周期,提前一步将产品推出去,这些都有利于降低成本。带USB控制器的单片机的优势当然是更简单,但它不一定与你们公司现有的单片机内核相同,开发者可能需要重新学习。更重要的是,如果某一天需要切换到另一款带USB控制器的单片机更是困难,源码移植可得费不少工夫。如果采用单纯的USB接口芯片,则没有这个问题,USB接口芯片即使进行了更换,单片机源代码只需要修改与USB接口芯片通信的那部分即可。
本书为了阐述的方便,决定采用带USB控制器的单片机,即基于ARM 32位Cortex-M3内核的STM32F103C8T6单片机,它集成了USB 2.0全速控制器。需要特别注意的是:本书虽然使用STM32F103C8T6作为阐述平台,但并没有对与USB控制器无关的其他模块进行深入探讨,因为本书旨在详尽阐述USB设备的开发思路及透彻理解USB 2.0规范,这对于所有平台都是通用的。换句话说,只要你需要学习USB设备开发,无论使用的单片机型号与本书是否相同(包括其他厂商带USB控制器的单片机,或单纯的USB接口芯片),本书所述内容对你都是适用的。
USB接口芯片选型完成后,就开始进入USB设备的硬件设计环节,包括原理图与PCB设计、PCB制造、元器件采购及焊接调试等步骤,如图2.3所示。值得一提的是,现如今网络电商已经非常发达了,不仅仅是元器件采购,即使是PCB制造也能够轻松找到PCB厂商,我们只需要到相应的官方网站自助上传PCB生产文件(通常是PCB光绘文件)下单,再等待比较短的周期就能够(通过快递方式)收到制作完成的高质量PCB,跟以前在学校使用机器手工制作单面PCB相比,实在是太方便了。
图2.3 USB设备的硬件设计
USB设备的硬件设计完成之后,就得着手USB设备的软件设计了,我们将最终下载(也常称为“烧写”或“编程”)到单片机内部只读存储器(Read-Only Memory, ROM)的程序称为固件(Firmware),它是USB设备的核心,通常总是会完成至少一个功能。例如,对于USB鼠标设备,固件的作用是采集用户的操作信息并将其上传到主机。对于使用USB接口的逻辑分析仪,固件的作用是根据主机设置的数据采集参数,将采集到的参数回传给主机。为了区别于主机端的软件设计,我们称为USB设备的固件设计。
一般说来,硬件方案确定之后,相应USB设备的开发环境也就基本确定了。为什么这样说呢?因为芯片的制造厂商并不单纯地制造出芯片就完事了,为了让客户更容易地使用而达到快速占领市场的目的,总会有单独的部门进行演示板(Demonstration, DEMO)或评估板(Evaluation Board, EVB)的设计与开发,笔者曾经入职过的某集成电路设计公司的客户服务(Customer Service,CS)部门就是做这种事情的。简单地说,评估板存在的意义就是将厂商制造该芯片的市场战略意图表达出来,它通常包含相关的硬件原理图、PCB文件、物料清单(Bill of Material, BOM)、数据手册(Datasheet)、设计说明书及必要的软件例程等。通俗地说,评估板就是想告诉你:我这个芯片可以做什么?如果你要快速使用它,应该怎么做?
评估板在芯片推广过程中扮演了非常重要的角色,它不仅存在于很多简单的纯硬件类芯片中,对于稍显复杂(或需要单片机控制)的芯片更是如此,USB接口芯片的底层还是有些复杂的,所以相应的芯片厂商必然会准备好配套的评估板。
当我们开始设计USB设备固件时,一般都会直接参考厂商发布的固件例程。例如,将相关源代码复制到自己原来产品的工程目录下。当然,也有更直接的方式:直接在厂商发布例程的基础上更改!有些人可能会想:这也太没有技术含量了吧?我要重新编写固件来体现自己非凡的技术水平!行,你想这么做我当然不会阻止,但你的老板肯定不会答应,既然有现成且经过验证的成熟案例参考,为什么还要自己重新编写呢?在这方面,我还是跟你的老板站在同一战线的,因为芯片厂商肯定对自己的产品理解更深刻,发布的例程相对而言会更稳定。在极端情况下,芯片本身可能存在一些设计缺陷,需要在固件层面进行弥补,这种情况我们通常是无法知道的。有些芯片厂商会针对内部与外部(客户)开放两套数据手册(披露的细节不一样),所以我劝你还是别打“重新设计固件”的主意了!
对于有些USB设备,设计完硬件电路与设备固件后,整个USB设备开发流程可以算是完成了。有些人会想:好像不对吧!不是听说还要开发主机端的设备驱动程序与应用程序吗?这里可以回复:它们并不是必需的步骤!当你购买USB鼠标或键盘时,恐怕很少听说还要安装驱动或应用程序吧!换句话说,是否需要设计USB主机端的设备驱动程序与应用程序,取决于你开发的USB设备的具体功能。Windows操作系统为了方便用户使用USB总线与主机进行通信,已经提供了很多USB标准设备类驱动程序,如果你开发的USB设备符合某一种标准设备类,那么设备驱动程序的开发并不是必需的。例如,USB鼠标与键盘就不需要开发驱动程序与应用程序,因为它们是按照一定的规范(格式)向主机传递数据的,操作系统有能力进行适当的解析。
当然,是否需要开发设备驱动程序,还取决于选择的开发方式,即使两个USB设备的功能完全一样,你可以选择按某类标准设备进行开发,也可以自行开发设备驱动程序。选择前者就意味着不需要单独开发设备驱动程序(甚至应用程序),带来的好处就是开发流程简洁且周期短,大多数简单的USB设备都可以这么做,而缺点在于无法最大限度地挖掘USB设备的潜力。换句话说,USB主机只能以一定有限的能力与USB设备打交道。如果你对USB设备开发已经非常熟悉了,开发周期对你来说也完全不是事,而且对USB设备要求比较高,那么你也可以选择自行开发设备驱动程序。
设备驱动程序的具体开发形式也有几种,Windows 2000/XP/2003平台采用Windows驱动模型(Windows Driver Model, WDM),使用相应的驱动程序开发包(Driver Developer Kit, DDK)是开发方式之一,但是它对开发者要求比较高,可以理解为专门开发驱动的工程师采用的方式(简单地说,开发难度大)。为了简化驱动程序的开发,康博(Compuware)公司开发的DriverStudio软件平台对DDK进行了封装,使用起来更加方便,减少了开发时间,曾一度成为设备驱动程序的主流开发方式之一。后来,微软对WDM进行了优化,推出了全新的Windows驱动框架(Windows Driver Foundation, WDF),并提供相应的驱动开发包(Windows Driver Kit, WDK),它提供了面向对象和事件驱动的驱动程序开发框架,大大降低了开发难度,也直接导致了DriverStudio软件平台退出了历史舞台(不再支持最新的操作系统),掌握Windows设备驱动程序的开发人员,由过去的“专业”人士变为“普通”大众。
随着时代的快速发展,设备驱动程序的开发也已经变得更加简单了,即使我们不编写任何一行核心驱动程序代码,也能够轻松访问操作系统上的任意一个USB设备,只需要安装USB通用设备驱动程序即可,WinUSB与LibUSB就是目前应用广泛的两种,前者由微软提供且仅适用于Windows操作系统,后者则适用于包含Windows在内的多种操作系统,也是本书重点讨论的对象。
如果实在有必要,可能还需要开发与USB设备配套的应用程序,你可以将其理解为“能够进行数据分析、展示、控制等功能”的窗口界面(当然,也可以没有窗口界面)。如果你的USB设备不需要这样的功能,那就不需要做什么。例如,USB鼠标就不需要开发对应的应用程序,我们直接将其插入主机的USB接口就可以使用。而很多诸如逻辑分析仪、示波器等USB设备还会配带相应的应用程序,设备采集完数据发送到主机之后,还需要配套的应用程序进行数据分析并以图形的方式展示出来方便观察,此时应用程序设计就是必需的步骤。换句话说,如果USB设备往主机传输的数据需要特定应用程序去解析,通常就需要进行应用程序的设计。
使用成熟的框架是Windows应用程序的主要开发手段,比较常用的有MFC(Microsoft Foundation Class,微软基础类库)、.NET与QT。其中,MFC与.NET是微软提供的框架(相应的开发工具为Microsoft Visual Studio),后者更是微软当前主推的框架,QT是一个跨平台的C++图形用户界面应用程序开发框架。本书决定选择MFC,因为其相关学习资料很丰富,非常有利于初学者快速定位开发过程中的问题所在。当然,你并不需要对MFC很熟悉,我们只会使用向导创建一个对话框应用程序,并在其中编写一些用来访问USB设备的简单源代码。你也可以根据自身的知识储备选择其他熟悉的框架,只要在Windows平台下进行USB主机应用程序的开发,不同开发框架的选择对理解相关内容并没有影响,关键在于掌握Windows平台下访问USB设备的基本原理。
相关问答
单片机 与 usb 怎么连接?单片机与电脑连接一般有以下几种:1、RS232串口连接,这是最普遍的连接方式。2、RS232-usb,这种方式越来越受欢迎。3、JTAG--JLINK--USB(RS232),主要用于...
usb 接口怎么下载到 单片机 里面?您好:看你使用什么样的单片机,如果是STC系列的,可以直接用串口线下载,也可以用USB下载线下载(USB下载线网上有得买),下载软件是这个:STC_ISP_V480.exe;...您...
肿么通过 Usb 插口给51 单片机 供电-ZOL问答这个容易,在单片机上,USB接口的Vcc接5V,GND接地。就可以了,USB从电脑出来可以达到500mA,供一般应用足够了。数据线单片机测可以自己定义,只要符合规则,外形可...
我有一个 单片机 是 USB 的数据,怎么实现无线传输,传到电脑上的数据与有线的一样?无线传输;首先你必须要了解单片机通过USB传输的数据的协议,数据是怎样发到电脑的USB,然后根据协议在自己设计无线传输方式。可以是红外,这个比较简单,传输...
单片机 是 USB 接口的,只要是 USB 数据线都能当做下载线吗,还是需要专门的下载线啊, 单片机 入门不懂啊?问题描述的不是很清楚,有些单片机是需要专门的下载线的,USB口是给实验板供电的。当然绝大多数的下载器也都是USB接口的,也可以通过该下载器给开发板供电,只...
怎么用 usb 转TTL线给 单片机 下载程序?找你的单片机的TXDRXD引脚,下载器的RXD接单片机的TXD,TXD接单片机的RXD,GND接单片机的GND,5V接单片机的5V的插针单片机(Microcontrollers)是一种集...
如何用 单片机 实现 USB 与备用电源的切换供电?-ZOL问答想让USB与备用电源之间实现切换供电,最简单的方法添加一个二极管即可实现,没必要那么复杂使用单片机。▲备用电源自动切换电路。电路如上图所示。二极管VD在...
单片机 中 USB 转串口什么意思, USB 不是串口吗,我记得是啊,为什么还要转?USB是通用串行总线接口,是四线的;串口,是九针的,也叫COM口,现在的主板上基本不作这个接口了,所以很多都是用USB口转成串口。USB是通用串行总线接口,是四线的;...
51 单片机 的 USB 通讯端口是哪两个?首先需要确定开发者选择的51单片机是否有USB通讯模块,如果没有,那肯定就没有标准对外接口,需要用IO口来模拟,IO口模拟的话,只要支持输入输出并有输入上拉功...
labview的程序怎样刷入 单片机 ?方法一找个仪器(示波器,daq)读电平时序自己解析,方法二找个i2c的转换芯片转串口或usb或者芯片提供dll,方法三搞个单片机自己写下位机解析时序再用串口传到电...