写好LabVIEW程序不可不知的利器(三):进阶应用
前两篇主要想传达一个写 LabVIEW 程序的概念,也就是要将常用到的功能包成Sub VI 。写程序不再只是将所有程序码写进一个 Loop 里面,而是开始写程序前会先规画好需要哪些程序功能,以及适合运用哪种 Design Pattern 的架构。今天要谈的是更进阶的方法,不仅将程序模块化,连程序功能也一起加进去。
除了 Data Flow 的概念,在 LabVIEW 里面另外一个很重要的概念就是 Shift Register 。一般初学者在学到 Shift Register 的时候,只知道 Shift Register 可以用来传递资料到下一次循环,以及程序执行一开始要先对 Shift Register 初始化,否则 Shift Register 内部会保留上一次程序执行结束的资料。但其实 Shift Register 只是 LabVIEW 帮我们预先规画好的存储器区块,我们可以随时随地去初始化、写入或读取里面的资料,进阶的用法就是 Functional Global Variable 。
将上图的程序架构包成 Sub VI 就是一个可随时随地被呼叫使用的 Functional Global Variable ,其有以下特点:
(1) 只执行一次的 Loop 。
(2) 未初始化的 Shift Register 。
(3) Enum Control 和 Case Structure 。
(4) 禁止 Reentrant execution 。
看起来 Functional Global Variable 和一般常用的 Local Variable 或 Global Variable 的功能很像。但不同的是 Functional Global Variable 本身就是一个 Sub VI ,所以在 VI Properties 中的 Execution 可以去设定是否允许 Reentrant execution ,而预设值是取消的,如下图。
在禁止 Reentrant execution 的状态下, Sub VI 可以随时随地使用,但如果同时有两个人在呼叫它的时候,并不会同时写入资料,而是会排队等先呼叫的人执行完,另一个人才能进去使用它。如此可避免同时去读写资料而造成 Race Condition ,甚至可以在程序里面增加功能去纪录资料是在何时何地被读写的。
接下来同样沿用前两篇的红绿灯程序来做为范例,在开始写程序之前,先规划一下会需要用到那些功能模块。首先是要有一个可以写入红绿灯状态并且可以读取显示的模块,另外就是要有一个计时功能的模块,设定好时间后,会等到时间到了再执行下一个动作。下面我会将这两个模块先写成 Functional Global Variable ,如下图。
上图是 Timing Module 的程序,在 Reset 的状态中,会将输入的 Wait Time (s) 以及将目前时间当作 Start Time 写入 Shift Register 中。
在 Check 的状态中,每次会等待 50ms ,并将目前的时间减掉 Start Time 计算经过时间,再与一开始设定的 Wait Time 相比较,输出为是否到达时间 Done ?
上图是 Traffic Light Module 的程序,其中 Shift Register 内存放的是红绿灯的状态, State Control 指定执行的方法,最后会输出下一次要执行的状态 Next State ,以及目前状态要等待的时间 Wait Time (s) 。当执行 Read 状态时,会将 Shift Register 中的资料读取出来并输出。
上图是红绿灯执行的流程,一开始会先初始化红绿灯,接下来亮红灯并停留 2 秒,接着亮黄灯并停留 1 秒,最后亮绿灯并停留 3 秒。
看到这边大家应该会有似曾相识的感觉,没错这是 State Machine 的写法,但是又会困惑为何循环每次只执行一次。因为接下来要示范的是 State Machine 的另外一种写法- Queued State Machine 。
主程序如上图所示,是由 Queue 所架构而成的,其所传递的 element 为主程序执行的状态 Queue State 以及 Traffic Light State 所包成的 Cluster 。而在程序一开始就预先 Enqueue element 进去一笔 Write 的指令,将 Traffic Light Module 状态设定为 Start 。当程序执行 Write 指令时,会将 TL State 写入前面所写好的 Traffic Light Module ,并且将 Wait Time 设定于 Timing Module 。再将 Read 的指令以及 Write 设定红绿灯的 Next State 的指令先后排入 Queue 里面。
接下来执行 Read 指令时,会读取目前红绿灯的状态并且更新界面上的 Indicator 。此时在 Queue 里面还有一笔 Write 的指令,是要将红绿灯的 Next State 写入。但我们必须等 Wait Time 到达时才能执行,所以就要使用 Enqueue Element At Opposite End 将 Wait 的指令插队排到 Write 之前来执行。
而在 Wait 的状态中,会去 Check 时间是否到达 Wait Time 了?如上图,如果时间还没到,同样将一笔 Wait 的指令插队排入 Queue 里面。当时间到达时,才不将 Wait 的指令排入,此时先前排入 Queue 里面 Write 指令就会在下一次循环执行。
整个程序的流程就会是 Write (更新红绿灯) -> Read (读取红绿灯) -> Wait until time done -> Write …… 循环。而在这次的程序中所写的两个 Functional Global Variable 除了可以储存资料外,它还可以将一些程序的功能或方法写进去,程序写起来较为弹性,像这次就把 State Machine 给一并写了进去。
转载
支持哦
这个很好,谢谢.
学习学习,谢谢小编!
这个有没有原程序呀,
在read 的状态下, 下一个状态还是read吗?
另外write的状态下的子条件框又的什么呢?
还请小编回答哦
多谢分享!
这个很好,谢谢.
学习学习,谢谢小编!
支持 连载 ,谢谢分享、