2011年1月26日,第一稿
2011年7月22日,第二稿
2011年7月22日,第二稿
5.3 控制程序流程——定序控制
依靠运算表达式和关系运算符以及逻辑运算符来控制程序的流程显然是不够的,所以图形化语言与其它基于文本的语言一样支持多种程序结构,比如条件控制结构和循环控制结构等。当然,它还具备一些图形化语言所特有的程序流程控制结构,比如顺序结构、带有移位寄存器的循环等等。这些结构的引入都是为实现数据流编程的特殊需要。
基于文本的语言程序是依据控制流来运行的,控制流基本上是依据文本语言的书写顺序来实现程序的执行流程。而图形化语言则不同,它的运行机制是基于数据流的。节点必须在所有的数据输入都有效时才会执行(也称为数据的相关性)。算术表达式依赖于节点间的连线实现数据相关的数据流控制作用。可是,有时侯数据相关性并不存在(或者不需要这种数据相关性存在),我们期待程序是一步一步的按顺序执行(定序执行),而不是按数据流关系执行。为了应对这种特殊的需要,LabVIEW提供了几种解决方法。
基于文本的语言程序是依据控制流来运行的,控制流基本上是依据文本语言的书写顺序来实现程序的执行流程。而图形化语言则不同,它的运行机制是基于数据流的。节点必须在所有的数据输入都有效时才会执行(也称为数据的相关性)。算术表达式依赖于节点间的连线实现数据相关的数据流控制作用。可是,有时侯数据相关性并不存在(或者不需要这种数据相关性存在),我们期待程序是一步一步的按顺序执行(定序执行),而不是按数据流关系执行。为了应对这种特殊的需要,LabVIEW提供了几种解决方法。
5.3.1 平铺式顺序结构
平铺式顺序结构将程序分割成许多块(子框图),这种平铺式顺序结构借助于电影胶片中帧的表现手法,将块与块之间表现为不同帧的连接。
这种平铺顺序结构把程序内容分成一帧一帧,程序执行时是顺序执行,从而实现了数据流程序的强制定序运行。这种平铺顺序结构的数据流特点被称为:强制数据流关系。下面我们来看一个具体的例子。
例 5-9 计算VI的执行时间
使用过电子秒表的朋友都知道,启动和停止之间的时间间隔就是被测时间间隔。这个测量过程就是一个定序的测量过程。计算VI的执行时间也是基于这样的过程。参见下图。
例 5-9 计算VI的执行时间
使用过电子秒表的朋友都知道,启动和停止之间的时间间隔就是被测时间间隔。这个测量过程就是一个定序的测量过程。计算VI的执行时间也是基于这样的过程。参见下图。
这里用了两个“时间计数器”一个做启动测量的开关(第一帧),另一个做结束测量的开关(第三帧)。第二帧中我们用一个1s的时间延迟Express VI。程序运行后在“VI运行时间”显示控件中会看到1000的值(ms)。请注意:测量结果的末位,可能会有正、负一个数的误差,这是数字化测量的基本误差。
如果没有采用平铺式顺序结构——这种强制数据流运行关系,程序运行1s后停下来,测量结果为:0(ms)。参见下图。
如果没有采用平铺式顺序结构——这种强制数据流运行关系,程序运行1s后停下来,测量结果为:0(ms)。参见下图。
平铺式顺序结构在许多地方都用得到。比如在仪器控制中,许多控制步骤是需要分步执行的;有些显示控件往往需要在显示之初进行清除显示内容等等。
平铺顺序结构的优点是:程序代码直观、清晰且便于理解。但也存在一定的问题:当程序中所需的定序代码较多时,依据图形化的特点,必然占据巨大的屏幕空间从而导致程序的可读性下降。
为了解决这样的问题,LabVIEW还提供的另一种形式的定序结构——层叠式顺序结构。
平铺顺序结构的优点是:程序代码直观、清晰且便于理解。但也存在一定的问题:当程序中所需的定序代码较多时,依据图形化的特点,必然占据巨大的屏幕空间从而导致程序的可读性下降。
为了解决这样的问题,LabVIEW还提供的另一种形式的定序结构——层叠式顺序结构。
5.3.2 层叠式顺序结构
顾名思义,将平铺顺序结构叠放起来就是层叠式顺序结构。这种转换可以直接进行,具体操作是:鼠标右键单击平铺顺序结构的边框,在弹出的快捷菜单中选择“替换为层叠式顺序”即可,参见下图。
替换后的层叠式顺序结构如下图所示。
上图中,我们看到平铺式顺序结构已经被层叠式顺序结构替换,替换的结果是我们只能看到其中一帧的内容,其它帧的内容被叠放在一起。在选择器标签中,我们看到目前显示的是第0帧内容,共有[0..2]三帧(0、1、2)。
其它两帧的内容显示如下:
其它两帧的内容显示如下:
叠层顺序结构似乎只有一个优点,程序结构简单、清晰(程序内容并不清晰)、占用屏幕空间小。
可是叠层顺序结构的缺点可是不少:
平铺式顺序结构没有这个问题。
注意:Case结构也存在相同的问题。
平铺式顺序结构没有这个问题。
平铺式顺序结构没有这个问题。
上面列举了层叠式顺序结构的一些缺点,正是因为这些缺点以至于好多有关LabVIEW的书籍都发出了这样的警句“慎用顺序结构”。这里面包含了两个意思:
除此之外,还有没有更简单、更直观的方法呢?
可是叠层顺序结构的缺点可是不少:
- 隐藏了程序的某些部分
平铺式顺序结构没有这个问题。
注意:Case结构也存在相同的问题。
- 影响从左到右的可视流习惯
平铺式顺序结构没有这个问题。
- 数据流中断,破坏了数据流所倡导的并行性
- 层叠顺序结构的局部变量可能导致程序的可读性进一步下降甚至发生错误
平铺式顺序结构没有这个问题。
上面列举了层叠式顺序结构的一些缺点,正是因为这些缺点以至于好多有关LabVIEW的书籍都发出了这样的警句“慎用顺序结构”。这里面包含了两个意思:
- 顺序结构使用强制数据流运行机制,破坏了数据流编程的并行性
- 层叠式顺序局部变量会导致错误发生或程序的可读性下降
除此之外,还有没有更简单、更直观的方法呢?
5.3.3 利用公共线程
算术表达式是利用数据相关性(数据从属)来实现的数据流运行机制。因为运算符本身就具备了这种数据的相关性。可是VI之间就很难保证具备这种数据相关性,那么VI间如何实现数据流编程呢?
回顾我们在子VI的设计中,曾经为每个子VI都创建了输入错误簇和输出错误簇。这实际上就是一对数据流公共线程,利用这对错误簇我们就可以建立VI间的数据从属关系。从而实现了数据流下的定序运行。
例 5-10 计算VI的执行时间
在例5-9中,我们利用平铺式顺序结构实现了VI运行时间的计算,现在我们换另一种方式来实现,参见下图。
回顾我们在子VI的设计中,曾经为每个子VI都创建了输入错误簇和输出错误簇。这实际上就是一对数据流公共线程,利用这对错误簇我们就可以建立VI间的数据从属关系。从而实现了数据流下的定序运行。
例 5-10 计算VI的执行时间
在例5-9中,我们利用平铺式顺序结构实现了VI运行时间的计算,现在我们换另一种方式来实现,参见下图。
这里面所用的函数功能与例5-9相同,不同的是时间计数器函数(VI)的背景色是绿色的,其实它是一个VI,是OpeG组织设计开发的自由图形化源代码。
下面我们就来看看OpenG的时间计数器的图形化代码。参见下图。
下面我们就来看看OpenG的时间计数器的图形化代码。参见下图。
它的程序代码仅仅是在时间计数器函数下附加了一个错误簇,这样就可以实现定序数据流的编程。显然,使用这种方法比平铺式顺序结构要简单的多。在许多场合下,错误簇就是实现定序数据流的最佳方法。
现在我们再通过一个具体的例子来看看数据流编程的基本处理方法:
例 5-11 打开文件读出内容并显示
这是一个很实用也很简单的读文件的操作,我们很容易写出如下图所示的程序代码。
现在我们再通过一个具体的例子来看看数据流编程的基本处理方法:
例 5-11 打开文件读出内容并显示
这是一个很实用也很简单的读文件的操作,我们很容易写出如下图所示的程序代码。
这个程序能够正常工作吗?从逻辑关系上看,它是可以工作的。因为它完成了整个程序的所有步骤,并满足打开文件后必须关闭的基本原则(这也是一再强调的)。可是从数据流的观点来看似乎还存在着问题,因为这里不恰当的使用了数据流。问题是:我们能够确保文件读完后才进行关闭的操作吗?显然如果文件的内容很多时是无法保证这一点的。因为读文件和关闭文件是同时进行的。
用顺序结构解决问题的方法参见下图。
用顺序结构解决问题的方法参见下图。
利用人为数据关系同样也可以解决这个问题。参见下图。
利用错误簇会更好。参见下图。
其实这里是用错误簇与refrum相配合实现的数据流的关系。同样LabVIEW中还有许多类似的公共线程对。比如DAQmx、GPIB、VISA、文件I/O等。
DAQmx Base
DAQmx Base
这是Mac版的LabVIEW 8.6(使用DAQmx Base版驱动)所提供的一个用声卡采集数据进行功率谱分析的例子,从这个例子可以看出 task ID和错误簇构成一对公共线程来控制程序执行顺序(满足数据流的要求)。而While循环中下部所显示的数据分析处理部分,则完全是按照数据从属的关系来进行的。
VISA(GPIB、串口)公共线程
VISA(GPIB、串口)公共线程
仪器控制程序的公共线程,仍采用NI提供的例子来展示仪器控制公共线程的使用。同样它来自LabVIEW 2010(Mac版)。
这里 VISA GPIB Resource 和错误簇构成一对公共线程来控制程序的执行顺序。注意这里的属性节点也通过公共线程控制,这是非常正确的用法,应该有这个良好使用习惯。
文件I/O的公共线程
这里 VISA GPIB Resource 和错误簇构成一对公共线程来控制程序的执行顺序。注意这里的属性节点也通过公共线程控制,这是非常正确的用法,应该有这个良好使用习惯。
文件I/O的公共线程
文件I/O程序的公共线程,仍采用NI提供“读配置文件”的例子来展示文件I/O公共线程的使用。LabVIEW 2010(Mac版)。
同样refnum和错误簇构成一对公共线程来控制程序的执行顺序。
属性(方法)节点的公共线程
同样refnum和错误簇构成一对公共线程来控制程序的执行顺序。
属性(方法)节点的公共线程
DAQmx的公共线程
注意图中顺序结构的用法。这个例子使用LabVIEW Windows版。
认真品读这些例子会对数据流编程有一个基本的认识和了解,更重要的是建立、习惯这种数据流的编程思想。
认真品读这些例子会对数据流编程有一个基本的认识和了解,更重要的是建立、习惯这种数据流的编程思想。





















