引言
USB(通用串行总线)集中了PCI和RS-232串行总线的优点,具有方便的即插即用和热插拔特性以及较高的传输速率,因此,将USB技术应用于数据采集是非常合适的,可以达到数据采集系统的高速度处理。目前,USB已经推出了其协议的2.0版本,速率高达480 Mbit/s。
本文研发了一套基于USB接口的数据采集系统,整个系统的设计涉及到硬件、设备固件(Firmware)、USB设备驱动程序及客户应用软件。下面分别加以说明。
1 USB接口芯片
本文介绍的USB数据采集系统采用了Cypress公司EZ-USB FX2系列的CY7C68013-128AC芯片,它同时集成了8051微控制器和USB2.0收发器,在提高集成度的同时也加快了数据传输的速度。在系统中,CY7C68013-128AC既是数据采集控制器又是USB控制器,EZ-USB FX2系列有3种型号:CY7C68013-56PVC、CY7C68013-100AC、CY7C68013-128AC。该系列的芯片都是针对USB2.0的,并且与USB1.1兼容。其中,CY7C68013-128AC是128脚,TPQF封装,功能非常完善,与另外两种相比,主要是增加了16位地址总线和8位数据总线以及更多的IO口,因此,CY7C68013-128AC的可扩展性最好。图1是该芯片的内部结构图。
2 USB的固件和驱动程序设计
2.1固件
固件是储存在程序内存中的代码,它使得USB接口芯片与主机和外设中其他电路能够通信。Cypress公司给出了一个固件库和固件框架(Frame Works),均是用Keil C51开发的。固件库提供了一些常量、数据结构、宏、函数来简化用户对芯片的使用;固件框架实现了初始化芯片、处理USB标准设备请求以及挂起状态下的电源管理等功能。该框架不添加任何代码,编码后产生的.HEX文件载入芯片就能与主机进行基本的USB通信,只是不能完成特定的任务。对于用户而言,主要的工作就是选择适当的传输方式,添加需要使用的端点(Endpoint),考虑到本系统要求实现一定数量数据的快速采集,并要迅速地将采集到的数据传输和进行分析处理,并且对数据的完整性要求较高,我们采用了块传输方式(Bulk Transfers),在TD-Init()函数中添加初始化代码,亦即选择块传输方式和选择端点2、6分别为输出、输入端口,在TD-Poll()函数中添加功能代码,以实现发送和接收数据功能,关键代码分别如下:
2.2 USB设备驱动程序
USB设备驱动程序主要是使操作系统能够识别USB设备,建立起主机端与设备端之间的通信,它们之间的通信是通过Windows提供的API函数实现的,这些函数可以控制显示器、处理信息、访问存储器、读写磁盘和其他设备。
图2是USB设备驱动程序的整体结构图。
USB设备驱动的整体结构包括如下5个主要部分:USB应用程序接口、USB设备驱动函数、USB中断服务程序、USB回调接口程序、USB标准事件处理程序。
2.2.1 USB应用程序接口
USB应用程序接口主要功能是对USB驱动器进行软硬件初始化、打开端口、关闭端口、读端口、写端口和端口控制操作。当设备驱动器装入系统设备表时,I/O系统就调用该应用程序接口。
USB应用程序接口的一个例程主要包含:
a)对USB端口安装、初始化和硬件配置(USB_init())。初始化步骤为:将USB设备驱动器安装到I/O系统设备表中,获取USB控制器使用的中断号,初始化USB驱动器数据结构与USB端口状态寄存器,启动USB标准事件处理程序。
b)打开USB端口(USB_open())。USB_open函数允许应用程序打开一个USB端口和选择DMA数据传输方式。
c)关闭USB端口(USB_close())。USB_close函数允许应用程序关闭一个端口,并关闭DMA通道。
d)对USB端口进行读操作(USB_read())。USB_read函数允许应用程序从输出端口或控制端口读取一定量的数据。
e)对USB端口进行写操作(USB_write())。USB_write函数与USB_read函数功能类似,允许应用程序写数据到输入端口或控制端口。
f)对USB设备进行I/O控制操作(USB_ioctl())。
2.2.2 USB中断服务程序
USB控制器产生单一中断,多个端口共享。每个端口产生ACK、NACK/ERROR中断;输出端口产生接收零字节包或短包中断;控制端口0接收设置包时产生中断;USB控制器产生USB事件中断,如帧起始(SOF)、挂起、恢复和复位。先识别发生USB中断的类型以清除中断产生的条件,再读USB状态寄存器,获取当前配置、接口或帧起始时间戳状态信息,最后向USB控制器消息队列或回调函数的接收消息队列发送中断消息。
2.2.3 USB标准事件处理程序
USB驱动器初始化后,启动USB标准事件处理程序负责处理枚举过程和异步USB事件。事件处理程序使用控制端口0,直到完成枚举过程。当USB应用程序处于非活动状态时,除控制端口0以外端口均不可访问。事件处理程序在端口0上执行控制操作,响应USB标准请求,并负责通知USB应用程序枚举完成和接口活动状态,USB事件通过回调接口传递到USB外设应用程序。当对USB端口枚举操作完成,USB应用程序就可打开并使用USB端口。
3客户应用软件
开发系统应用软件的底层,需要极好的兼容性和稳定性。对于广大用户而言,与系统的交互是通过应用程序实现的,因此,如何设计出运行效率高、界面友好、稳定性高的应用程序是至关重要的因素。。VC++是开发Windows应用程序的主流开发工具,充分利用它的面向对象特性的C++和功能强大的MFC来开发专业级的应用程序,MFC是一个强大的、扩展的C++类层次结构,它能使开发Windows应用程序变得更加容易,而且在整个Windows家族中都是兼容的。Lab-Windows/CVI是以ANSI c为核心的交互式虚拟仪器开发环境,它将功能强大的C语言与测控技术有机结合,具有灵活的交互式编程方法和丰富的库函数。本设计就是采用Visual C++6.0和LabWindows/CV提供的Graph控件来开发应用程序的,应用程序的主要功能有:打开/关闭USB设备,检测USB设备,实现向USB设备发送指定数量的数据。
下面是各部分的一些代码及说明:
1)查找、打开USB设备
2)线程(Thread)
线程就是程序中单独顺序的流控制。线程是进程中的实体,一个进程可以拥有多个线程,一个线程必须有一个父进程。线程不拥有系统资源,只有运行必须的一些数据结构;它与父进程的其他线程共享该进程所拥有的全部资源。图3是线程的状态转换图。
线程被分为两种:用户界面线程和工作线程(又称为后台线程)。本程序设计主要使用工作线程来执行数据的读写操作等,它与用户界面线程的区别是不用从CWinThread类派生来创建,对它来说最重要的是如何实现工作线程任务的运行控制函数。
对于工作线程来说,启动一个线程,首先需要编写一个希望与应用程序的其余部分并行运行的函数,如Fun(),接着定义一个指向CWinThread对象的指针变量*pThread,调用AfxBeginThread(Fun,param,priori-ty)函数,返回值赋给pThread变量的同时启动该线程执行上述Funl()函数,其中Fun是线程要运行的函数的名字,亦即控制函数的名字,param是准备传送给线程函数Fun的任意32位值,priority是定义该线程的优先级别,是预定义的常数,可参考MSDN。
本程序设计中的关键代码如下:
4实例
本例中使用了LabWindows/CVI的Graph图形显示控件,用来显示各类信号波形,如普通连续波信号波形、单载频矩形脉冲信号波形、调频(非线性调频)脉冲压缩信号波形和二相编码波形等。图4为各类信号波形图。这些信号均为数据采集系统的测试信号,可由DDS(直接数字频率合成器)芯片AD9858实现。
将图4中各类信号波形的频率、宽度、幅度和载频信号频率等参数读出来,分别进行一些计算,将计算出的结果通过USB口传送到DDS来产生波形;其他公共参数如"DDS时钟频率"根据实际采用的时钟频率设置。比如线性调频信号,一般关心的是一个信号的带宽、起始频率和调频斜率这3个值。这3个参数其实就是信号波形中的起始频率fs、终止频率f0和持续时间t,它们是等价的,现在把这些参数的值从测试信号波形中读出来,然后代入下式:DFRRW(8(f0-fs)/t)×231/SCLK。式中:SCLK是DDS的时钟频率,它的值设为1 GHz;DFRRW为步进频率斜率控制字,它的值设为1,代表每8 ns更新一次。最后把计算出的DFTW(步进频率调节字)值通过USB口传送到DDS。
另外,二相编码的实现是通过控制DDS的POW(相位补偿字)来实现的,通过改变PSO和PS1的值,就可以改变信号的相位,而且相位的改变可以是绝对调相和相对调相。这里使用了4个工作组,其中2个工作组的POW为0,另外2个工作组中的POW为π。将上面测试信号波形中的参数读出来,代人POW=214W/360中,其中W为波形的相位值,再把计算出的POW值通过USB口传送到DDS即可。
5结束语
本设计中使用的USB2.0作为接口部分,具有接口简单、传输速率高和即插即用等特点;应用程序充分利用VC的MFC框架的比较丰富的资源和LabWin-dows/CVI丰富的库函数,在进行数据采集和控制时,具有界面友好、兼容性和工作可靠、稳定等特点。