工业控制 | 能源技术 | 汽车电子 | 通信网络 | 安防监控 | 智能电网 | 移动手持 | 无线技术 | 家用电器 | 数字广播 | 消费电子 | 应用软件 | 其他方案

电路设计->微机单片机电路图->接口电路图->基于USB和多线程的实时数据采集系统

基于USB和多线程的实时数据采集系统

作者:Lamborghini时间:2009-10-15

  摘要:说明基于USB技术的实时数据采集系统的硬件、软件实现;重点介绍PDIUSBD12带并行总线的USB接口器件以及基于多线程思想设计应用程序的方法。

  关键词:USB PDIUSBD12 多线程 实时数据采集

  1 问题的提出

  随着信息技术的飞速发展,各种数据的实时采集和处理在现代工业控制中已成为必不可少的。这就为我们的设计提出了两个方面的要求:一方面,要求接口简单灵活且有较高的数据传输率;另一方面,由于数据量通常都较大,要求主机能够对实时数据做出快速响应,并及时进行分析和处理。

  传统的外设与主机的通信接口难以满足上述第一个方面的要求。这些接口一般采用PCI部线或RS-232串行总线。PCI总线虽然有很高的传输率(可达132Mbps),还能“即插即用”,但是它们的扩充槽相当有限,且插拔并不方便。

