错误处理机制

错误簇由一个布尔类型数据、一个数值型数据和一个字符串数据组成。它们分别表示是否有错误、错误
代码和错误信息。

不可预期错误

不可预期的错误也可以被称为”异常”,这是程序中错误处理机制主要需要预防的错误。
处理方法:一旦有错误出现,程序的后续代码全部忽略,让程序尽快终止。在需要预防出错的地方加一个条件结构,函数的错误输出连接在条件结构的分支选择器上,程序后续的代码全部放在条件结构的”无错误”分支中。把判断对错的代码都放在较为底层的子VI 中。在编写错误处理机制时,就必须考虑到哪些代码在出错时依旧需要运行。

可预期的错误

可预期的错误,即编程者已经知道在某种情况下函数会返回某个错误并需要针对此错误进行预定的处理。
image.png

自定义错误

更加可靠的做法是借助”编程→对话框与用户界面→错误代码至错误转换”VI; 提供给这个VI 错误代码和错误信息,它就可以输出一个对应的错误簇。错误代码可以选择LabVIEW 中已定义的错误.例如. LabVIEW 的错误代码
50 表示”信息超出范围”,它与输入值越界性质类似。也可以使用5000~9999 和-8999~-8000 之间的某个数值,这两段数值是专门留给用户自定义错误代码的。
简易错误处理:程序运行过程中不应有错误对话框出现,但在程序退出前,可以提示用户所出现的错误。
在程序调试过程中,编程者是希望一旦发生错误,就立即显示出来的。在程序的项目中自己设置一个专用的条件禁用符号,用于判别程序是在调试阶段还是在发布阶段.例如,用”DEBUG”作为条件禁用符号,把它添加到项目设置中,当它的值为”True” 时,程序可以随时弹出错误对话框。
image.png

可重入VI

状态机

循环条件结构

image.png
image.png

单状态传递的状态机

image.png
软件设计从上到下。

多状态传递的状态机

每一个状态结束前,它只能指定下一个状态.但在实际程序中,有时执行完一个分支的代码就可以根据当前数据确定后两次迭代中需要执行的分支。完成这种功能需要用到队列。
队列是一种数据结构,队列中可存放多个类型相同的数据。队列中的数据必须是先进先出,即每次从队列中取出一个数据时,只能取队列中最先被放进去的那个。
image.png
image.png
队列和数据缓冲区的区别:1.队列中数据是否增加取决于是否有读队列的过程,如果出队的速度>入队的速度,队列中不会有残留数据,反之,数据不断增加和数据缓冲区一样。2.队列有调节读写速度的能力,当数据满后,缓冲区自动移除最早进入缓冲区的数据,而队列则被动等待出队。VI结束前必须释放队列,如果忘记释放队列会导致内存泄露。
数据入队列后如果不出队会一直在,除非vi关闭或销毁队列。
队列的应用:
1.用队列实现数据缓冲区
image.png
2.利用队列替代全局变量
3.利用队列在不同任务中循环或者VI之间传递数据(数采和显示的例子)
image.png
image.png
4.利用队里创建基于命令的动作机。(上面的多种状态传递的动作机)

状态机的使用

很多程序的运行过程都可以用状态机来表示。在设计LabVIEW 程序时,可以先画出程序的状态机,即状态图,然后根据状态图编写出程序。这是一种相当有效的程序设计开发过程。
缺点:1.状态机的核心是一个条件结构。条件结构、事件结构和层叠式顺序结构都有一个共同的缺点:每次只能显示一个分支中的代码,不利于程序阅读.
2.,状态机不适合应用于大型程序。程序规模加大之后,如果再用状态机来表示它,必然造成状态数量的急剧膨胀,表示它的状态图会变得非常混乱。而LabVIEW条件结构中的分支过多,会大大降低程序的可读性和可维护性。
** 常见的一些程序结构模式,例如循环事件结构模式,也可以看作是一种状态机.但是事件结构已代替了条件结构,因为使用事件来控制程序状态的跳转更加便捷。
**

状态工具包安装不上

D:\app\Labview\Shared\ProductCache\NI LabVIEW 2010 Statechart Module [10.0.115.0]

全局变量

在 LabVIEW 中应当尽量避免使用全局变量和局部变量。全局变量看似方便,但带来的问题也很多 。 最主要的是它破坏了数据流顺序的逻辑关系,导致程序可读性和可维护性下降。会导致数据竞争的关系。

共享变量

共享变量与全局变量相比,其作用域更广。它不但可以在不同的VI 之间传递数据,还可以在不同的程序、甚至不同的计算机以及硬件设备间传递数据。在实际应用中,共享变量主要用于网络上不同VI 的数据共享或读/写其他硬件设备上的数据。单进程共享变量, 顾名思义就是作用域为单个应用程序进程的共享变量,与全局变量的性质是完全相同的; 唯一的不同点是单进程共享变量都带有错误输入/输出端,我们可以利用错误处理连线来控制单进程共享变量的执行顺序。
在project中右键新建variable:
image.png

