循环结构

    LabVIEW中的循环结构有 for 循环和 while 循环。其功能与文本语言的循环结构的功能类似类似,可以控制循环体内的代码执行多次。

一、for 循环

    但是 LabVIEW 中的 for 循环的限制更多一些。
    1. For 循环的迭代器只能从 0 开始,并且每次只能增加 1。
    2. For 循环不能中途中断退出。C 语言里有 break 语句,但在 LabVIEW 中不要试图中间停止 for 循环。

    外部数据进入循环体是通过隧道进入的,有几种方式:


图1:For 循环结构上的隧道

    图 1 所示的 For 循环结构演示了三种隧道结构,就是在 For 循环结构左右边框上用于数据输入输出的节点。这三种隧道从上至下分别是:索引隧道、移位寄存器(shift register)、一般隧道。

    一般隧道,就是把数据传入传出循环结构。数据的类型和值在传入传出循环结构前后不发生变化。   
    索引隧道是 LabVIEW 的一种独特功能。一个循环外的数组通过索引隧道连接到循环结构上,隧道在循环内一侧会自动取出数组的元素,依顺序每次循环取出一个元素。用索引隧道传出数据,可以自动把循环内的数据组织成数组。

    通过移位寄存器传入传出数据,也是数据的类型和值都不会发生变化。移位寄存器的特殊之处在于在循环结构两端的接线端是强制使用同一内存的。因此,上一次迭代执行产生的某一值,传给移位寄存器右侧的接线端,如果下一次迭代运行需要用到这个数据,从移位寄存器左侧的接线端引出就可以了。
  
C 语言程序员初学 LabVIEW,在使用循环结构时,常常为创建一个中间变量烦恼。为循环中的变量创建一个 Local Variable 不是好的方法。我们应当时刻记得 LabVIEW 与一般文本语言不同,LabVIEW 的数据不是保存在显示的变量里,而是在连线上流动的。LabVIEW 是通过移位寄存器把数据从一次循环传递到下一次的。


图2:反馈节点

    如果单纯是为了让下一次迭代使用上次迭代的数据,也可以使用反馈节点,如图2所示。

    移位寄存器左侧的接线端可以不只有一个,用鼠标可以把左侧的接线端拉出多个来,如图3所示。下面的接线端可以记录上两次、三次……的数据。


图3:多接线端移位寄存器

    使用数组的隧道有一些需要注意的事项,参考:LabVIEW 代码中常见的错误

    从 LabVIEW 8.5 开始,for 循环增加了结束判断条件。for 循环也可以像 while 循环那样随时结束运行。

二、While 循环

    LabVIEW 的 While 循环相当于文本语言中的 do… while… 循环。有些语言还有 while… do… 循环,LabVIEW 没有这样的循环。LabVIEW 的 while 循环至少要运行一次。
    for 循环中可以用的数据传递方式,几种隧道也都可以在 while 循环中使用。所以在很多情况下,while 循环可以替代 for 循环。

    While 循环比 for 循环(LV 8.5 之前)灵活的地方是可以进入循环后在决定何时循环结束。比如,希望当某一变量大于一个值时停止循环,这种情况下不能预知循环次数,所以一定要使用 while 循环。
    while 循环也有不利的方面:
    首先,for 循环更利于阅读。读者一眼就可以看出程序会内运行多少次。
    其次,while 循环也可以使用带索引的隧道来构造数组,但是它的效率低于 for 循环。


图4:使用循环构造数组

    如图4,用两种循环所产生的数组大小是相同的。但是如果使用的是 for 循环,LabVIEW 在循环运行之前,就已经知道数组的大小是100,因此 LabVIEW 可以一次为 Array1 分配一个大小为 100 的内存空间。但是对于 while 循环,由于循环次数不能在循环运行前确定,LabVIEW 无法一次就为 Array2 分配合适的内存空间。LabVIEW 会在 while 循环的过程中不断调整 Array2 内存空间的大小,因此效率较低。
    所以,在可以确定次数的情形下,最好使用 for 循环。

三、移位寄存器

    移位寄存器除了在迭代间传递局部数据,还有其他一些功能。

    首先,移位寄存器可以用于程序的内存优化。
    由于移位寄存器的左右接线段使用的是同一块缓存,可以利用这一特性,显示的告诉 LabVIEW 重用某些数据的内存,并且不对数据做额外的拷贝。详细说明可以参考:LabVIEW 程序的内存优化

    移位寄存器还经常被当作全局变量来使用,比如 LabVIEW 程序中常见的功能全局变量


《我和LabVIEW》目录

事件结构

阮奇桢

    Event Structure 也是一种选择结构,程序根据发生的事件决定执行哪一个页面的程序。此时,LabVIEW 的界面编写与 Visual Basic 的界面程序有些类似。

一. 按照产出源来区分事件的种类

    按照事件的产生源来区分,LabVIEW有以下几种事件:


