
1.3 VI的开发与调试步骤
虚拟仪器开发平台搭建完成后,即可运行LabVIEW来开发实现各种功能的VI。本节将通过开发一个“判断数字量是否在某一范围内”的简单实例来说明VI的开发调试过程。包括需求分析、前/后面板设计、定义子VI、运行调试及错误捕获等。由于重在说明开发流程,就省略了较为易上手的LabVIEW基本操作讲解。若读者是第一次接触LabVIEW,可以先花1~2小时学习LabVIEW的入门课程,相关教学视频可在NI官方网站或本书的支持网站https://www.mviacademy.com免费获得。
假定我们要完成一个VI,用于判断某种外部输入的实数量(如某种产品的输出电压、电流)是否在一个预先给定标称值的±10%范围内。
1.需求分析
从数据结构和算法两方面分析以上需求:
(1)数据类型和数据操作:
VI要求输入的实数量和标称值均应为浮点数值量,需要对这些数据进行算术运算操作;
VI输出结果只有两种可能(在范围内和不在范围内),因此为布尔量,需要进行逻辑比较运算操作。
(2)算法:
● 通过用户界面获得输入的数字量和标称值;
● 通过计算“标称值±标称值×10%”获得范围的上下限;
● 如果“输入的数字量≥下限”并且“输入的数字量≤下限”,则表示输入数字量在范围内;
● 显示给用户输入量是否在范围内的判断结果。
2.前面板设计
前面板是VI的人机界面,创建VI时,通常应先设计前面板,然后再设计程序框图。用户可以在前面板设置输入数值并观察VI的输出。输入量可以通过操作输入控件(Control)完成,程序的输出可以通过显示控件(Indicator)显示给用户。输入控件和显示控件以各种图形出现在前面板上,如旋钮、开关、按钮、图表、图形等,这使得前面板非常直观、易懂。LabVIEW控件面板中提供了各种丰富的控件(在前面板右击会弹出控件面板,如图1-13所示),开发者可以直接从控件面板中选择需要的控件放入前面板来构建用户界面。选择的控件可以通过右键菜单选项在输入控件和显示控件属性之间转换,以改变组件的输入/输出属性。

图1-13 VI前面板和LabVIEW控件面板
根据需求分析,用户前面板上应包含2个输入控件(输入量和标称量)和一个显示控件(显示输入量是否在范围内)。通过从控件面板中选择两个双精度类型的数字控件(Double Numeric Control)和一个方形LED (Square LED)作为显示控件,并修改其标签(Label)后,得到如图1-13所示前面板。
3.后面板设计
每一个VI前面板都对应一个编辑实现程序功能的G语言面板(通常称后面板)。从控件选择面板上选择一个控件并放置在前面板上,LabVIEW会自动在后面板上生成与之对应的图标,显示其对应的数据类型。前面板上用户的输入数据经过输入控件对应的图标传送至LabVIEW后面板。这样开发人员就可以在后面板中设计图形化的程序,实现各种功能,然后再将处理结果由输出控件对应的图标返回到前面板中。后面板中的图形化语言程序框图可理解为传统程序的源代码,图1-14显示了一个VI前、后面板之间的数据传递示意图。
G语言程序由程序结构框图(Structure)、节点(Node)、输入/输出端子(Terminal)和连线(Wiring)构成。其中程序结构框图(如循环、分支等)用来实现结构化程序控制命令,节点被用来实现各种功能函数和子VI调用,输入/输出端子被用来同前面板的控件和显示控件传递数据,而连线则代表程序执行过程中的数据流,定义了框图内的数据流动方向。
LabVIEW含有大量丰富的内置函数库(在后面板右击弹出函数库,见图1-15),开发者可以直接从函数库中选择需要的函数放入后面板,这些函数以各种直观的图标节点形式出现在后面板上。随后通过工具盒中的连线工具连接各功能节点的输入/输出端子,并在程序结构框图的控制下以数据流驱动的方式实现各种复杂的功能。根据前述需求分析中的算法,选择相关函数并连线后创建的程序如图1-15所示。

图1-14 VI前、后面板之间的数据传递

图1-15 VI后面板和LabVIEW函数库
4.定义VI为子VI(subVI)
从功能角度来看,前面板和后面板代码设计完成后,VI设计就已经完成。然而在实际工作中,VI不仅可作为独立的应用程序,还可以被定义为程序中的一项常用操作,当作子VI(一个VI被其他VI在程序框图中调用,则称该VI为子VI)来使用。被定义为子VI的程序在运行时通常并不显示其前面板,而往往是被当作函数在主VI中调用。子VI既可有效提高程序的模块化程度和代码重用率,还可使VI后面板的图形代码更整洁易读。
定义子VI一般可通过三步完成:
(1)定义VI输入/输出参数。
(2)为VI创建图标。
(3)为VI添加文档说明。
要将VI定义为子VI,首先需要使用连线工具为VI定义输入/输出端子。在VI前面板右上角图标的右键菜单中选择显示“连线板”选项,再通过选择连线的模式确定输入/输出端子数量(图1-4中VI前面板右上角图标),最后使用连线工具将前面板相应的输入控件与显示控件分别分配至连线板上的输入/输出连线端子,即可完成子VI输入/输出参数定义。LabVIEW连线板中最多可设置28个接线端。笔者在选择连线板时通常遵循以下两个原则:
(1)选择既能满足当前端子需求数量,又能保留部分裕量的组合模式,但一般选择接线端总数不超过16个的接线板。
(2)如果连接的参数较多,尽量使用簇对参数打包,然后将该簇分配至连线板上的一个接线端。
除了定义端子,还应为VI定义一个形象的图标(在VI前面板右上角图标的右键菜单中选择图标编辑器)。当设计的VI作为子VI被主VI调用时,定义好的图标就会作为代表该子VI的功能节点,出现在主VI的后面板中,为子VI定义的输入/输出端子也将整合在图标周围,以便与其他功能模块或数据进行连接。和G语言一样,一个形象的图标可以有效增强程序的可读性。图1-16是调用子VI的例子。

