本帖最后由 ZHZJK 于 2016-8-30 12:42 编辑
首先要介绍几种基本程序架构的特点。(废话可以略过)
1.状态机:将整个程序的功能进行分割。然后将各个功能像积木一样进行排列组合。形成一个堆叠的流程图。熟练使用状态机,会大大提高使用者的模块化意识。提高程序的灵活性和简介性。当然,追基本状态机是单线程的,写按钮控制也比较繁琐。
2.事件结构:事件结构其实算是比较容易上手的结构。通过各个事件实现相对应的程序功能及动作。事件结构其实更偏向于面向对象,熟练使用事件结构会有助于面向对象的理解。
不过事件结构要注意几点:首先,尽量不要在事件结构里做长时间的动作,尤其是while循环(当然能驾驭住不出问题,可以将就用)。接着,掌握不牢会导致程序的卡死。最后基本的事件结构也是单线程的。
3.消费者结构(队列):单说生产者与消费者,主要用于测量行业。一个循环进行实时采集,然后通过队列进行传输进行处理。保证采集和处理的效率。缺点嘛,这基本结构也太简单了吧,真完全照搬好像只适用采集项目。不过呢,消费者算初学者接触比较早的有规范的多线程程序了。
---------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------
下面正戏马上就要开始了,不过我要说下我讲的目的:
没有绝对完美的架构,也没有绝对差的架构。我想要传达的是一种对架构的理解,而非告诉大家要用某一种架构。而是希望大家慢慢去理解这内容。
1.从事件结构开始
假如你是初学者,我建议先学会使用事件结构进行编程吧。事件结构简单方便,发生什么事情做什么,十分形象。
让我们先用事件结构编写一个简单的登录操作程序吧。当然本篇并不是介绍事件结构的,所以不会太下笔墨。
首先,如上图,我们先建立个VI,添加个背景。
然后,建立个选项卡,建立两个面板,登录和主操作。
接着,为选项卡添加相应内容。
最后,我们透明掉选项卡。
这样我们界面就如下图初具雏形了。
接下来我们就要进行编程,实现以下功能:
1)点击确定按钮进行登录,用户名为admin,密码123。如果成功就跳转到主操作,失败弹出对话框。
2)然后点击主操作里面的确定按钮会退出
下面几张图就是具体的事件结构程序。
至此,我们就用事件结构写了个简单的程序。
此程序见 附件:事件结构.vi。
2.基础衍生
不要满足于事件结构,在我经手的第二个案子,很多按钮用簇打包好,但还是有4,50个事件。
每次打开事件结构都眼花缭乱。我就意识到,该去寻找一个新的架构了。
该怎么办呢,用子vi来代替选项卡???确实能实现,但作为探究者,我们就要用选项卡进行编程,该怎么办?
我当时想出了一个方法,用多个事件结构(事件结构非常危险,容易造成卡屏现象,不过对事件结构理解到一定地步也没什么大事)。
下面我们接着往下讲把。思路很简单就是将每个界面写成一个事件结构。
然后将每个事件结构放在不同分支里面。
如上图,我们进行编程,编写登陆和主操作两个条件结构,分别编写两个事件,将按钮操作分开。而且查找相应事件非常方便。
缺点,注意界面切换,如果界面切换时触发按钮事件,会卡死。
处理方法,将事件结构里面锁定前面板勾取消即可。(卡死具体原理涉及到NI事件结构本身的缺陷,等单独讲事件结构再说)。
3.深入研究
不能将执行时间过长的代码放到程序中;更改选项卡都要找很长时间;一些东西裸露在循环外一点不美观。等等,等等,都告诉我们要进一步完善我们的程序架构。
这时,我们要引入状态机到我们的程序。
如下图,我们利用状态机将我们程序分为各个状态:
每个界面或者每个大分类,我们都用带有”-----”的字符串作为该状态的初始化。
我们可以在”-----初始化-----”,”-----登录-----”和”-----主操作-----”这边做一些该程序的初始化操作。
例如:在”-----登录-----”里面,我们进行选项卡切换,用户名密码清零这些操作。如下图所示:
这样做的好处非常明显,程序看起来非常有条理,而且每次初始化或者里面的功能都会变的非常简单。
举个例子,如果我们登陆失败,我想将该界面的用户名和密码清空。
原来我们程序是不带有该功能的,现在我们要怎么办?方法就在下图:
我们在登陆失败后,执行”-----登录-----”状态即可。
该改版程序请见"结构1.vi"。
4.我不要单线程
说实话,上面程序都是单线程的,单线程的缺点非常明显------运行时间。运行时间过长的程序会造成程序的延时。影响同时也会影响我们该循环中的事件结构。
下面我们来把上面程序改成多线程的。在此处,我们要与消费者与生产者结合起来,编写一个状态队列的结构。
在这我们要建立两个循环,第一个用来触发事件,然后用队列将触发的状态传送到第二个循环中。第二个循环则是一个接收队列状态的状态机。
具体程序架构会如下图,这也是现阶段比较流行的架构了。
其实上面架构比单线程好点,但在很多时候两个循环是完全不够用的。
例如,我们有两个要采集数据的硬件,两台机器数据传输都占用大量时间,这时我们就要为两个机台数据传输单独开辟线程,因为队列也是变相的单线程。
如果只用一个,会导致状态堆积,程序的延时,而造成各种各样不必要的bug。
下图就是该结构的原始框架:
当然这只是一个原始框架罢了,在labview自带的项目模板”队列操作处理器”就是该架构的自带项目模板。有兴趣的可以去研究研究。
该程序请看附件”队列状态机.vi”。
5.动态调用
不得不说的是labview里面的动态调用,那才是真正的多线程操作。该结构先前开贴大概讲了下就不多做讲解了。具体内容看下面地址
https://bbs.elecfans.com/jishu_568849_1_1.html
6.骨架要好,皮囊也要美观
好的架构是就像好的骨架,但决定作用还是属于皮囊与血肉。
我们可以将主程序的程序框图叫做第一程序界面。在第一程序界面里面,我们应该展示的是我们的整个程序的流程与思想。
Labview最大优点是啥,快速,图形化还是易上手?不不不,这些都不能算大优点,最大优点就是可视化。对可视化,好的程序应该一眼看下去,就明白流程。其中哪个流程不明白,再点开又一目了然。
在第一界面上,我们不要了解是如何去判断能否登录的。我们只要知道,按钮按下,我们进行登录,登录成功我们会到下个操作。至于其中细节,不应该是主程序的主要功能。
另一点要讲的就是程序总线处理。
要想长成参天大树,决不会在很低的地方就进行分叉。同样程序处理也是。就拿错误处理来说,当出现错误,很多人人会立马跳出会话框,说某某错误,怎么怎么样。
但按照我们程序总线来说,我们不应该立即去处理他。而是让他往下走,走到一个程序错误讯息搜集器那边。然后搜集器将错误统计,将错误进行分类,过滤,然后对程序其他地方进行控制。例如:控制三色灯,界面按钮禁用,隐藏等等。
好了,程序架构讲解下半章就这样讲解完了。希望对架构不了解的朋友能够理解。
程序架构不是天马行空,它必然是脚踏实地,慢慢发展而来。
队列状态机.vi (19.01 KB, 下载次数: 65)
结构1.vi (164.37 KB, 下载次数: 59)
结构2.vi (172.52 KB, 下