在USB产生之前,现代工业生产中一般通过PCI口、ISA口或是RS232串行接口进行数据的采集;但是这些传统的接口存在着体积庞大、共享性差、电磁抗干扰性弱等缺点,因此所采集的数据容易失真,与传统的接口相比较,USB接口技术以其即插即用、热插拔、接口体积小巧、节省系统资源、传输可靠、提供电源、良好的兼容性、共享式通信和低成本等优点,成为外围设备与计算机进行连接的新型接口,同时也被广泛应用于现代工业数据采集。Cypress公司的EZ-USB FX2系列芯片中的CY7C68013就是一款性能较高的USB2.0微控制器,该数据采集卡就是以该芯片作为核心设计的。 1 USB型数据采集卡简介 该数据采集卡应用在电机参数测试虚拟仪器中,用来对电机的相关数据进行采集和分析,该数据采集卡基于USB总线,由A/D转换器、存储器、CY7C68O13芯片与工业控制计算机USB总线的接口等组成,模拟信号经过放大器放大,送到A/D转换器的输入端,在CY7C68013芯片的控制下由AD5220完成A/D转换,并把数据存放在存储器中,然后由工业控制计算机总线USB接口将数据调入计算机中进行处理,用户通过客户端软件即可对数据采集卡进行固件下载,获取管道信息,采集数据,进行存储等操作(而之所以要进行固件下载,是因为其没有ROM,每次上电都必须重新下载一个HEX文件,该固件的作用是辅助或者说控制硬件来完成预期的功能)。其中,CY7C68013接口芯片是Cypress公司EZ-USB FX2系列芯片中的一款,它是第1个集成了USB2.0协议的微处理器,它支持12 Mb/s的全速传输和480 Mb/s的高速传输,可使用4种USB传输方式:控制传输、中断传输、块传输和同步传输,完全适用于USB2.0,并向下兼容USB1.1。该芯片有以下的特点: 1)集成了一块增强型的8051内核.它比标准型的8051速度更快,功能更强,且指令集和标准8051完全兼容。 2)集成有一个串行接口引擎以及一个USB2.0收发器。由于USB2.0收发器和串行接口引擎完成了USB协议的封包、解包等功能,屏蔽了底层信号的电器特性。 3)支持软配置。采用再次枚举技术,固件程序可以保存在主机上,每次上电后通过USB接口将固件下载到芯片RAM 中,具有很大的灵活性。 4)通用可编程接口(GPIF)。GPIF提供可编程控制的接口时序,使得无需附加逻辑就能实现与外围芯片的连接。 5)4个可编程端口(Endpoint)。CY7C68013共有7个输入输出端口:EP0,EP1OUT,EP1IN,EP2,EP4,EP6,EP8.其中EP2,EP4,EP6,EP8分别可以被配置为批量/中断/同步传输模式,传输方向均可配置为出/入。 6)可编程缓冲区(Buffer)深度。端口EP2,EP6的缓冲区大小可编程为512字节或1024字节,深度可编程为2/3/4倍大小;端口EP4,EP8的缓冲区固定为512字节,深度为2倍。采用不同的配置方式,实现特定带宽,速率要求的数据传输。 2 固件编程 固件是在USB接口芯片加电后,由其他设备加载到CY7C68013中并在其中运行完成接口数据传送功能的一段程序.其作用是辅助或者说控制硬件来完成预期的设备功能.固件的主要功能包括:初始化工作;辅助硬件完成设备的重新列举(ReNumeration)过程,对主机的设备响应做出适当的响应;对中断的处理;数据的接受与发送;对外围电路的控制。 在该系统中,CY7C68013芯片的固件程序控制整个硬件系统的运行,并负责处理PC主机发来的各种USB请求,以完成它们之间的数据传输。该固件的编程,是根据Cypress公司提供的固件编程框架(如图1所示)来完成的。开发所使用的编程语言则是Keil公司的C51编译器,集成开发环境为uVision2。所使用的传输方式为高速块IN传输。 这个程序框架按照结构化的程序设计方法,将整个程序分为几个不同的功能模块,分别是初始化,重新列举和响应设备请求。 初始化:主程序一开始首先进行一些全局变量的初始化工作,之后调用TD-Init()函数.用户在该函数中添加自己的初始化代码以配置I/O端口.初始化工作还包括开中断,清除所有等待的USB中断请求等。 重新列举:初始化之后,固件程序将会检测是否收到设置数据(GOTSUD标志位是否为真);如果没有,程序会以1 s为间隔,软件模拟设备的断开和连接,直到收到设置数据为止。 最后就是响应设备请求。 在该固件的程序设计中,共包含9个程序文件:testregs.h,testregs.inc,testheader.h,testdly.h,dscrptr.a51,delayms.a51,jumptable.a51,main.c和function.c。其中,头文件testregs.h,testregs.inc对EZ-USB FX2中的各种功能寄存器进行了定义;testheader.h定义了通用的FX2常量、数据类型和宏;testdly.h定义了FX2中某些寄存器所需的同步延时宏;dscrptr.a51定义了系统所使用的各种USB描述符;delayms.a51中包含了延时1 ms子程序和芯片挂起处理子程序;jumptable.a51文件定义了FX2中的中断跳转表;main.c是固件运行的主程序文件,负责处理各种USB设备请求;function.c中包含各种功能函数的定义,如TD-Init和TD-Poll。 在main.c文件的基础上,还定义了3个中断服务子程序,其中2个中断将数据读取到块端点IN6的缓冲区,并配置端点IN2以供主机访问。function.c中的TD-Init函数负责对CY7C68013进行初始化,它在固件运行的开始时调用,首先设置CPU时钟为48 MHz,然后配置EZ-USB FX2的各个端点,最后是能下载FX2的双自动指针特性和远程唤醒功能。TD-Poll函数则负责完成USB块传输,在该程序中,使用了3个块端点:IN6,OUT2和OUT7。其中,IN6负责读取AD5220模数转换的结果,并将其送到主机;OUT2负责清空缓冲器并启动定时器;OUT7负责停止定时器。 3 应用程序 该应用程序主要负责读取系统硬件所采集的数据,并实时的以波形方式显示出来,同时还可以读取USB设备描述符、配置描述符和下载EZ—USB FX2固件代码的功能。它所使用的编程语言是微软公司的Visual C++。 1)EZ-USB FX2中寄存器CPUCS的第0位控制着增强型8051的复位操作,该位为1则锁定CPU为复位状态;该位为0则结束对CPU的锁定,使其开始正常工作。在该程序中8051的锁定和复位通过使用供应商自定义请求代码IOCTL-Ezusb_VENDOR_REQUEST来实现。其中,CPUCS控制寄存器的地址为0xE600,VENDOR_REQUEST_IN中的bData为1表示锁定,为0则为复位。实现8051锁定的部分代码如下: BOOLEAN CUsbhostDlg::usb8051hold (HANDLE *phDeviceHandle) { VENDOR_REQUEST_IN myRequest; …… myRequest.bRequest=0xA0;//固件加载请求 myRequest.wValue=0xE600;//cpucs寄存器的地址 myRequest.wIndex=0x00; myRequest.wLength=0x01; myRequest.bData=1;//传输的数据值,为1标示锁定,为0表示复位 myRequest.direction=0x00; bResult= DeviceloControl (hDevice, IOCTL_Ezusb_VENDOR_REQUEST, &myRequest,sizeof(VENDOR_REQUEST_IN), NULL, 0, (unsigned long *)&nBytes, NULL); …… } 2)下载程序按钮用于从主机上下载EZ-USB FX2的芯片固件程序,由增强型8051执行。该程序下载的文件类型为.hex,容量小于8 Kb,且仅能下载至FX2的片内RAM 中。其部分代码如下所示。它首先调用UsbOpenDriver来打开指定的USB设备;然后读取所下载文件的内容;最后使用IOCTL_Ezusb_ANCHOR_DOWNLOAD请求完成数据下载。在进行下载之前,要锁定EZ-USB FX2,下载结束后,要使用8051复位来结束锁定。其中的部分代码如下: void CUsbhostDlg::OnDownloadFile() { if(UsbOpenDriver(&hDevice,DeviceName)!= TRUE) {MessageBox("无效设备,请重试!"); return ; } BOOLEAN res1=usb8051hold(&hDevice); if(res1==TRUE) { CFileDialog dlgLoad( TRUE,0,0, OFN_HIDEREADONLY OFN_OVERWRITEPROMPT, dlgLoad.m_ofn.lpstrTitle= "Anchor Download"; if(dlgLoad.DoModal()!= IDOK) return; m_strDldFile= dlgLoad.m_ofn.lpstrFile; …… bResult= DeviceIoControl(hDevice,IOCTL_Ezusb_ANCHOR_DOWNLOAD, buffer, numreadfile, NULL, 0, &nBytes, NULL); …… //进行数据传输前,首先通过//IOCTL_Ezusb_RESETPIPE来复位管道6 bResultl= DeviceIoControl(hDevice,IOCTL_Ezusb_RESETPIPE, &input,sizeof(unsigned long), NULL, 0, &nBytes1, NULL); …… //启动接收数据的线程 g_KeepGoing = true; if(_beginthread(ReceiveThreadFunction,0,hDevice)< 0) { AfxMessageBox("启动接收数据线程失败!"); } } 3)在复位管道6之后,就准备接受数据了,然后调用_beginthread函数来启动接收数据的线程,其函数名是ReceiveThreadFunction。在该线程中,循环向块端点6发出IOCTL_EZUSB_BULK_READ 请求,来读取系统硬件所上传的数据,如果返回的数据长度是512字节,则说明读取数据成功了,同时把这些数据存储在硬盘上。ReceiveThreadFunction函数的部分代码如下所示: void _cdecl ReceiveThreadFunction(HANDLE hDeviee) { …… //读取数据 while(g_KeepGoing) { nBytes = 0; bulkContro1.pipeNum = 6; g_Transfering= FALSE; bResult= DeviceIoControl(hDevice,IOCTL_EZUSB_BULK_READ,&bulkC6ntrol, sizeof(BULK_TRANSFER_CONTROL),InBuffer,512,&nBytes, NULL); …… } 其余部分的代码不再赘述。 4 结语 在结合实际应用的基础上,笔者提出了在该数据采集系统中固件设计的方法以及固件程序的一些实现,同时也给出了应用程序中的部分代码。
|