6调用文本编程语言创建的代码
6.1.概述
本章主要叙述在LabVIEW中如何调用利用传统的基于文本的编程工具创建的代码.
通过学习本章您将了解以下知识:
z利用Code Interface Node将C语言创建的代码集成到LabVIEW项目中;
z利用Call Library Function Node调用动态链接库。
在用LabVIEW开发大型的项目的过程中,尽管它能给开发者提供快速的解决方案,但是有时候传统的基于文本的开发工具在实现某些功能时相对可能容易些(如开发对运行时间要求很苛刻的程序),或者有些任务不能通过调用LabVIEW的函数来直接实现(如操作系统API的某些功能)。这个时候就可以考虑使用Code Interface Node (CIN)或者Call Library Function Node来调用基于文本的开发工具开发的代码。通常来说在大型的项目开发过程中这样做的目的主要有以下几个方面:
z代码的复用。对一个项目开发团队来说,整个团队使用的开发工具可能不只是一种。从横向来看,团队中负责各子系统的开发人员可能使用的开发工具不尽相同,, 从纵向来看,整个团队多年来可能已经换过
多种不同的开发工具。为了能减少重复工作,共享代码或重复利用以前的代码,可以用CIN 将C代码或者用Call Library Function Node将其它工具创建的DLL集成到LabVIEW项目中来。
z项目的开发效率。虽然用LabVIEW为项目提供解决方案,其效率相对于基于文本的传统开发工具大大提高,但是有些时候用传统的开发工具实现某些功能却比LabVIEW来的容易。例如开发与底层硬件交互或者开发对运行时间要求很苛刻的程序时,VC可能就比LabVIEW来得方便。或者开发者需要某种特殊的算法,而且这种算法用传统的开发工具实现要比LabVIEW开发容易些(如图像处理的一些算法等)。这时开发者就可以用CIN或者Call Library Function Node把传统开发工具的长处和LabVIEW的长处结合在一起,共同为项目提供解决方案。
z LabVIEW不能胜任的工作。LabVIEW提供了很多函数和开发的toolkit,但是这并不意味着LabVIEW可以完成任何事情。例如操作系统API提供的某些功能,LabVIEW的函数库中就没有提供。那么开发者就可以用CIN或者Call Library Function Node来扩展LabVIEW为项目提供方案的能力。
值得注意的是,在LabVIEW项目执行调用的外部代码时,执行的线程将被占用,直到执行节点返回为止。也就是说如果线程正在执行外部代码,那么它将不会处理其它任务,当然用户也将不能中断此执行过程。那么开发人员在将外部代码集成到项目中时,如果代码如果完成的任务执行时间较长,就一定要慎重处理了。
6.2.用CIN调用C代码
Code Interface Node (CIN)可以被看作是LabVIEW用来扩展自身开发能力的一种方法,它通过将VC++或Symantec C(在Linux平台上可以是gcc)编写的代码集成到VI中来扩展LabVIEW自身能力的不足。与调用DLL不同的是,CIN可以将外部的代码与VI集成在一起,一旦编译成功后就可随VI一起分发,不需要原来的源文件或者其它文件来支持其运行。从运行的效率而言,DLL和CIN相同。
在LabVIEW项目中使用CIN,一般通过以下途径:
1. 指定接口的输入输出参数的类型传递方式;
2. 创建.C代码的框架并完成代码;
3. 编译代码为LabVIEW可以识别的格式(.lsb格式)
4. 加载CIN目标代码
以下章节用实际例子对其逐步详细说明。为了把重点放在CIN调用步骤的说明上,该例子只简单完成两个数的求和的运算。
6.2.1.指定接口的输入输出参数的类型和传递方式
首先,在Function ->Connectivity->Libraries & Executables中(如图 6-1)选取Code Interface Node 放在Diagram上。默认情况下,CIN节点只有一个输入端口和一个输出端口,用户可以通过用鼠标拖动图标的边框,或者通过选择节点端口右键菜单中的Add Parameters/Remove Parameters来增加/删除参数。但是增加的参数是成对出现的。每增加一个输入(或输出)端口,都会有一个与之相对应的输出(或输入)端口出现。
图 6-2 CIN节点在LabVIEW8 函数面板中的位置 图 6-3 CIN的输入输出参数
输入输出参数的数据类型由与之连接的Control或Indicator决定。也就是说输入参数的类型取决于与其连接Control的数据类型,输出参数的类型取决于与其连接的Indicator的类型。
CIN的参数传递方式可以分为:Input-Output和Output Only两种类型。不同的连接方式表示了不同的参数传递方式。
默认情况下,LabVIEW中CIN节点的参数传递方式为“Input-Output”(传递指向参数的指针),节点左边连
接输入参数,右边连接输出参数。例如图 6-3 a)中所示,连接一个32位整型Control作为输入参数,连接一个32位的整型Indicator作为输出参数。在VI调用CIN的时候,LabVIEW只将输入参数的指针传递给CIN目标代码,CIN代码执行完毕后,LabVIEW会将输入参数指针指向的值传递给输出Indicator。在这种情况下,LabVIEW认为CIN代码可以修改连接到输入端Control的值。此时就要注意,如果VI中有其它地方也需要调用CIN前输入Control中的值作为参数,那么必须在调用CIN前copy输入Control的值,否则就有可能出错。
在参数传递时,也可以只在输入端连接Control,而使输出端悬空。例如图 6-3 b)中所示,连接一个32位整型Control作为输入参数,而输出端悬空。这时LabVIEW会认为CIN不会修改传递给它参数的值。如果VI中有其它地方也需要调用CIN前输入Control中的值作为参数,就不必在调用CIN前copy输入Control 的值了。当然必须确保在CIN代码中不能修改参数的值,如果用户非要更改参数的值,那么更改后的值将在输入Control中显示。
如果用户只想用一对连接端子连接输出参数,就可以将参数传递方式设置为Output Only类型。可以通过选择端子右键菜单中的Output Only将参数传递类型设置为Output Only类型。设置成功后端子对应得输入端就会变成灰(图 6-3 c)。对于Output Only类型的参数,LabVIEW会为其分配专门的空间来存放返回值,然后将指向分配空间的指针传递给CIN,一旦CIN执行完成,就会按照与其连接的Indicator数据类型将返回值显示在出来。但是在某些情况下,可能会将同一个输出连接到多个具有不同数据类型的Ind
icator上(图 6-3 d),这时对LabVIEW 来说就有可能出现判断数据类型错误的情况。为了解决此问题,可以将一个Control 连接到与输出对应得输入端子上,输出端子将会引用该Control的数据类型(图 6-3 d)。
对于求和运算的例子来说,我们指定两个8位的整型量作为输入参数,指定一个8位的整型量作为输出参数,结果如下:
图 6-4 Sum=A+B的CIN参数
6.2.2.创建.C文件框架并完成代码
为CIN节点指定了输入输出参数后,可以通过选择节点右键菜单中的Create .c File生成CIN源代码的模版。用户在生成的模版中添加CIN要完成功能的代码。
为求和运算例子创建的源代码如下:
/* CIN source file */
#include "extcode.h"
MgErr CINRun(int8 *A, int8 *B, int8 *Sum);
MgErr CINRun(int8 *A, int8 *B, int8 *Sum)
c语言编译器ide代码编辑{
/* Insert code here */
return noErr;
}
模版会自动包含LabVIEW程序目录下Cintools目录中的extcode.件,这个文件不仅定义了CIN使用的基本数据类型和函数原型,还定义了可能与系统头文件中定义有冲突的一些常量。Cintools目录中还有一个hosttype.件,此文件用于解析系统头文件和extcode.h之间的差异,同时也包含了给定平台的通用头文件。
始终在.C源文件的起始位置包含extcode.件,如果代码对系统进行了调用,则一般应该在extcode.h
文件后立刻包含hosttype.件,然后再将系统的头文件包含进来。对给定的系统来说,hosttype.h只包含了部分头文件,如果用户需要的系统头文件没有包含在内,则可以在它之后包含需要的头文件。
在生成的C模版文件中,除CINRun必须存在外,还有其它7个用于维护现场的函数可选则使用:CINLoad, CINSave, CINUnload, CINAbort, CINInit, CINDispose, and CINProperties。LabVIEW在运行到CIN节点时会调用调用CINRun函数,CINRun函数会接收到输入输出参数。7个用于清理现场的函数只有在特定的情况下才会被调用。例如,LabVIEW在第一次加载vi时会调用CINLoad函数,如果用户要在第一次加载vi时完成某种特殊的任务,就可以在CINLoad函数中添加相应的代码。下面代码给出了一个在CINLoad中添加代码的模版:
CIN MgErr CINLoad(RsrcFile reserved) {
Unused (reserved);
/* Insert code here */
return noErr;
}
一般说来,在C源代码文件中只需要编写CINRun函数九可以了,只有在某些特殊情况(如完成某些初始化,预分配空间或者维护交叉调用的信息)下才调用现场维护的函数。
对于两个数求和的例子来说,我们可以在CINRun函数的/* Insert code here */ 处添加下句A和B求和的代码如下:
/* CIN source file */
#include "extcode.h"
MgErr CINRun(int8 *A, int8 *B, int8 *Sum);
MgErr CINRun(int8 *A, int8 *B, int8 *Sum)
{
/* Insert code here */
*Sum = *A + *B;
noErr;
return
}
6.2.3.编译代码为LabVIEW可以识别的.lsb格式
完成了代码的编写后就需要将代码编译成LabVIEW可识别的.lsb格式。LabVIEW支持不同平台上的编译器(Windows上的VC++,Symantec C,Linux的gcc,以及Mac上的xCode)编译CIN。开发平台和编译器不同编译的方法也不同。对于Linux和Mac平台上CIN的编译,用户可以参考LabVIEW的操作手册,这里只对在Windows平台上用VC来编译CIN的方法做详细讨论。
CIN的编译其实并不复杂,但是NI在LabVIEW的手册中提供的编译方法(特别是基于Makefile的编译方法)并不是很完美,这使很多同仁几乎为此忙到崩溃(我曾经在论坛中见到好多朋友为此花了大量的时间来求救)。下面提供两种在Win32平台下使用VC++6来的编译的CIN的方法:Makefile方法和VC++ IDE方法。
Makefile方法
1.在C源文件的目录中创建一个与C源文件同名且后缀名为.mak的文件(如add.mak)其中包含以下
内容:
name = C源文件去掉后缀的部分
type = CIN
cinlibraries = Kernel32.lib
CINTOOLSDIR=Cintools目录的路径
!include <$(CINTOOLSDIR)\ntlvsb.mak>
例如为两个数求和的例子创建的add.mak文件如下:
name = add
type = CIN
cinlibraries = Kernel32.lib
CINTOOLSDIR=d:\cintools
!include <$(CINTOOLSDIR)\ntlvsb.mak>
文件中“CINTOOLSDIR=CIN工具所在目录”是指向LabVIEW安装目录中Cintools目录的路径。但是由于编译器不识别长文件名,所以此处的路径比须是DOS操作系统的路径名(即目录和文件名8字符,后缀名3字符的格式),否则编译器将不能识别。建议将整个Cintools目录copy到一个容易用DOS命名方式表
达的路径下使用,如d:\cintools。
此时将会跳出询问是否生成新的project来包装makefile和询问工作平台的对话框(图 6-5和图6-6)选择Yes和OK.
图 6-5 包装makefile的对话框
3.保存Project并选择Build就会生成需要的.lsb文件
图 6-6 为包装的项目选择平台
VC++ IDE方法
使用VC++ IDE编译.lsb的方法可以按照下面步骤来完成。
1.创建新的DLL Project。选择File -> New…选择Win32 Dynamic-Link Library作为要创建项目的类型,并为项目命名(图 6-7),选OK后再选择An Empty DLL Project,然后生成一个dll项目;
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论