摘要本文描述了在实时数据采集系统中,利用DLL技术实现在VFP中调用C程序的方法,以及利用DDE技术实现前台数据采集应用程序与后台数据库管理系统之间的数据传递。
1引言
在实时数据采集系统中,往往需要将所采集的大量数据进行分类,筛选和存档,以备检索和分析。这就要用到数据库技术,而数据库语言(如VFP)一般不具备与硬件接口的能力,而C语言虽然可以用来编写实时数据采集程序,但对数据库管理的功能却不及数据库语言。因此,比较理想的方案是用C语言程序来负责实时数据采集,而采集来的数据交由VFP程序进行管理,使得两者的优势都得以发挥。而这种方案的关键技术在于WINDOWS环境下的C语言与VFP的接口,以及实时数据采集系统与数据库管理系统之间的数据交换技术。
在本系统中,我们将负责实时数据采集的应用程序称为"前台程序",将负责管理数据库的应用程序称为"后台程序"。前台程序用VFP编写,其中与硬件接口的部分用C语言编写,由VFP调用和控制。同时,前台程序提供人机界面,便于对控制参量进行输入和调节。此外,前台程序还实时的将采集到的数据传递给后台程序。后台程序与普通的数据库管理系统基本相同,具备数据管理的全部功能,同时,后台程序还负责接收来自前台程序的数据,并充实到数据库中去。
2前台程序
C语言程序具有直接驱动硬件的功能。因此,在前台程序中,与硬件有关的接口程序用C语言编制成可供调用的函数,设计专用的DLL(动态链接库),放置于WINDOWS的SYSTEM目录下,将有关的C函数置于DDL之中。DLL中的C函数的编写须注意以下几点:
(1)DLL中的函数不能拥有自己的窗口,所采集的数据的实时显示由C函数通过返回值传递给VFP程序,在VFP的表单中显示。
(2)DLL中的函数不设置消息循环。启动数据采集操作的消息(一般由定时器发出)发给VFP的表单,由VFP来调用相应的C函数,开始实时数据的采集操作。
(3) VFP在调用DLL的C函数之前,须用DE-CLARE-DLL命令对函数进行声明,其参数和返回值的类型如下表所示:
SHORT 16位整数
INTEGER 32位整数
SINGLE 32位浮点数
DOUBLE 64位浮点数
STRING字符串(char类型)
用DECLARE_DLL命令对函数进行声明之后,可象调用普通函数那样直接调用C函数。
(4)由于C函数参数的虚实结合是值传送,因此,如果被调用的C函数须将多个数据返回给VFP的话,只能将数据放在数组或结构中,并返相应的指针,而VFP对指针的处理是很困难的。解决的办法是:每个C函数只采集一个数据,并通过返回值将数据传递给VFP程序,对于多个数据的采集,由VFP多次调用C函数来实现。以下是给硬件端口送控制字的C函数例子:
#include
void setport(unsigned port-no,unsigned c-word)
&&port-no:端口地址,c-word:控制字
{
outportb(port-no,c-word);
}
总之,前台程序主要以VFP来构造,只是VFP语言不能完成的,与硬件直接接口的部分用C函数编写。至于DLL的设计和DECLAER-DLL命令的使用,限于篇幅,在此不一一详述,可参考有关资料。以下是前台程序的框架:
用可视化方法设计一表单,表单中加入如下控件:
(1)用于显示实时数据的若干文本框;
(2)若干编辑框和按钮,用来输入控制参数(如采集周期,控制方式等),可以调节实时采集系统的各种参数设定。
(3)一个计时器,用以产生定时间隔,在Timer过程中输入数据采集程序代码,每当Timer事件产生时,开始事件采集操作。
(4)显示日期和时间的文本框。
3前后台程序的数据传递
整个系统各个模块之间的关系如图1所示:

后台程序模块与普通数据库管理系统基本相同,前后台模块通过一个称之为"数据信箱"的临时数据库传递数据。采用这种方案,是基于这样一个原因:前台程序的实时性很强,一般始终处于连续运行状态,且不能被打断,否则有可能丢失数据,而后台程序的状态是随意的,甚至可以关闭。因此,前台程序每一次数据采集之后,将数据存入信箱,后台程序可在任意时刻到信箱中取数据,并充实到数据库中去,同时将该数据从信箱中删去。这样,前后台程序就可实现数据的异步传递。
显然,信箱数据库是前后台共享的文件,任何一方打开信箱时必须加锁。但是,在我们这个系统中,情况比较特殊:如前台程序欲打开信箱存入数据时,有可能因为后台程序正在使用信箱,前台程序就必须等待,用于前台程序的实时性很强,这种不可预知的等待有可能会造成数据采集的延误。因此,必须赋予前台程序对信箱的优先打开权。即只有在前台程序不可能使用信箱的时间段内,后台程序才能使用信箱。为了协调前台程序和后台程序打开信箱的时机,采取如下方法:
(1)在前后台之间,建立一DDE(动态数据交换)通道,前台程序为服务器方,后台程序为客户方。
(2)每当后台程序在打开信箱之前,先向前台程序提出申请,前台程序根据当前的状态,决定是否允许后台程序使用信箱,并将是否允许的标志通过DDE通道发送给后台程序。
(3)后台程序若收到允许标志,便可打开信箱取走数据,并充实到数据库中去;若收到禁止标志,则等待一段时间再行申请,直到被允许打开信箱为止。
(4)为防止后台程序占用信箱时间过长,后台程序从信箱每取一条记录都要申请一次,直到信箱中的所有记录全部取完。
(5)DDE通道采用"冷式链接",即每次申请在收到回答后,后台程序即将该通道释放,以尽量减少对前台程序的打扰。
(6)前台程序在启动数据采集之前,为了防止数据采集程序被打断,须禁止DDE通信,完成采集后再行开启。
4程序框架
4.1前台程序框架
(1)由Timer事件驱动的采集程序
DECLARE INTEGER Gather IN MYDLL;
integer outdata,integer outdata2,short DataNo
&&负责数据采集的C函数声明
LockBox= 'lock ' &&禁止后台程序打开信箱
=DDEEnabled(.F.) &&暂时禁止DDE链接
&&以下为数据采集操作
data1=Gather(0,0,1)
data1=Gather(0,0,2)
data1=Gather(0,0,3)
┇
&&data1,data2,data3,..作为表单中实时数据显示文本框的数据源
use box &&打开信箱,存入数据
┇
use
LockBox= ' unlock '
=DDEEnabled(.T.) &&开放DDE链接,允许打开信箱
(2)前台程序的DDE链接(在主控程序中)
public LockBox
LockBox= ' unlock '
=DDESetService( ' stage ' , ' DEFINE ' ) &&创建DDE服务器' stage '
=DDESetTopic( ' stage ' , ' TrData ' , ' Staproce ' ) &&创建主题词' TrData '
PROCEDURE Staproce
PARAMETERS channel,action,item,data,format,advise
IF action= ' REQUEST ' AND Item= ' LockBox '
=DDEPoke(channel, ' UseBox ' ,LockBox)
&&传送信箱标志,主题词为' UseBox '
ENDIF
Return
4.2后台程序的DDE链接
PROCEDURE DDELink
EmptyBox=.F. &&信箱空否标志
M=DDEINItiate( 'stage' , ' TrData ' )
IF m=-1
DDEFlag=.F. &&DDE通道建立失败
Return
ELSE
DDEFlag=.T.
LockBox=DDERequest(m, ' UseBox ' ) &&获得信箱标志
ENDIF
=DDETerminate(m)
IF LockBox= ' unlock '
use box &&打开信箱取数据
┇
use
ENDIF
Return
5结论
本系统所采用方案的主要特点体现在利用WIN-DOWS的多任务机制,将人们所熟悉的,较为成熟的数据管理平台用于实时控制系统,这对于充分利用PC机丰富的软件资源来提高实时控制系统的性能,具有较为普遍的意义。
参考文献
1蔡明志.高级WINDOWS编程.学苑出版社, 1994年
2申少军等. FoxPro 2.5大全.电子工业出版社, 1994年
3 Les Pinter. Visual FoxPro编程手册.科学出版社, 1997年




