Labview程序设计模式_第1页
Labview程序设计模式_第2页
Labview程序设计模式_第3页
已阅读5页,还剩19页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、 例如我们在 LabVIEW 中构建一个用户界面型程序时,往往首先在背面板中加入一个大的 while 循环以使程序持续运行。如果需要响应用户界面事件则还需要加入一个Event 事件结 构。那么我们是否曾经考虑过以下的这些问题:(1) 应用中是否存在并行响应的情况?如在持续的数据采集过程中,是否需要同时响 (4) 同一个循环中采用哪种方式进行数据交换?是局域变量、全局变量、共享变量还 (6) 如果程序运行过程中,发生系统错误或者硬件通讯错误,是否会停止运行?待错 (7) 如何组织程序中的核心数据结构?是否需要采用面向对象程序设计? (9) 如何处理程序运行中的断电情况?重新启动时的继续运行?数据

2、的最低丢失? 但是,如果使用 LabVIEW 开发一个典型应用的程序却无法回避这些问题。因此,有必要对 针对这些共性研究哪种结构更加适合于应用。这些结论综合起来就形成了程序设计的模式。 的特有的程序设计模式。 分的 LabVIEW 主程序。最基本的状态机结构如图1 所示。状态是状态机运行的经脉,在开 始使用状态机模式撰写程序时需要将应用分为若干个状态。下面以图中的应用为例说明基本 前面板具有3 个按钮(Control)和1 个波形显示控件Chart(Indicator功能分别是: 4) Chart:用于显示获取的随机数。这是一个非常简单的应用,但是具有一定的代表性。根据要求,该应用至少包含以下

3、5 2) Idle:空闲状态,用于响应各种用户界面操作;3) acquire:采集状态,用于持续模拟采集数据;4) about:用于弹出关于和帮助对话框;5) stop:停止状态,退出循环并中止程序。 图1 基本的状态机结构背面板 态;如果dialog 被按下,则进入about 状态;如果stop 被按下,则进入stop 状态;否则如 果没有任何按钮被按下,则仍然进入当前的Idle 状态继续检测。在acquire 状态中,为了保证程序的重复采集使得下一个状态仍然为acquire,但是这样 stop 被按下,则不再进入acquire 状态而直接进入stop 状态。 态图的方式显示清晰明了)和扩展

4、性(日后只需要扩展状态即可扩展相应的功能)。 如图2 所示,但是它们实质上是不同的。主要体现为以下7 点:针对基本状态机模式的第(13)个问题,需要对模式进行改进。本节将一一分析这些 问题对应的解决方案,并最终形成一种新的状态机模式消息队列型状态机模式。 个书桌上有许多种类的书籍(通信、计算机、机械、法律等),这些书都摆放在书桌上很整 些书立中寻找即可。 如果把这些状态混在一起,我们需要找到某一个状态时会比较困惑和麻烦。如同上面所述, 态。在实际的状态控制中,需要确保程序只会进入实际的状态中运行而不会进入到“书立”分支中,因此对每个“书立”加入了“-”以示区别。 程序具有很多个状态的时候。(2

5、) 缺乏数据共享和错误处理机制。 在case 结构中如何传递不同分支的数据呢?这个问题似乎很容易解决,使用局域变量,全 统运行的内存空间和时间。由于状态机的基本组成元素除了case 结构之外还有循环,因此 可以使用移位寄存器来传递数据。如图5 所示。 图5 使用移位寄存器进行数据共享和传递,将所有的数据封装在一个簇中并对每个数据 数据的时候并不会影响现有的数据引用。(3) 每一个状态分支只能够决定后面的一个状态,而无法决定一个状态序列(多个状 如果需要传递一个状态序列,很明显可以使用队列或数组进行状态的传递。在LabVIEW 程 态机基础上的改进。 首先到叫号机处领取号码进行排队(进入队列)并

6、等待。然后,当前面的储户办理完业务后 就可以到相应的窗口办理业务(退出队列)。事实上,这种方式在现代生活中随处可见。在 LabVIEW 中至少有两种实现消息队列的方法。如图6 所示。前者使用数组函数实现 列的有序操作和状态的序列变化。 特使用一个实例说明消息队列型状态机的使用过程。 买的商品找币,当币值不足或商品已经销售完毕时则无法购买。程序的前面板如图7 所示。在贩卖机的左上侧有4 个按钮。 (2) Change Back:表示找零,也就是将目前剩余的货币退还给用户。 ), 单击Stop 按钮将退出应用程序。本例将使用本节介绍的消息队列状态机模式解决这个应用(也可以使用其它的设计模 式)。系

