- 易迪拓培训,专注于微波、射频、天线设计工程师的培养
LabVIEW程序设计模式(三)—消息队列型状态机模式
录入:edatop.com 点击:
针对基本状态机模式的第(1~3)个问题,需要对模式进行改进。本节将一一分析这些问题对应的解决方案,并最终形成一种新的状态机模式——消息队列型状态机模式。
让我们回到程序,并给程序的状态设置一些“书立”。如图 4所示,系统共有9个有效状态(UI Initial、Data Initial、Instr Initial、Temperature、Power、FFT、JTFA、Data Clean、Exit)。如果把这些状态混在一起,我们需要找到某一个状态时会比较困惑和麻烦。如同上面所述,将这些状态分为4类并设置了4个“书立”(Initial、Acquire、Analyse、System)分隔这些状态。在实际的状态控制中,需要确保程序只会进入实际的状态中运行而不会进入到“书立”分支中,因此对每个“书立”加入了“-------”以示区别。
图 4 状态分类
尽管我们只是进行了少量的修改,但是这的确有利于程序状态的组织和阅读,尤其是当程序具有很多个状态的时候。
图 5 状态机中的数据传递
图 5使用移位寄存器进行数据共享和传递,将所有的数据封装在一个簇中并对每个数据命名,这样在使用数据时就可以使用“Unbundle by name”或“bundle by name”。需要说明的是,即使使用一个数据需要共享,仍然希望采用簇的封装形式,这样当后续需要增加扩展数据的时候并不会影响现有的数据引用。
顾名思义,这种模式就像银行办理业务时排队一样采用队列的方式。当储户进入银行时,首先到叫号机处领取号码进行排队(进入队列)并等待。然后,当前面的储户办理完业务后就可以到相应的窗口办理业务(退出队列)。事实上,这种方式在现代生活中随处可见。
在LabVIEW中至少有两种实现消息队列的方法。如图 6所示。前者使用数组函数实现队列元素的入列和出列;后者使用队列函数实现队列元素的入列和出列。二者都能够实现队列的有序操作和状态的序列变化。
图 6 消息队列型状态机模式
本节解决了基本状态机模式中的(1)~(3)个问题,为了更好地比较和使用这些特点,特使用一个实例说明消息队列型状态机的使用过程。
【应用2】
本例将使用本节介绍的消息队列状态机模式解决这个应用(也可以使用其它的设计模式)。系统的功能并不复杂,关键是要判断贩卖机中的剩余钱数和剩余的货物数以决定交易是否成功。
图 7 自动贩卖机前面板
程序背面板如图 8所示。系统分为5个状态,并分为2大类。 [p]
图 8 自动贩卖机背面板
在UI Initial中,系统给标题栏和说明栏赋值,并将前面板的商品设置为不可购买状态,因为在初始化时还没有完成投币动作。如图 9所示。
图 9 UI Initial分支
在Data Initial中包含两个共享的数据:Money和GState,前者表示贩卖机中剩余的币值,初始化值为0;而后者表示贩卖机中各个商品剩余的数量,初始化值为20。数据使用移位寄存器传递以便于在各个case分支中共享和使用,如图 10所示。
图 10 Data Initial分支
CheckMoney分支主要是为了防止不合法的交易(如投入的币值不足或商品数量不足),如图 11所示。
图 11 CheckMoney分支
当程序运行到Exit分支时,将停止循环并退出程序,如图 12所示。
图 12 Exit分支
Idle分支用来监控前面板各个按钮控件的变化并执行相应的状态。该分支比较复杂,当检测到第0个按钮被按下时(即1USD按钮),贩卖机中的货币值应该加一,同时需要判断是否达到了交易条件(即进入CheckMoney状态)。其它的状态可以执行相应的代码即可,这里不再重复解释。
图 13 Idle分支
- 状态的分类不清晰。
让我们回到程序,并给程序的状态设置一些“书立”。如图 4所示,系统共有9个有效状态(UI Initial、Data Initial、Instr Initial、Temperature、Power、FFT、JTFA、Data Clean、Exit)。如果把这些状态混在一起,我们需要找到某一个状态时会比较困惑和麻烦。如同上面所述,将这些状态分为4类并设置了4个“书立”(Initial、Acquire、Analyse、System)分隔这些状态。在实际的状态控制中,需要确保程序只会进入实际的状态中运行而不会进入到“书立”分支中,因此对每个“书立”加入了“-------”以示区别。
图 4 状态分类
尽管我们只是进行了少量的修改,但是这的确有利于程序状态的组织和阅读,尤其是当程序具有很多个状态的时候。
- 缺乏数据共享和错误处理机制。
图 5 状态机中的数据传递
图 5使用移位寄存器进行数据共享和传递,将所有的数据封装在一个簇中并对每个数据命名,这样在使用数据时就可以使用“Unbundle by name”或“bundle by name”。需要说明的是,即使使用一个数据需要共享,仍然希望采用簇的封装形式,这样当后续需要增加扩展数据的时候并不会影响现有的数据引用。
- 每一个状态分支只能够决定后面的一个状态,而无法决定一个状态序列(多个状态)。
顾名思义,这种模式就像银行办理业务时排队一样采用队列的方式。当储户进入银行时,首先到叫号机处领取号码进行排队(进入队列)并等待。然后,当前面的储户办理完业务后就可以到相应的窗口办理业务(退出队列)。事实上,这种方式在现代生活中随处可见。
在LabVIEW中至少有两种实现消息队列的方法。如图 6所示。前者使用数组函数实现队列元素的入列和出列;后者使用队列函数实现队列元素的入列和出列。二者都能够实现队列的有序操作和状态的序列变化。
图 6 消息队列型状态机模式
本节解决了基本状态机模式中的(1)~(3)个问题,为了更好地比较和使用这些特点,特使用一个实例说明消息队列型状态机的使用过程。
【应用2】
本例要模拟一个自动贩卖机的工作过程。它的一次正常交易过程为:投币→选择需要购买的商品→找币,当币值不足或商品已经销售完毕时则无法购买。
程序的前面板如图 7所示。在贩卖机的左上侧有4个按钮。- 1USD:单击时表示投入1美元的货币,2USD和5USD类同;
- Change Back:表示找零,也就是将目前剩余的货币退还给用户。
本例将使用本节介绍的消息队列状态机模式解决这个应用(也可以使用其它的设计模式)。系统的功能并不复杂,关键是要判断贩卖机中的剩余钱数和剩余的货物数以决定交易是否成功。
图 7 自动贩卖机前面板
程序背面板如图 8所示。系统分为5个状态,并分为2大类。 [p]
- 第一类:Initial
- UI Initial:前面板界面的初始化。
- Data Initial:数据的初始化。
- 第二类:System
- Idle(Default):空闲状态。
- CheckMoney:贩卖机中的剩余钱数和剩余的货物数以决定交易是否成功。
- Exit:退出程序。
图 8 自动贩卖机背面板
在UI Initial中,系统给标题栏和说明栏赋值,并将前面板的商品设置为不可购买状态,因为在初始化时还没有完成投币动作。如图 9所示。
图 9 UI Initial分支
在Data Initial中包含两个共享的数据:Money和GState,前者表示贩卖机中剩余的币值,初始化值为0;而后者表示贩卖机中各个商品剩余的数量,初始化值为20。数据使用移位寄存器传递以便于在各个case分支中共享和使用,如图 10所示。
图 10 Data Initial分支
CheckMoney分支主要是为了防止不合法的交易(如投入的币值不足或商品数量不足),如图 11所示。
图 11 CheckMoney分支
当程序运行到Exit分支时,将停止循环并退出程序,如图 12所示。
图 12 Exit分支
Idle分支用来监控前面板各个按钮控件的变化并执行相应的状态。该分支比较复杂,当检测到第0个按钮被按下时(即1USD按钮),贩卖机中的货币值应该加一,同时需要判断是否达到了交易条件(即进入CheckMoney状态)。其它的状态可以执行相应的代码即可,这里不再重复解释。
图 13 Idle分支
从本例可以看出,相比基本状态机而言,尽管程序的复杂度增加了,但是在构建大型的应用程序时也更加地健壮,代码也易于维护和查看。