RS-232串行总线虽然连接方便,可是它的带宽非常有限,传输速度太慢,而且1条RS-232串口通信电缆只能连接1个物理设备。USB技术正是顺序这一要求提出的,它集PCI和RS-232的优点于一身:具有较高的传输速率(USB协议1.1支持最高传输速度达12Mbps,USB协议2.0支持最高传输速度可达148Mbps),实现了真正意义上的“即插即用”(Plug & Play),同时USB上最多可以连接127个外设。因此,将USB技术应用于数据的实时采集是非常适合的。

 

  实时系统对多任务的要求比较普遍。往往在后台采集数据、进行数据显示的同时,还要在前台界面对用户的操作做出响应。在实时系统中,对实时数据做出及时而准确的反应是十分重要的。由于受A/D采集速度等因素的限制,从硬件上采用USB接口技术的确可以提高速度,但毕竟潜力有限,因此在现有硬件设计基础上充分发挥软件的作用就能进一步提升速度。使用传统的单线程编程技术效率较低,无法及时处理,必须充分利用Windows的多任务处理功能,采用多线程编程技术来处理数据。

  在这个实时采集系统的设计上,我们将这两种技术结合起来:在硬件上采用USB技术;软件用VC++进行开发,采用多线程编程,使系统的效率从这两方面都得到提升。

  2 系统体系结构

  2.1 硬件结构

  整个系统硬件结构如图1所示。

  实时数据采集系统主要由多路选择开关、A/D转换、单片机系统、PDIUSBD12、微机组成。多路选择开关对多路信号进行选择,使其分时输入;A/D转换实现模拟信号的数字化;单片机系统主要完成信号采集、数据通信;PDIUSBD12实现USB接口;微机完成数据接收、存入数据库、数据处理、计算、显示等功能。

  其中PDIUSBD12是系统USB技术得以实现的关键。它是Philips公司的一个带并行总线的USB接口器件,支持本地的DMA传输。它完全符合USB1.1版的规范,同时集成了SIE(串行接口引擎)、FIFO存储器、收发器以及电压调整器。其主端点的双缓冲配置增加了数据吞吐量并轻松实现实时数据传输,功能框图如图2所示。

  

 

  在这个系统中,单片机采用的是80C52。PDIUSBD12与80C52的接口有2种方式:多路地址/数据总线方式、单地址/数据总线方式。我们采用的是前一种方式:使用了80C52的INT0、ALE、WR、RD和P0口,当PDIUSBD12接收到主机的有效信息时,会产生一个中断通知80C52进行处理。在此种方式下,PDIUSBD12在ALE下降沿的时候,对单片机的输出地址进行锁存。若输出地址为奇数,则表示对PDIUSBD12发送指令;若输出地址为偶数,则表示对PDIUSBD12进行数据传输。接口电路如图3所示。

  80C52将A/D采集的数据经PDIUSBD12的并行接口送入FIFO存储器。当USB的传输速率达到12Mbps时,MMU(存储器管理单元)和集成RAM作为USB之间速度差异的缓冲区,这就允许单片机以它自己的速率对USB信息包进行读写。若FIFO中数据已满,SIE会立即对数据做处理:同步模式的识别、并行/串行转换、位填充/解除填充、CRC校验/产生、PID校验/产生、地址识别和握手评估/产生。SIE实现了全部的USB协议层,完全由硬件实现而不需要固件的参与。数据经处理后由收发器通过数据线D+、D-传送到主机。对一个单片机而言,PDIUSBD12看起来就像1个带8位数据总线和1个地址位的存储器件。

  2.2 软件结构

  USB的软件系统包括三部分:客户应用软件、设备固件以及USB设备驱动程序。其中,设备固件和USB设备驱动程序又被称为主机软件。软件层次如图4所示。

  2.2.1 固件设备

  设备固件(firmware)是储存在程序内存中的代码。它使得USB接口芯片与主机和外设中其它电路能够通信。固件由USB驱动程序(USBD)、主控制器驱动程序(HCD)两部分组成。USBD的功能可以概括为:配置管理、总线管理、数据传输管理、提供客户服务。USBD把IRP划分为USB和设备需要大小的块,确保每一个设备能分配到它所要求的USB资源,这样它就可以支持USB设备配置。USBD提供了一个编程接口USBDI(USB驱动程序接口),给客户驱动程序一种方式,用于传输请求,传输的方向可以是来自或发往USB的功能单元。大量的客户服务是由USB的驱动程序提供的,它帮助USB的客户控制和访问它们的功能单元。HCD提供了对USB的低级支持,通过把IRP转换成为单独的事务处理后在USB上执行。

  

 

  本系统固件设计的目标是使PDIUSBD12达到最高的传输速度。微处理器主要忙于多路数据的采集及处理,PDIUSBD12的固件设计成完全的中断驱动。USB的传输可在后台进行,这确保了最佳的传输速率和更好的软件结构,同时简化了编程和调试。它的基本思想是:后台ISR(中断服务程序)和前台主程序循环之间的数据交换通过事件标志和数据缓冲区来实现。当PDIUSBD12从USB收到一个数据包时,就对单片机产生一个中断请求,单片机立即响应中断。在ISR中,固件将数据包从FDIUSBD12内部缓冲区移到循环数据缓冲区,并在随后请求清零PDIUSBD12的内部缓冲区,以使其能接收新的数据包。然后返回到主循环,检查循环缓冲区内是否有新的数据并开始其它的前台任务。

  基于这种结构,主循环不关心数据是来自USB、串口还是并口,只检查循环缓冲区内需要处理的新数据。这样,主循环程序专注于数据的处理而ISR能够以尽可能高的可能高的速度进行数据的传输。

  这部分程序结构可包括:

  主循环程序——发送USB请求,处理USB总线事件和用户功能处理等;

  硬件提以层——对单片机的I/O口、数据总线等硬件接口进行操作;

  PDIUSBD12命令接口——对PDIUSBD12器件进行操作的模块子程序集;

  请求处理程序——对USB的标准设备请求进行处理和对用户添加的厂商请求进行处理;

  中断服务程序——当PDIUSBD12向单片机发出中断请求时,读取PDIUSBD12的中断传输来的数据,并设定事件标志和Setup包数据缓冲区,传输给主循环。

  2.2.2 USB设备驱动设计

  在Windows下,与USB外设的任何通信必须通过USB设备驱动,这个驱动知道如何与系统的USB驱动和访问设备的应用程序通信。设备驱动是保证应用程序访问硬件设备的软件组件,使得应用程序不必知道物理连接、信号和与一个设备通信需要的协议等的细节,可以保证应用程序代码只通过外设名字访问外设或端口目的地。应用程序不需要知道外设连接端口的物理地址,不需要精确监视和控制外设需要的交换信号。

  设备驱动通过在应用层和硬件专用代码之间的转化来完成它的任务。应用层代码一般使用一套操作系统支持的函数,硬件代码则处理那些访问外设电路的必要协议。设备驱动能与应用程序之间相互通信是通过Windows提供的API函数,这些函数使应用程序能够控制显示器、处理信息、访问存储器、读写磁盘和其它设备。对于一些标准设备,