7、统的功能并不复杂,关键是要判断贩卖机中的剩余钱数和剩余的货物数以决定交易 程序背面板如图8 所示。系统分为5 个状态,并分为2 大类。 a) Idle(Default空闲状态。b) CheckMoney:贩卖机中的剩余钱数和剩余的货物数以决定交易是否成功。 统采用数组函数处理消息队列。 在UI Initial 中,系统给标题栏和说明栏赋值,并将前面板的商品设置为不可购买状态, 因为在初始化时还没有完成投币动作。如图9 所示。 存器传递以便于在各个case 分支中共享和使用,如图10 所示。 CheckMoney 分支主要是为了防止不合法的交易(如投入的币值不足或商品数量不足 当程序运行到Exi

8、t 分支时,将停止循环并退出程序,如图12 所示。 Idle 分支用来监控前面板各个按钮控件的变化并执行相应的状态。该分支比较复杂,当 检测到第0 个按钮被按下时(即1USD 按钮贩卖机中的货币值应该加一,同时需要判断 这里不再重复解释。 应用程序时也更加地健壮,代码也易于维护和查看。针对基本状态机模式的第(45)个问题,需要对模式进行改进。本节将一一分析这些 问题对应的解决方案,并最终形成一种新的状态机模式用户界面事件模式。 (2) 无法响应更多的前面板事件。 中提供的事件结构(Event Structure)能够让我们非常便捷地处理这两类问题。在 LabVIEW 中事件结构的使用并不是一件

9、难事,根据事件的发出源,事件可以抽象地 事件结构的使用方法。图14 所示的结构称为用户界面事件模式,它能够很便捷地响应各种事件并且不占用CPU 的资源,这是由LabVIEW 中事件结构本身的特性决定的。 和椭圆(oval一次完成的绘画过程是:在画布上单击鼠标开始绘制按住鼠标的同时在 画布上拖动鼠标在画布上放开鼠标结束绘制。程序的前面板如图15 所示,由上下两大部分组成。上面用于选择需要画图的样式,下面是画布,右上方的X 表示程序的结束。 决的,只能通过事件结构。因此本例将使用用户界面事件模式实现上述的画图板功能。程序的背面板如图16 所示。共有4 个事件。(1) Panel Close?:响应

10、前面板的X 动作,这是一个过滤性事件,当事件发生时并不真 正关闭前面板而只是停止程序的运行。 (4) Picture :表示绘画的结束,此时一定要加入Mouse 从这个步骤开始。事件分支左侧的 Button 参数表示单击鼠标的键位,只有在单击鼠标左键 函数可以在当前的位置上画一个点并且将画笔移动到当前位置。从图中可以看出系统定义了4 个移位寄存器变量以实现不同事件分支的共享,它们的含 (1) 表示当前画布中的图像,事实上就是前面板picture 中的内容。因为每次画图时都 是在当前画布上图像进行叠加,所以需要使用移位寄存器以避免过多地局域变量。(2) 表示开始绘制时的鼠标位置,也就是Mouse

11、 Down 在画布上的相对位置,绘制的 (3) 表示是否开始了绘制。前面提过每次的绘制过程都是从Mouse Down 开始的,如 果没有这个动作,那么在鼠标在画布上的移动是无效的。(4) 表示开始绘制时的图像,这个变量与(1)是不一样的。它表示在Mouse Down 时画 布上的图像,而不是画布中的实时图像。 Picture 事件如图18 所示,该事件是绘图的过程中,因此移位寄存器(3) 的值必须是true。可以根据不同的画图类型使用相应的函数进行绘图,如画Line 时,只需 要把当前鼠标的位置作为Line 的终点。 Picture 事件如图19 所示,该事件表示绘制的结束,因此只 需要把移位

12、寄存器(3)的值设置为false 即可。 多时往往需要使用大量的移位寄存器,因为建议使用cluster 的形式将各个变量有序地组织 列型状态机模式和用户界面事件型模式的优点呢?这样可以同时避免基本状态机的第(15) 状态机模式的基本构成元素是while循环和case 结构,而事件结构模式的基本构成元 素是while循环和event结构,因此新的模式应该由while循环、 case结构和event 结构 在第一种方式中,每次循环的运行需要经过一个事件结构才能够实现case 中各个分支 些函数可以在 case 结构中共用显示这是无法满足要求的,它从本质上而言仍然是一种 事件结构。我们可以回忆状态机

13、模式中的“空闲Idle”状态,这正是长时间占用CPU 资源的源头,如果在Idle 中加入一个事件结构后就有效地规避了这个问题。图 20 三种结构的组合方式 原来的货币值与新加入的币值相加得到新的值)。这样,需要有一种途径把 1USD、2USD 和5USD代表的币值作为参数传递给函数。图21所示为带参数的状态机结构,在消息队列的状态机模式中,加入了一个变体型的 果发生错误将直接转到错误处理状态。当然,也可以在图21 的基础上做一些改进和变形, 图 21 带参数的状态机结构【应用4】 图 22 2D数组排序_前面板系统使用状态机和事件结构相结合的模式,如图23所示。程序分为8 个状态,共有4 图图

14、 23 2D数组排序_背面板 图 24 状态机中的事件结构(1) Index:当前排序的列号,表示Listbox 以哪一列为依据进行排序。 量赋值即可,并且当该单击是有效单击时进入“DSort”状态进行排序操作。 在图27所示的DSort 状态中,根据内部变量的值对Listbox 赋值并更新列头的显示。 提供2D 数组的排序方式,只提供了1D 数组的排序函数。本例充分利用了LabVIEW 提供的排序函数功能,当然并不是唯一的,也可以使用LabVIEW 实现常用的排序算法。 LabVIEW 提供了多种动态调用的方式,从底层而言是通过VI Server 技术实现的。图31 所示为LabVIEW 中

15、的Application Control 选板,动态调用所使用的节点都位于这 作;最后再关闭该VI 的句柄避免内存泄漏,这就完成了一次对VI 的调用。 出接口,也就是说这种动态调用的前提是必须知道被调用VI 的输入输出接口,否则无法进 Open VI Reference 的路径输入是一个多态的输入口,也可以使用String 输入,如图33所示。此时被调用的VI 必须在内存中,且输入的是被调用VI 的文件名。值得一提的是这种“文件名”调用方式在可执行程序中是无法被调用的,因此建议最好采用路径的调用方式。 显然这是一个比较熟悉的递归调用,但是在LabVIEW 中似乎很难实现。由于LabVIEW 不

16、允许同名的VI 同时在内存中,因此一个VI 是无法VI 调用本身的。但是,通过VI 的可重 入技术和动态调用技术却可以实现VI 的递归调用。 同理我们也可以使用这种递归的方式实现 f(n)=n! 的算法,从数学上可以写作 f(n)=n*f(n-1),其中 n=1,f(0)=1。具体的实例将不再详述。此外,递归算法的效率比较低, 在实际应用中应谨慎使用。 调用的VI 运行完毕,主程序才会继续执行。这似乎无法解决在本节开头提到的问题,那么 是否存在一种动态调用方式使被调用的VI 与主VI 之间分别独立运行呢?答案是肯定的。 行、停止和赋值,各个属性节点和方法的具体含义见LabVIEW 的帮助文档。

17、使用这种方式动态调用VI 时,并不需要知道VI 的输入输出接口。 图 36 是该使用“属性节点和方法”实现动态调用的一个实例。在大多数应用程序启动 ), 主程序,将Wait Until Done 设置为false,这样就可以保证被调用VI 的独立运行;最后,关 世界上不会存在一劳永逸的事情,因此也不要认为任何一种程序设计模式能够“通杀” 所有的程序结构。本文对LabVIEW 程序设计模式的讨论主要是为了更好地理解LabVIEW 程 序的设计方法,更进一步地设计出健壮、可扩展性强的程序。 在LabVIEW 中选择“FileNew”菜单,会弹出图45 所示的对话框。当然,也可以将自己 在使用LabVIEW 时,程序员会更习惯于使用函数面板(Function Palette包括调用一 个子VI(SubVI)或者选择一个内置的函数。那么能否把一个自定义的VI 放在函数面板中, 当选择该VI 时并不是调用其作为一个子VI,而是调用该VI 的背面板代码?

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论