完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
写好 labview 程序的利器(四): Event Producer/Consumer 前一篇文章谈到的是如何利用 Functional Global Variable 来将程序功能模块化,在这种概念下,写程序就不再是边写边改,而是一开始就可以先规划好程序里面需要用到哪些功能,接着才将这些模块一个一个写出来。
同样以红绿灯的程序为例,首先需要一个红绿灯的模块,它必须要有初始化、更改亮起的灯号,以及读出目前红绿灯状态的功能。如上图, State 用来设定模块要执行哪一个程序,当执行 Write 时,输入的 Light Command 可以指定要写入的灯号;而当执行 Read 时,则会将目前的红绿灯状态由 Traffic Light 输出。以下说明模块内部的程序码。 (1) Initial : 将初始值写入 Shift Register 。
(2) Write : 将指定的灯号设为 true ,并且写入 Shift Register 。
(3) Read : 将目前 Shift Register 的值读取出来显示。
其中可以注意到的是,我在这个模块里面加了 error in 和 error out 的接点。当有 error 发生时,里面的程序就不去执行,如下图所示。即使程序用不到这个机制,也可以藉由资料流来控管各个模块在主程序里面执行的先后顺序。
另外,程序里面还需要一个计时器的功能,它要可以去设定时间,并且等待到时间到达后,才继续去做下一件事。如上图,这个模块和秒表的功能相同,可以 Reset 将要等待的秒数写入,然后每隔一段时间去 Check 时间是否到达。以下是这个模块的程序说明。 (1) Reset : 将 Wait Time 以及目前起始的时间写入 Shift Register 。
(2) Check : 检查目前经过的时间是否到达设定的 Wait Time 。
当写好所有需要用到的程序功能的模块后,接下来就是选择一个 Design Pattern 来当作主程序的架构。其中最常被用到的是 State Machine ,初学者也较容易上手。但 State Machine 的架构下,即使不做事在 Idle 的状态下,程序也会不停的 Polling ( 轮询 ) 去确认按键有没有被触发来改变状态,资源被平白浪费掉了。 而比较好的写法是 Event Producer/Consumer 的架构,如下图。在这种程序架构下,只有当使用者去触发按键时, Producer 才会将指令排入 Queue 里面,接着 Consumer 才会去执行任务,而平时两个循环并不会执行程序。接下来教大家如何把前面写好的模块加入 Event Producer/Consumer 的架构。
首先在人机界面上,要可以提供使用者自行输入灯号的顺序,以及停留的时间,如下图。
接下来就要把要亮起的灯号,以及等待时间写入 Traffic Light Module 和 Timing Module 中,但很明显的这两者的资料型态不一样。解决的方法是在一开始定义 Queue Element 的资料型态中,将两个不同的资料型态和 State 用 Cluster 包起来传递,如下图。
不过这种作法很容易当程序里面有一大堆不同的资料形态要进行传递时, Cluster 会越来越大而难以管理。但其实除了 State 之外,传递资料时同时只会有一种资料型态输入至模块,所以更好的做法是使用 Variant 来传递资料。当 Producer 下了一道指令 ( State ) 和资料 ( Data ) 时,都将资料转成 Variant ,而 Consumer 收到指令后再将其转回特定的资料型态。如下图,将 Queue State ( Enum Control ) 和 Data ( Variant ) 用 Cluster 包起来做为 Queue element 的资料型态。
在 Producer Loop 里面的 Event Structure 设定当使用者按下 Start 按键即触发,接着会把使用者输入的灯号顺序 Commands 用 For Loop 将 Array 拆开,然后再用 Unbundle By Name 解出要亮起的灯号 ( Light ) 以及停留时间 ( Wait ),分别用 To Variant 包进 Queue Command 里面再 Enqueue 排入序列当中。所以这边做的事就是下指令给 Consumer ,让它先去执行 Write 改变灯号,然后再 Reset 计时器并写入 Wait Time ,让它等待时间到达后再去做下一件事。
在 Consumer Loop 中,当它收到指令后,会先用 Unbundle By Name 将 Element 解开,然后根据里面的 State 来执行指定的任务。例如前面 Producer 先下了一个 Write 的指令, Consumer 在这个状态下会先用 Variant to Data 转回原本的资料型态,然后再写入 Traffic Light Module 更改亮起的灯号。接着要去更新人机界面上的红绿灯,所以后面再插队排入 Display 的指令。虽然 Queue 里面还有 Reset 的指令,但它就会优先执行完 Display 的指令再去处理后续的任务。
在 Display 的指令下, Consumer 会去读取 Traffic Light Module ,然后更新人机界面上的红绿灯。
在 Reset 的指令下, Consumer 同样要先将 Data 用 Variant to Data 转回原来的资料型态,然后再将 Wait Time 写入 Timing Module 中。接下来因为要去检查是否已经到达等待时间了,所以同样以插队的方式排入一个 Wait 的指令,让 Consumer 预先去执行。
在 Wait 的指令下, Consumer 会去检查 Timing Module 是否已经到达等待时间?若还没到达,则预先排入 Wait 的指令,让它继续去检查;若已经到达等待时间的话,就预先排入一个 Initial 的指令,让灯号初始化。
Initial 的指令会初始化红绿灯,将灯号全部先关起来,然后同样去更新人机界面的红绿灯。通常在程序一开始,会先做初始化的动作,而在这个架构下, Initial 变成一个指令。除了一开始就可以先 Enqueue 进去一笔 Initial 的指令之外,在程序执行中随时都可以去下 Initial 的指令来做初始化。
程序停止也是由 Producer 来控制,新增一个 Stop 按键触发的 Event ,当使用者按下 Stop 时, Producer 就会送出 Stop 的指令。 |
|
相关推荐
11 个讨论
|
|
|
不错的资料~~~~~~~~~~学习了~
|
|
|
|
|
|
|
|
你正在撰写讨论
如果你是对讨论或其他讨论精选点评或询问,请使用“评论”功能。
211 浏览 0 评论
请教大神,在labview里面对实时扫描资源中的C系列模块NI9234进行配置发生非预期错误
1709 浏览 0 评论
1585 浏览 0 评论
LABVIEW 2023 Q1调用python后一直报错1671
1960 浏览 2 评论
5207 浏览 3 评论
/9
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-12-2 14:52 , Processed in 1.447847 second(s), Total 74, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191

淘帖
4080