功能型全局变量

循环结构的移位寄存器,无明显缺点。功能全局变量虽然有很多优点,但如果要把它作为更大的功能模块来使用,也同样存在很多不足。由于它和状态机都是基于循环条件结构的,因此,前文提到的状态机的缺点,功能全局变量也同样存在.模块功能复杂,往往接口的数据也多。把众多的接口数据放在一个V1 上提供给用户,用户很可能被这个V1 上的数据搞得晕头转向,不知该如何使用。
现在只要使用LabVIEW 8.2 以上的版本开发新的功能模块,就完全没有必要继续使用功能全局变量这种模式了。LabVIEW 从8. 2 版本起,开始支持面向对象的编程。面向对象的概念既包含了功能全局变量的优点,又克服了其缺点。

界面程序

LabVIEW 新建对话框中的基于模板中几个关于界面的VI有”用户界面事件处理器”(User Interface Event Handler)”使用事件的顶层应用程序”(Top level Application Using Events)和”使用事件的对话框”(Dialog Using Events),所使用的都是循环事件结构。
image.png

界面程序的程序框图设计

对于界面VI 的程序框图而言,在循环事件结掏外,应该只保留极少量必不可少的节点,其他的代码统统移至循环事件结构内。其实,初始化和收尾完全可以被看作两个自定义事件. 需要时发出事件,然后跳至事件结构中相应的分支去处理即可。
image.png

用户自定义事件的设计

image.png
大型的程序中往往需要多个用户自定义事件,并且有可能随着程序的开发,发现需要增加一些新的事件。
更好的方法:在程序中仅使用一个用户自定义事件,利用它的事件数据参数来区分事件的不同用途。“事件数据”用于携带事件相关的一些数据,因为不同用途的事件需要携带的数据类型可能各不相同,所以这个”事件数据”的类型可以使用变体,以存放各种数据D:\Program Files (x86)\Labview2010\LabVIEW2010\resource\importtools\Common\Event\Method有模板
用户在抛出”用户事件”时,需要给这个事件指定一个”事件名’二循环事件结构捕获到这个事件后,跳入”用户事件”处理分支.在处理这个事件之前,首先查看一下”事件名”,然后再根据”事件名”对事件做不同的处理.
image.png

对耗时代码的处理

“编辑事件”对话框最下方的”锁定前面板直至本事件分支完成”选项,默认是选中的。程序在处理某事件时不应该再对用户的界面操作产生新的事件,这一点是十分必要的。
最基本的做法就是把光标设为沙漏状,这是Windows 比较常见的处理方法。
image.png

其他注意事项

1.在一个VI 内,最多只能有一个事件结构。虽然LabVIEW 并不禁止在一个VI 内使用多个事件结构,但是多事件结构极易造成程序逻辑错误,而且也没有任何必要。在一个VI 内,完全可以把所有的事件都放到一个事件结构中
去处理。
2.通常只有当用户在界面上改变了一个控件的值.LabVIEW才会产生值改变事件。在程序中,直接赋值给控件的接线端或局部变量是不会产生值改变事件的。如果希望在程序中改变控件值的同时也让它发出值改变事件,可以把值赋给控件的“值〈信号)”属性
image.png

回调VI

与事件结构相比,回调VI 编写起来稍微麻烦一点。但回调VI 与主VI 是并行运行的。如果某个事件处理过程比较耗时,把它放在事件结构中就会阻塞整个程序,使得程序界面暂时失去响应,而把它放在回调VI 中,则不会影响程序其他部分的运行。动态调用也可以达到这一效果,但回调VI 编写起来少许简便一点。
出现问题:右表通过回调函数开始后无法按stop键,只能等其结束才能按stop键
image.png
image.png

同一功能对应多种不同界面的应用程序

需求:每个用户对程序的功能需求是一致的,但对程序界面的需求却各自不同.比如, 一个对同一产品进行测试的程序,但每个版本对界面的语言以及控件的位置、尺寸、颜色等各有不同的需求。
动态注册事件的特性之一就是把界面和程序代码完全分离开来了。界面VI 的程序框图极其简单,只须维持程序持续运行〈或许需要有一个空循环〉以及能够把控件引用传递给功能VI 即可s 而功能VI 的界面无须显示,项目仅须利用其程序框图。这样一来,项目中每个VI 只负责一件任务s 或者负责界面,或者负责实现程序功能.需要对程序功能进行修改或者调整某一风格的界面时,只须改动其对应的那一个VI 即可。程序中也不再有代码重复的VI.可维护性大大加强.
例子:在两个风格完全不同的界面上实现同一个简单的功能,即在界面上点一下按钮,就返回一个随机数值。
方法一:
image.png
image.png
image.png
方法2:公司设计多按照此设计方法来,主vi调用显示界面。

