LabVIEW与LabWindows CVI的联合编程

前言:
本文主要介绍NI公司图形化编程语言-虚拟仪器LabVIEW软件如何调用NI公司的基于C语言的开发环境-LabWindows CVI开发语言生产的(Dynamic Link Library,缩写为 DLL),实现不同开发环境之间LabVIEW和C语言的接口互连,提高不同开发环境之间的互操作性,极大方便了使用不同开发环境的软件工程师之间实现系统和软件集成;
LabVIEW是一种图形化编程语言,具有简单易学、形象直观的特点。同时,LabVIEW作为一种通用的、完善的高级编程语言,具有强大的外部接口能力,这些接口包括DLL、C语言接口(CIN)、 ActiveX、NET. DDE、MATLAB等。通过这些接口,用户能够方便地调用C、VC、VB、Labwindows CVI等编程语言编写的程序。可以实现LabVIEW与C、Basic、Matlab、Labwindows CVI等编程语言,甚至与外部应用软件(如Word、Excel等)之间的通信,达到代码复用及提高开发效率的目的。通过动态连接库DLL文件实现LabVIEW中与外部程序的接口技术,是最常用的一种方式,通过这种技术可以编写出功能更加强大的应用软件。
因此,通过示例来学习如何调用外部dll。动态链接库(Dynamic Link Library,DLL)是一个可以多方共享的程序模块,内部对共享的例程和资源进行了封装。动态链接库文件的扩展名一般是.dll,DLL 和可执行文件(EXE)非常类似,最大的区别在于DLL虽然包含了可执行代码却不能单独执行, 必须由Windows应用程序直接或间接调用。
一、简单实例
本节我们通过调用外部链接库的方式,来实现:输入一个 Double 型数组数组及其长度,输出一个整型数组。该整型数组中每个元素对应输入数组中每个元素求平方后的基数。
1.1 生成DLL文件
首先我们在Labwindows CVI中新建一个项目,写入算法代码并生成目标DLL文件:
方法如下:
打开LabWindows CVI 2019,选择 New-project,如下图所示;

选择File-New-Source(*.c)和File-New-Include(*.h),如下图所示;

选择Edit-Insert Construct-Insert Code Snippet DllMain,如下图所示;

此时,cvi会自动创建主函数DllMain,点击保存命名:保存源文件,头文件以及项目文件,并在源文件和头文件中加入ArrayFloor1d函数,如下图所示;Dll工程的.c代码如下所示:


#include <ansi_c.h>
#include <cvirte.h>
int __stdcall DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
if (InitCVIRTE (hinstDLL, 0, 0) == 0)
return 0; /* out of memory */
break;
case DLL_PROCESS_DETACH:
CloseCVIRTE ();
break;
}
return 1;
}
void __stdcall ArrayFloor1d(double *intput,int length,int *output)
{
int i ;
for (i=0;i<length ;i++)
{
output[i]=(int)(intput[i]*intput[i]);
}
}
对LabwindowsCVI Dll工程来说,需要配置IDE来告诉其哪些DLL函数是可以被外部程序加载和调用的,其步骤如下所示:1) 单击Build->Target Settings,2)在弹出的对话框中,在Exports方框中单击Chang. 3)在弹出的对话框中,选择要导出的DLL函数声明的头文件ArrayFloor.h并在Export what选择 Include file and marked symbols。4) 单OK按钮,完成配置。(注意:Labwindows2019只有32位,因此LabVIEW2019也要选择32位)。
1.2 编写LabVIEW程序
在前面板上编写程序:

通过外部编译器(例如Labwindows)将代码编译为动态链接库DLL文件后,在调用库函数对话框中指定该动态链接库的地址,选择函数名:

线程设置可以任意,调用规范必须设置为C。
在调用库函数“参数”选项卡中,“ArrayFloor1d”函数本身返回值为“void”,所以,其返回类型设置为空即可。对其它3个参数设置如下:input:该参数为指向“double”的指针类型,对应LabVIEW的一维数组。所以,“类型”设为“数组”;“维数”设为1;“数据类型”设为“8字节双精度”;“数组格式”设为“数组数据指针”;最小尺寸设为“<None>”;length:“类型”设为“数值”;“数据类型”设为“有符号32位整型”选项;“传递”设为“值”; output:该参数为指向“int”的指针类型,对应LabVIEW的一维数组。所以,“类型”设为“数组”;“维数”设为1;“数据类型”设为“有符号32位整型”;“数组格式”设为“数组数据指针”。如下所示:



配置好参数后,就需要要添加输入输出,由于Output用于得到函数汁算结果,因此输入时只需要输入一个常数初始化数组即可。运行程序,可以在前面板看到:

二、学以致用
上节我们已经介绍了如何利用LabWindows CVI编写DLL文件,以及LabVIEW如何调用DLL文件。本节我们对其学以致用,我们通过仿真信号函数来产生一个带白噪声的正弦信号,然后调用C语言写的一阶简单低通滤波算法来处理该信号。首先仿真信号函数在函数面板中的位置为:

我们在LabWindows CVI 2019中新建一个项目,编写一阶简单低通滤波算法的代码:
void __stdcall Filter(double *intput,int length,float coef,double *output)
{
int i;
for(i=0;i<length;i++)
{
if(i==0)
output[i]=intput[i];
output[i]=coef*output[i-1]+(1-coef)*intput[i];
}
}
然后生成目标DLL文件(生成DLL文件的步骤前面已经赘述了,下面就不在介绍):然后在labVIEW中新建一个空白 VI,编写如下代码:

然后在调用库函数对话框进行参数的配置:




这里需要格外注意:我在C语言的程序中对形参使用了double,int,float等类型的数据类型:它们在labVIEW中有相对应的数据类型:这个数据类型一定要配置正确,否则程序就会出错。配置完成以后,我们就可以运行程序,在前面板观察:我们可以看出通过调用DLL文件来滤波的效果和利用自带函数滤波的效果相差不大,这说明了调用DLL文件是一个可行的方案。

三、局限性
由于LabVIEW自身的一些特点,并非所有的DLL都能在LabVIEW中直接调用。遇到下列情形不能直接调用DLL。
A. LabVIEW以CLN方式调用DLL时只能使用导出函数,不允许使用导出变量。
B. LabVIEW目前仅支持有限的面向对象编程,无法直接使用导出类的DLL。
C. MFC扩展DLL是基于面向对象的语言的,LabVIEW无法直接使用。
D. 包含复杂数据结构,如链表或者需要动态分配内存的DLL函数。
E. 函数的返回值是复杂的数据结构。
四、结论
通过以上实例,由上面的例子可以看出,LabVIEW中调用动态连接库DLL文件中函数的编程并不复杂,关键是要知道被调用函数的名称,并且保证输入、输出参数的顺序及数据类型要配置正确即可。我们可以也看出LabVIEW可以方便地调用各种编译软件生成的DLL文件,这样,用户在编写大型项目时更加灵活,也为熟悉C语言的工程师提供了巨大的方便。