Windows提供通用驱动;不过,这个实时数据采集系统是自定义的设备,对此Windows并不提供通用的驱动,需要对设备编写自定义的驱动,并且必须遵循微软在Windows98和更新版本中为用户定义的Win32驱动模式。Windows98和Windows2000中,USB总线驱动是WDM驱动,扩展名为.sys。编写USB设备驱动需要使用Visual C++,此外还需要Windows 98或2000设备开发包(98DDK/NTDDK)。USB设备驱动的编写通常不是一项简单的任务,驱动开发包就提供一种途径,通过做尽可能多的工作为跳过驱动开发,这些开发库有Blue Water Systems的WinDK和Compuware NuMega的DriverWorks。这些工具包能够集成到Visual C++编程环境中。运用这些工具包只需很少的时间就能生成一个高效的驱动程序。

 

  这一部分可以包括4个模块:初始化模块、即插即用管理模块、电源管理模块和I/O功能模块。初始化模块提供一个DriverEntery入口点来执行大量的初始化函数。即插用模块实现USB设备的动态插拔及配置。当硬件检测到USB设备接入时,Windows查找相应的驱动程序,并且调用它的DriverEntery例程,PnP(即插即用)管理器调用驱动程序的AddDevice例程,通知它添加了一个设备。驱动程序会收到一个包含有设备分配资源信息的启动设备的IRP,在对设备进行正确配置后,开始与硬件的对话。在运行过程中,如果设备被拔除,PnP会发出相应的IRP,驱动程序会进行盯应处理。USB设备的挂起和唤醒是由电源管理模块进行管理的。I/O功能模块完成I/O请求的工作。

  2.2.3 应用程序设计

  固件程序和USB设备驱动程序的设计是USB设备开发者的工作,对于广大用户而言,与系统的交互是通过应用程序实现,而且整个实时采集系统的主要数据处理都是在这里完成的。因此,运行效率高、界面友好、具有强大数据分析和处理的应用程序的设计,也是系统设计上一个不容忽视的关键因素。应用程序的主要功能有:启动/关闭USB设备,检测USB设备,设置USB数据传输管道/端口,设置A/D,采集数据,显示/分析数据。这里,我们采用Visual C++6.0作为程序的开发环境,并且充分运用了多线程的编程思想。

  在这个设备中,设置4个线程:首先是1个主线程,负责用户界面,并保持中枢地位。它的生存周期也就是整个用户程序的主存期,用户的动作(例如鼠标事件、键盘事件)都会触发主线程的消息机制,从而完成对用户的响应;而3个分离的辅助线程分别负责数据的采集、数据的分析处理以及数据的显示这3个不同的任务。辅助线程是在主线程运行过程中产生的,它的生命就是线程函数本身,函数一旦return,线程就结束了。因此,辅助线程的生存周期只是整个程序生存期的一部分。

  MFC程序只会有一个CwinApp对象,而CwinApp派生自CwinThread,即产生了应用程序的主线程。每当需要一个额外的线程时,应先产生一个CwinThread对象,再调用全局函数AfxBeginThread(),将线程产生出来。

  对于辅助线程(worker thread),要为它准备一个线程函数,然后调用AfxBeginThread()。例如:CWinThread* pThread=AfxBeginThread(ThreadFunc,¶m);

  UINT ThreadFunc(LPVOID pParam); //线程函数

  对于用户界面线程(UI thread),不能够光由一个线程函数来代表,因为它要处理消息,它需要一个消息循环。应该先从CWinThread派生一个自己的类,再调用AfxBeginThread()产生一个CWinThread对象。具体程序见本刊网站(http://www.dpj.com.cn)。

  结语

  基于USB技术的实时数据采集系统,在编程上运用了多线程思想;从硬件和软件两方面录求较佳的解决途径,并将二者结合起来,在实际中取得了良好的运行效果。



评论

技术专区