图1:配置事件

    1. 应用程序事件(<Application>),这类事件主要反映整个应用程序状态的变化,例如:程序是否关闭,是否超时等。
    2. VI事件(<This VI>),这类事件反映当前VI状态的改变。例如:当前VI是否被关闭,是否选择了菜单中的某一项等等。
    3. 动态事件(Dynamic),用于处理用户自己定义的或在程序中临时生成的事件。
    4. 区域事件(Pane)和分割线事件(Splitter)是LabVIEW 8中新添加的特性。LabVIEW 8中,用户可以把一个VI的前面板分割成几份,这两类事件用来处理用户对某个区域或区域分割线的状态的改变。


图2:面板上划分区域

    5. 控件事件(Control)是最常用的一种事件,用于处理某个控件状态的改变。例如,控件值的改变,或者鼠标键盘的操作。
打开上述的“edit events”框,只要选定了某一个事件产生源,其相应的所有事件均排列在右侧events框中。
有时候,多个事件产生源会对同一个用户操作分别产生相应事件。比如在某一控件上按下鼠标,区域事件和控件事件都会发出鼠标按下(Mouse Down)事件。LabVIEW 按以下规则顺序产生不同的事件:
 键盘相关的事件(Key Down, Key Up, etc.)只在当前选中(Key Focused)的控件上产生;
 鼠标相关的事件(Mouse Down, etc.)按照从外向里的顺序发出。例如,区域的鼠标按下事件先于控件的鼠标按下事件发出;结构的鼠标按下事件先于先于结构内控件的鼠标按下事件发出。
 值改变事件按照从内向外的顺序发出。结构(Cluser)内控件的值改变事件先于结构的值改变事件发出。

二. 按照发出时间区分事件的种类

    按照事件的发出时间来区分,LabVIEW的事件可分为通知型事件(Notify Event)和过滤型事件(Filter Event)。

    通知型事件是在LabVIEW处理完用户操作之后发出的,比如用户利用键盘操作改变了一个字符串,LabVIEW 在改变了该控件的值之后,发出一个值改变(Value Changed)通知型事件,告诉事件结构,控件的值被改变了。如果事件结构内有处理该事件的框架,则程序转去执行该框架。
    过滤型事件是在 LabVIEW 处理用户操作之前发出的,并等待相对应的事件框架执行完成之后,LabVIEW 再处理该用户操作。这类事件的名称之后都有一个问号。例如键盘按下?事件(Key Down? Event),当用户处理该事件时,控件的值还没有被改变,因此,用户可以在该事件对应的事件框架内决定是否让 LabVIEW先处理该事件,或改变键盘按下的值之后再让LabVIEW继续处理该事件。
    可以明显地看出,过滤型事件比相应的通知型事件要先发出。
    当同一VI的程序框图上有多于一个的事件结构时,通知型事件是同时被发往所有的事件结构的,而过滤型事件则是按顺序、依次发往每一个事件结构的。但是,在同一VI上放置多个事件结构是没有必要,而且极易引起错误的。所以应该避免在同一VI上使用多个事件结构。

    下面举例说明如何使用通知型事件。我们经常需要使用到这样的字符串控件:控件用于输入电话号码,因此只接收数字和横线,对其他按键不起反应。LabVIEW没有直接提供此种控件,但是它们可以利用通知型事件被方便地实现出来。


图3:利用 Key Down? 事件实现电话号码控件

    这个例子可以在这里下载:Phone Number Control.vi

三. 动态事件

    在初始状态下,打开事件配置(Edit Events)对话框,动态事件下的一栏是空的。因为动态事件只有注册过之后才能使用。与事件相关的操作在函数选栏的 Programming -> Dialog & User Interface -> Events 下面。
    用于注册事件的节点是事件注册节点(Register For Events)。需要注册某一事件时,先为它的产生者生成一个引用节点,然后将引用节点与事件注册节点的下方区域相连,再选取所需的事件。如下例:


图4:注册动态事件

    对于当前VI上的控件或区域等类型的事件,一般来说可以在事件结构中静态地被选择,所以不需要再动态注册一遍。但有时,当前VI的程序框图已经过于复杂,我们希望在子 VI 里去处理某些控件的事件。这时就可以把控件的引用传入子 VI,在子 VI 中动态注册所需事件。在子 VI 的事件结构中处理相应的事件。

四. 用户自定义的事件

    用户自定义的事件是动态事件的一种。用户自定义的事件不基于任何一个LabVIEW对象,它是使用创建用户事件节点(Create User Event)生成出来的。并且,用户可以选择不同的事件数据类型。

五. ActiveX控件的事件

    ActiveX 控件的事件不能直接被LabVIEW的事件结构所截获。ActiveX 事件需要用注册事件回调 VI 节点(Register Event Callback)来为某一事件指定一个VI。当事件发生时,执行被注册的 VI。我们也可以利用注册事件回调 VI 节点为某一 LabVIEW 自身的事件注册一个回调 VI,但是出于运行效率,和程序可读性等方面的考虑,最好不要这样使用。

相关文章:
    我和 LabVIEW

范例下载:
    Phone Number Control.vi