资源描述
Click to edit Master text styles,Second level,Third level,Fourth level,Fifth level,Click to edit Master title style,Click to edit Master text styles,Second level,Third level,Fourth level,Fifth level,Click to edit Master title style,*,Http:/,Http:/,Thank you!,LabVIEW,程序设计模式,Intelligent Electronics Institute,Huazhong,University of Science&Technology,目录,LabVIEW,程序设计模式及分类,状态机模式,消息队列处理模式,用户界面事件模式,状态机,-,用户界面事件混合模式,其他模式,2,LabVIEW,程序设计模式,源于虚拟仪器技术的,LabVIEW,程序设计语言,从被创建开始就是面向测量和应用的,并且绝大多数采用,LabVIEW,开发的应用程序都同测控仪器等硬件设备紧密结合。虽然这些设备的类型和规模各不相同,应用领域的差异也很大,但从测量和控制过程的基本步骤来看,绝大多数的,LabVIEW,程序的基本框架是有章可循的,具有一定的模式特征。,3,测量系统的,LabVIEW,程序框架,多数的测量系统的应用程序框架可以分为,8,部分,包括初始化、打开会话、获取数据、分析数据、显示,/,存储数据等,如右图所示:,测量系统的,LabVIEW,程序框架,4,图形化数据流的编程模式,LabVIEW,是采用了独特的图形化数据流的编程模式,这种编程模式类似于传统的面向过程编程模式,同样通过程序执行控制结构和子程序等组件来构成整个程序的框架。而这种图形化数据流的编程模式又与传统的文本的顺序执行有所不同,,LabVIEW,程序框图中节点间的数据流确定了代码的执行次序,这使得互不关联的代码可以简章地建立并行性程序。,LabVIEW,图形化的源代码,5,设计模式的分类,基于这种图形化数据流的编程模式,在大量开发实践的基础上,为满足各种不同的应用需求,总结出了不同的程序代码框架,也就是,LabVIEW,程序设计模式。,根据针对问题的不同,可以分为通用型和专用型。通用型的,LabVIEW,程序设计模式是针对一般性测量控制应用程序提出的,而专用型的,LabVIEW,程序设计模式是针对某些特殊的应用或应用中某些特殊功能提出的解决方案。,6,设计模式的分类,按照两种类型分类,各种类型又分别包含以下几种设计模式:,通用型,:主要包括状态机模式、消息队列模式和用户界面事件模式;,专用型:,主要包括主从线程模式、生产消费模式、后台服务模式、异常处理模式和代理模式。,7,状态机模式,绝大多数的测试测量系统在运行时需要从一个状态转换到另一个状态,或者在不同的状态之间互相切换,直至结束。因此状态机模式作为一种典型的类顺序结构方式,被广泛应用于各种自动化测试系统中。,状态机具有,3,个基本的要求:状态、事件和动作。任何一个状态机的执行都离不开这三个要素。,8,状态机模式,状态的选择是保证其他步骤有条不紊进行的前提,通常把程序需要经历的状态称做一个“状态序列”,它描述了程序当前的运行情况。在设计可交互式状态序列时,“等待”是一个必不可少的状态,因为常有一个状态需要等待用户“确认”,这个状态决定了下一个状态,这取决于与外部对象的交互。,状态机在控制状态的同时,与各个状态对应的事件也会随之触发。,动作是事件的响应,当一个事件发生时,状态机会决定应该执行什么样的动作,这主要取决于目前所处的状态和发生的事件。,9,一个简单的状态机框架,在,While,循环中加上一个,Case,结构就可以构成一个简单的状态机框架,其中循环主要用来使程序连续执行直到应用程序结束,,Case,结构允许程序员定义各种状态。,Case,结构的状态通常是由循环的前一次迭代决定的,而位于其子框图中的代码则用于确定状态的变化及执行相应的任务。,10,顺序型状态机模式,顺序型状态机是最简单的一种状态机结构,它和顺序结构等价。在状态机的基本构架上,将循环索引端连接到,Case,结构的选择端口上,并在最后一个,Case,子框图中控制循环结束。,顺序型状态机模式,顺序结构,11,顺序型状态机模式,状态之间的数据传递中,顺序型状态机与顺序结构的实现方式是不同的。前者使用的是移位寄存器,后者使用的是顺序结构的数据通道或者顺序局部变量。,12,例,1,利用顺序型状态机计时,利用顺序型状态机计算某个动作运行的时间,这个程序共需要,3,个子框图,调用“定时”函数子面板中的“时间计数器”函数开始计时。“时间计数器”函数返回计算机开机到当前的时间毫秒数。在第,2,个子框图中,放入需要计算的动作模块,并将初始的时间值传递给移位寄存器。在第,3,个子框图中将利用移位寄存器的值进行时间差的计算,得到动作模块运行所消耗的时间,并退出循环。,例,1,利用顺序型状态机计时,13,改进的顺序型状态机模式,顺序型状态机模式的整个状态序列的顺序是固定的,在程序运行时无法改变。也正是这一点制约了顺序型状态机的应用,因为它妨碍了作为,LabVIEW,优点之一的程序并行运行机制。为了能够在程序运行中改变状态序列的执行顺序,可以对其加以改进,采用移位寄存器代替循环索引控制状态机的执行。移位寄存器的高度灵活性使得程序员可以按照实际情况设定状态序列的实际执行顺序。,14,改进的顺序型状态机模式,改进的顺序型状态机模式的状态机中采用移位寄存器,可以在每个,Case,子框图中指定下一个状态。,15,例,2,利用改进的顺序型状态机计时,利用改进的顺序型状态机改写例,1,后,程序中用了两个移位寄存器,上面的一个用于控制状态机的运行,另一个用于数据传递,将第一个状态中得到的时间值传递给第三个状态参与计算。而且并不一定要按照图中的顺序安排各个子框图,只需要利用移位寄存器的输出值将各个状态之间串起来即可。,例,2,使用改进的顺序型状态机计时,16,测试流程型状态机,顺序型状态机还有一个缺点:不便于阅读和修改程序,,Case,结构的子框图列表中显示的是数值,不具有任何的实际意义。所以需要找到一种方式,不仅能够保证,Case,结构的正常运行,还要能够很方便地识别,Case,结构中各个子框图的功能。,使用枚举型常量代替数值型常量控制状态机运行,也就是我们提出的测试流程型状态机,正好能满足我们的要求。,17,例,3,利用测试流程型状态机计时,与例,1,,例,2,相比,程序员可以定义枚举值为各个状态的功能,在,Case,结构的子框图列表中,这些枚举值会显示出来,这样就可以很清楚地知道各个,Case,子框图的具体含义了。,例,3,利用测试流程型状态机计时,18,消息队列处理模式,当我们需要动态地根据用户的输入改变状态序列时,状态机模式的劣势就显现出来,因为其状态序列是固定规定好的,一旦程序运行越来就无法修改。为此,需要引入消息队列模式,通过建立队列缓冲区来解决这个问题。这种模式也称为“队列型状态机模式”,但是由于其应用和原理都并不局限于状态机模式,所以为了避免混淆,一般称为“消息队列处理模式”。,19,消息队列,程序员可以将消息队列看成一段存储空间,用来暂存各种消息。之所以称为队列,是由其消息处理机制决定的,按照,FIFO,(先进先出)的思想,需要使用队列的方式处理各种消息。在程序初始化时,首先创建消息队列缓冲器,程序可以根据发生的事件将相应的消息投入到消息队列中,消息处理机构会实时探测消息队列中的消息并按照消息处理机制进行处理;当消息被接收后程序会执行相应的代码,并将该消息从消息队列中删除;当接收到消息“,Exit”,时,应用程序会停止运行,并释放队列空间。,20,消息的处理过程,消息的处理过程,21,消息队列建立方式,建立消息队列的方式有多种,常用的是使用队列函数和数组。队列函数位于“同步,队列操作”函数子选板中,常用的,4,个是获取队列引用,元素入队列,元素出队列和释放队列引用。而使用数组操作函数对消息进行操作,结构简单,只需要配合移位寄存器使用即可,不需要额外的函数,而且不需要使用特别的函数手动销毁队列空间,在应用程序退出时会自动销毁队列。,22,使用数组处理消息队列,假如执行某种操作需要经历,4,部分扫描区域:区域,A,、区域,B,、区域,C,和区域,D,,用户可以使用前面板的按钮控制,3,种扫描顺序,分别是,ABCD,、,DCAB,和,BDCA,。“执行顺序”显示单击各个按钮时程序状态执行的顺序。,消息队列例程前面板,23,使用数组处理消息队列,在建立消息队列之前首先要确定程序的状态,“初始化”状态是必不可少的,它用以复位前面板控件、中间变量值、寄存器值和打开扫描仪器等;“等待”状态,在该状态下程序一直探测前面板三个按钮的动作;“退出”状态用于销毁空间,关闭扫描仪器等;此外,还需要“扫描区域,A”,、“扫描区域,B”,、“扫描区域,C”,和“扫描区域,D”,分别控制各个不同的扫描区域。,24,使用数组处理消息队列,扫描例程,初始化状态,建立消息队列,移出消息队列,加入消息队列,25,使用数组处理消息队列,扫描例程,等待状态,26,使用数组处理消息队列,一旦用户单击前面板的按钮,这个信息将会被系统探知,并执行相应的消息处理函数,如,Case,子框图标识为“,1”,、“,1”,和“,3”,的源代码。当没有搜索到任何“真”值时,便将“等待”状态加入消息队列,以便不断探测消息队列中的值,维持循环的运行。当搜索到“,0”,“,2”,时,将相应需要执行的状态序列加入消息队列。运行完各个扫描区域的代码后,程序应该继续回到“等待”状态。,27,利用数组处理消息队列,扫描例程,扫描区域“,A”,状态,28,利用数组处理消息队列,在只有在这个状态才把“真”值传递给,While,循环判断端子,使循环中止,结束程序运行。当然,程序员还可以在这个子框图中添加一些代码,如销毁释放控件、关闭仪器会话等。,扫描例程,退出状态,29,使用队列函数处理消息队列,使用队列函数处理消息队列的原理和使用数组方式是一样的,二者的构造和流程也相同。“删除数组中的元素”相当于“从队列中移出元素”函数,“往数组中增加元素”相当于“将元素移入队列”函数,实现的方式也是一样的。但两者的消息传递方式不同,前者采用的是移位寄存器方式,而后者采用队列技术;并且前者可以在程序结束时自动释放,后者的队列资源也可以在程序结束后释放。但是当程序作为子程序时,队列资源并不会随着子程序的结束而自动销毁,而是需要等到主程序结束时才释放。所以有必要使用“释放队列引用”函数手动销毁队列。,30,使用队列函数处理消息队列,使用队列函数处理消息队列,建立消息队列,移出消息队列,销毁消息队列,移入消息队列,31,用户界面事件模式,通过搜索的方式来捕捉所有的“单击按钮”事件或其他事件,往往会占用大量的,CPU,资源。另外,状态机模式并不能捕捉其他一些常见的事件,如鼠标移动、关闭窗口和单击某个菜单项等。为了解决这些问题,程序员可以使用用户界面事件模式。这种交互方式能够处理目前使用到的绝大部分事件,这是,LabVIEW,中用于人机交互的一种强大而高效的模式,而且事件捕获的方式采用中断实现,在事件没有发生期间,,CPU,可以处理其他的操作,这就极大地减轻了,CPU,的负担。,32,事件框架,根据来源的不同,事件可分为用户界面事件、外部,I/O,事件和其他程序事件。其中,用户界面事件包括鼠标单击、键盘按键等动作;外部,I/O,事件包括当数据采集完毕或发生错误时硬件定时器或触发器发出信号等情况;其他程序事件可通过编程生成并与程序的不同部分通信。,LabVIEW,支持用户界面事件和通过编程生成的事件,但不支持外部,I/O,事件。,33,简单的事件结构,事件驱动程序通常包含一个循环,该循环等待事件的发生并执行代码来响应事件,然后不断重复以等待下一个事件的发生。程序如何响应事件取决于为该事件所编写的代码。这种程序模式的执行顺序取决于具体所发生的事件及事件发生的顺序。,事件结构,34,用户界面事件,用户界面事件分为两种类型:,通知事件,和,过滤事件,。,通知事件,表明某个用户操作已经发生,且,LabVIEW,对事件处理后对事件作出响应,可以配置一个或多个事件结构对一个对象上同一通知事件做出响应。,过滤事件,允许用户对发生的事件做出响应,人为控制事件的发生。,通知事件,过滤事件,35,用户自定义事件,根据事件的发出源,事件可以抽象地分为用户界面事件和用户自定义事件。鼠标单击、值改变、菜单项被选中和键盘单击等都是用户界面事件。自定义事件可以通过编程创建和命名自己的事件,来传送用户自定义数据。用户自定义事件需要使用的函数包括创建自定义事件、产生自定义事件、取消自定义事件、销毁自定义事件和注册自定义事件。,36,例,4,用户自定义事件,用户自定义事件,37,事件注册,自定义事件并不能使程序产生对应的事件,还需要事件结构能够识别这些事件,这就是“事件注册”。当向事件结构注册自定义的事件后,使用“产生用户事件”函数时,,LabVIEW,才会将用户事件及相关事件数据注册到与事件队列中。,从事件类型上而言,,LabVIEW,支持,静态,和,动态,两种事件注册模式。其中动态事件不仅可以注册,还可以修改。,38,静态事件注册,只有用户界面事件才可以进行静态事件注册,允许指定,VI,在程序框图上的事件结构的每个分支具体处理该,VI,在前面板上的那些事件。首先需要选择事件源,它可以是程序、,VI,或某个控件。同时选择一个事件源可产生特定的事件,如前面板大小调整、值改变等。其次,根据应用程序的需求,编辑该分支来处理事件数据。,LabVIEW,在,VI,运行时将自动注册这些事件,一旦,VI,开始运行,事件结构便开始等待事件,程序员无法在程序运行时改变事件结构所处理的事件。,静态事件注册,39,动态事件注册,动态事件注册通过将事件注册与,VI,服务器相结合,允许在运行时使用应用程序、,VI,和控件引用来指定希望产生事件的对象。并用可以完全控制,LabVIEW,产生事件的类型和时间。但是,动态事件注册比静态事件注册复杂,它需要将,VI,服务器引用和程序框图函数同时使用以注册和取消注册事件,而无法通过事件结构的配置信息自动注册。此外,动态事件可以使事件仅在应用程序的某个部分发生,或在应用程序运行时改变产生事件的,VI,或控件。,40,处理动态注册事件的步骤,(,1,)获取要处理事件对象的,VI,服务器引用;,(,2,)将,VI,服务器引用连接至“注册事件”函数以注册对象的事件;,(,3,)将事件结构放在,While,循环中,等待处理对象事件至出现终止条件为止;,(,4,)通过取消注册事件函数停止事件发生。,41,例,5,“最值器”,“最值器”用于求取给定,5,个输入值的最大值、最小值和平均值。只有当仪器开关设置为“真”时,即仪器打开后,仪器面板上的“输入值”控件才会起作用。当改变控件的值后,,3,个输出量也会实时改变。,“最值器”前面板,42,例,5,“最值器”,用户自定义事件用于“初始化”命令,并且使用动态注册方式。在事件结构的外部还产生自定义事件,这样程序进入事件结构后可以直接进入这个自定义事件的子框图中。该框图主要用于将开关量设置为“假”(复位),并将输出显示端清空。,“,:用户事件”事件框图,43,例,5,“最值器”,另外一个动态注册的事件是“输入值”控件的“值改变”事件。以保证只有当“开关”控件为“真”时才有效,当“开关”值设为“真”时,才将该事件注册以供事件结构监听;否则就不注册,此时即使改变“输入值”控件的值,也不会有任何作用。,“,开关,:值改变”事件框图,44,例,5 “,最值器”,“,:值改变”子框图中,将获得的值转换为数组型值,并得到数组中值的最大值、最小值和平均值。在循环结束后需要取消注册事件并销毁自定义事件。,“,:值改变”事件框图,45,状态机,用户界面事件混合模式,使用状态机和事件结构各有优劣,将状态机模式与用户界面事件模式结合起来,构成状态机,用户界面事件混合模式,这样一种模式可以有效地避免单个模式带来的缺点。这种模式的具体做法,其主体框架仍然由状态机构成,唯一不同的是在“等待”子框图中,不再是使用“搜索数组”函数获取前面板控件值的改变,而是采用事件结构探测各种发生的事件。这样可以充分发挥事件结构的优点,既不会遗漏部分事件,也不会过于占据计算机资源。,46,状态机与用户界面事件混合模式,状态机与用户界面事件的结合,47,例,6,状态机,用户界面事件结合模式,状态机与用户界面事件结合模式,等待,48,例,6,状态机,用户界面事件结合模式,状态机与用户界面事件结合模式,扫描区域,A,49,其他模式,前面介绍的所有模式都具有很强的扩展性,在流程控制中能够满足绝大多数应用的需要。但是在某些特殊的应用中仍然存在局限性,需要更具有针对性的程序框架来满足这些需求。,还有其他更多的模式在工程应用中可能会遇到。包括主从线程模式、生产消费模式、后台服务模式、应用程序启动模式、代理模式。,50,主从线程模式,主从(,Master/Slave,)线程模式通常应用于具有两个或多个同时发生的并且拥有不同运行速率的线程的程序中。程序员可以在两个循环中放置不同的任务,二者是互不影响的,数据通信采用全局变量或共享变量的形式。,主从线程模式框架,51,生产消费模式,主从模式的数据通信是利用全局变量、局域变量或共享变量实现的,由于这些变量的每次复制都是原始数据的一个副本,占据了大量的空间。实际上,只需要使用一部分缓冲区作为数据存储的中间部分,这需要借助队列技术,也称为“生产消费模式”。这种模式仍然采用两个简单的,While,循环,但是数据通信采用队列结构,一方面将采集到的数据传送给队列空间,另一方面从队列空间中读出数据,二者是相互独立而又紧密联系的。,生产消费模式,52,后台服务模式,后台服务程序,一般不需用户的干涉而在计算机后台运行,即不需要显示应用程序的前面板。,LabVIEW,为用户提供了,VI,属性和方法接口,通过这些接口程序员可以方便地控制,VI,的一些固有属性和运行时的状态。,后台服务模式,53,应用程序启动模式,通常程序员需要在应用程序启动时显示应用程序的名字和版本,也就是通常所说的“开机画面”,而在子,VI,装载完成后,该启动画面将自动退出并启动主应用程序。,LabVIEW,允许程序员根据自己的实际应用,通过更改,VI,属性编写自己的“开机画面”应用程序,以显示应用程序的名字和版本等信息。,54,应用程序启动模式,“应用程序启动模式”程序框图,“应用程序启动模式”前面板,55,代理模式,LabVIEW,默认在主程序打开时就将其调用的所有子,VI,载入内存。在大型的应用程序中,子程序会成百上千,这就势必会减慢应用程序打开的速度。为了解决这个问题,可以在,LabVIEW,应用程序中引入“迟载入”技术,即在顶层,VI,需要某个子,VI,时才将其载入内存。这对于那些使用非常频繁的子,VI,特别有用,这种模式就是代理模式。,56,代理模式,LabVIEW,提供了一种很简单直接的方式允许程序员设定主程序调用子程序的方式,打开“调用设置,”命令,即可弹出“,VI,调用配置”对话框配置子,VI,的调出方式。,加载调用方,VI,的同时加载子,VI,。,在调用子,VI,时加载子,VI,。,仅在调用方,VI,第一次调用子,VI,时加载子,VI,。子,VI,仅在调用方,VI,需要该子,VI,时才加载,且在操作结束后可将子,VI,从内存中释放。,57,习题:,1,、试比较消息队列处理模式和用户界面事件处理模式的异同。,2,、参考原书,2.5.4,节的虚拟仪器示例,试做如下的修改。,(,1,)原有界面上的“开关”仅控制仪器是否工作。当为“开”时,仪器能够正常工作,并显示结果;当为“关”时,仪器停止工作,此时不会显示结果,但是不会退出程序。,(,2,)新增一个“退出”按钮,用于控制退出程序。,3,、某栋,8,层房屋需要安装一部电梯,其终端控制过程如下描述。,(,1,)每个楼层都设置了两个按钮,供当前层的用户选择上楼或下楼(顶层和底层仅设置一个按钮);,(,2,)以某个处于,3,楼的用户为例,假定他按了“上”的按钮,如果电梯处于下降状态并且最后状态小于,3,层,或者处于上升状态且当前位置已经大于,3,,则不予理睬,直至完成当前传输后再响应;否则电梯运行到,3,层,并处于上升状态,如果该用户进入后没有按需要到达的楼层则电梯处于等待状态,一定时间后超时则开始响应其他动作;如果该用户按下的目的地大于,3,层,则电梯将运行到相应楼层;如果该用户按下的目的地小于,3,层,则不响应。,58,习题:,试利用,LabVIEW,设计并模拟以上单部电梯的运行过程,在设计时需要考虑程序的可扩展性(如果是,100,层房屋呢?)。,4,、根据自己的专业要求,利用,LabVIEW,编写一个程序,并使用本意的某种或多种程序设计模式。,59,
展开阅读全文