图1-16 调用子VI的程序框图
在实际工作中,为每个VI从头设计图标往往要花费大量时间,较为有效的做法是将常用的一些图标进行整理,或者从网上下载常用的图标汇总在一起作为开发资源。这些资源不仅能缩短开发时间,同时在团队工作时,还能规范并提高开发的标准化程度。
最后,也是最为重要的一步,就是为VI添加文档说明。很多开发人员在项目之初并不重视文档编写,往往在项目完成后才从头为开发的VI或subVI添加说明,优秀的开发人员应避免这种陋习。试想一下,若开发一个大型、复杂、工期较长的项目,等到项目交付时,可能根本记不起来为什么要这样设计VI。另外一种可能就是项目工期非常紧张,到最后迫于客户的压力,可能根本没时间为之前设计的VI创建说明,就要将设计交付给客户。当客户验收时发现缺少VI文档,可能会拒绝付款。最糟糕的情况是若干年后接到客户升级系统的订单时,由于缺少文档,可能连开发人员自己都已经读不懂程序了。因此,从整个项目生命周期(包含后期升级和维护)来看,养成从一开始就为VI添加说明文档的好习惯,总体上反而能有效缩短项目的开发和升级维护工期。另外,若一开始就为每个VI添加说明文档,可利用LabVIEW的文档生成工具,自动生成整个项目的说明文档及帮助文档。
要为VI添加文档,可在VI前面板右上角图标处右击,在弹出的菜单中选择VI属性选项,再从分类中选择文档,就可以在VI描述文本框中为其添加说明(图1-17)。

图1-17 为VI添加说明
5.运行调试
完成以上工作后,就可以对VI进行调试和运行了(选择前面板或后面板工具栏的按钮即可)。
如果VI存在语法错误,则面板工具条上的运行按钮将会变成一个折断的箭头,表示程序不能被执行。这时该按钮被称作错误列表,单击则LabVIEW弹出错误清单窗口,单击其中任何一个列出的错误,选用Find功能,则出错的对象或端口会变成高亮。
在LabVIEW的工具条上有一个“高亮执行”(Highlight Execution)按钮,使其变成高亮形式
,运行程序,VI代码就以较慢的、可见的速度运行,没有被执行的代码灰色显示,执行后的代码高亮显示,并显示数据流向和连线上的数据值。这样就可以根据数据流动状态跟踪程序的执行。
为了查找程序中的逻辑错误,有时候希望框图程序逐节点执行。使用断点工具可以在程序的某一点中止程序执行,用探针或者单步方式查看数据。使用断点工具时,单击希望设置或者清除断点的位置。断点的显示对于节点或者图框表示为红框,对于连线表示为红点。当VI程序运行到断点设置处,程序暂停在将要执行的节点处,以闪烁表示。按下“单步执行”按钮,闪烁的节点被执行,下一个将要执行的节点变为闪烁,表示将要被执行。用户也可以单击“暂停”按钮,这样程序将连续执行直到下一个断点。
也可以用探针工具查看当框图程序流经某一根连接线时的数据值。从工具盒选择探针工具(Probe),再单击希望放置探针的连接线(或在连线上右击,在弹出的菜单中选择设置断点)。这时显示器上会出现一个探针显示窗口。该窗口总是被显示在前面板窗口或框图窗口的上面。图1-18给出了设置了断点、探针并打开高亮执行时的VI后面板示例。

图1-18 设置了断点、探针并打开高亮执行时的VI后面板
6.错误处理
单独从这个例子来说,完成前面几步已经似乎已经完成了VI的开发。然而现实世界非如此简单,无论开发人员如何细心,测试验证过程如何仔细,程序还是难免有bug。另外,一个程序在运行时总会有这样那样与设计时不一致的情况发生。例如程序要求打开的串口已经被其他进程占用,需要与之通信的设备由于某种原因死机等。如果没有在程序中采取有效的错误捕获、处理措施,就会导致程序异常或者至少降低程序的响应。因此在设计过程中,必须采取有效的错误处理措施,保证程序健壮、可用。
考虑前面的例子,你可能觉得这个VI简单到根本无须增加任何错误处理,但是还是有改进的地方。如果考虑这个VI被其他复杂的主VI调用,那么当主VI中出现错位时,利用错误状态的传递,就可以通过出现错误时不执行代码来提高整个应用的响应速度(图1-19)。

图1-19 有错误处理能力的VI后面板
通过这个简单例子,读者还不能体会这种错误处理的实际意义,随着开发项目的复杂程度越来越高,程序中对错误进行处理的优越性会自然而然体现出来。鉴于错误处理措施可以保证程序健壮性并有效地提高程序可用性,因此将在第6章中专门讨论有关错误处理的方法。