两种实现界面程序的方法对比

选择结构在外,事件结构在内,在LabVIEW中称之为“队列消息驱动”结构。事件结构在外,选择结构在内,事件驱动结构。
image.png
优先选择事件结构状态机

多态VI

使用变体作为子VI的参数类型

变体的缺点:类型安全性比较差
image.png
image.png

多态VI的概念

类似于C++中的函数重载,通过调用不同函数来实现。

编写多态VI

File-new vi more —polymorphic,the differnece bewteen Instance VI icon and polymrophic VI icon.
image.png
若选择左下角单选按钮的”绘制多态VI 图标”,则调用了多态VI 的程序框图上就会一直显示多态VI 的图标s 而如果选择”绘制实例VI 图标”,则多态VI 将随数据类型的不同而显示相对应的实例VI 的图标,以便让图标更清晰地显示出多态VI当前的功能.多态VI 右下方有两个多选选择框。若选中了”允许多态VI 自动匹配数据类型”,则多态VI 将根据输入数据类型的不同,自动选择调用相应的实例VI; 如果该项没被选中,则编程者必须每次手动选择所需要的实例VI。
直接将多态vi文件拖到程序框图中即可。后可以进行选择。
注意事项:多态VI 只能处理有限种数据类型,它只能支持实例VI 中处理了的那些数据类型.
多态VI 的每个实例VI 可以是完全不同的,前面板、程序框图、调用的更底层子VI 等都可以完全不同。但是,为了便于用户理解,一个多态VI 应该局限于处理某一种算法:它的每个实例VI 负责一种数据类型。并且,为了便于用户在不同的数据类型之间切换,每个实例VI的连线板应当使用同样的模式,接线的位置也应当保持一致。
菜单设计的小技巧:使用冒号:作为层级分割符。

Express VI 快捷VI

Express VI 的功能强大、使用便捷,但付出的代价是效率较低。在一些功能简单的应用程序中,它所调用的Express VI 也许包含了大量应用程序根本用不到的功能,这部分功能既占用内存空间,又会影响程序的运行速度。

子VI在程序框图上的显示方式

图标,可扩展节点
image.png

开发自己的Express VI

工具-高级-创建或编辑Express VI。

传引用

传值是符合数据流驱动程序的传参方式, 在LabVIEW 中应该尽量使用这种方式,但是传引用在某些情况下是不可避免的。假如程序要在不同的线程中对同一数据进行操作,就不得不用到传引用。

LabVIEW自带的传引用数据类型

LabVIEW中大部分数据类型是值传递的,而另有一部分数据类型专门用于传引用。
image.png
除了控件选板上的各种”引用句柄”外. LabVIEW 还有其他一些数据类型,尽管其数据线的颜色不同,但其实也属于传引用的数据类型.其中,包括了硬件设备的句柄(如VISA 资源名称、IVI 逻辑名等)、通知、事件、队列等。
引用数据类型本身是一个4 字节的数据,用这个4 字节的数据再指向一个其他的对象,程序中真正需要使用的是它所指向的对象。各种不同引用类型的区别在于它们所指向的对象种类是不同的,比如有的引用指向一个文件,有的指向仪器设备,有的指向某个VI 或控件。

队列

使用了传引用,就必须自己管理内存了.比如在这个例子中,程序为了传引用而创建了一个队列。在程序结束前,需要销毁这个队列,以避免可能出现的内存泄漏。

数据记录文件引用句柄

“引用句柄”控件选板中的”数据记录文件引用句柄”常常用于表示用户自定义的引用数据类型。因为被引用数据生成的队列需要通过强制类型转换函数转换成自定义的引用句柄数据类型,再传出子VI . 这样,在应用程序中,子VI 间就是通过引用句柄的深绿色线来传递数据了.
image.png

数据引用节点

image.png
“新建数据值引用”用于创建一个数据的引用,”删除数据值引用”可以从引用中取回原来的数据。,引用主要应用于多线程程序中.如果两个线程同时对同一份数掘进行修改,则必须使用传引用的机制。否则,若使用值传递的方式,数据在数据线分叉的地方,就会变成独立的两份,之后在两个线程内分别修改的是两份完全独立的数据,而并非是对同一份数据进行的修改.除了使用队列可以解决竞争外,新增添的数据引用节点更是一个简单的途径。
LabVIEW 中绝大多数的函数和子VI 都是值传递的.当它们需要使用到被引用的数据时,必须把引用转为数据,处理过的数据可能还需要再转为引用。配合使用“元素同址操作结构”后. LabVIEW 会尽量使用数组原地址,而不再复制从引用中取出的数据,这样就充分利用了传引用的效率。
LabVIEW中分为两种:传值和传引用,大部分是传值(包括数据线, 线相当于局部变量)
image.png
image.png
对于同一数据的引用,千万不能嵌套使用”元素同址操作结构” ,否则就会死锁。