0cebd6decd7931b765ce0508763231126fdb7730.docx
- 文档编号:25734733
- 上传时间:2023-06-12
- 格式:DOCX
- 页数:148
- 大小:3.31MB
0cebd6decd7931b765ce0508763231126fdb7730.docx
《0cebd6decd7931b765ce0508763231126fdb7730.docx》由会员分享,可在线阅读,更多相关《0cebd6decd7931b765ce0508763231126fdb7730.docx(148页珍藏版)》请在冰豆网上搜索。
10年Labview编程经验
当我开始在键盘上敲打出这句话的时候,我已经使用LabVIEW7年了。
7年的时间,就算天赋平平也可以积攒下一箩筐可供参考的经验了。
所以我打算利用今后的闲暇时间写一些这方面的东西,既可以同大家交流,也是作为自己这七年工作的总结。
还是在上大学的时候,有一次老师让编写一段软件,用来模拟一个控制系统:
给它一个激励信号,然后显示出它的输出信号。
那时我就想过,可以把每一个简单的传递函数都做成一个个小方块,使用的时候可以选择需要的函数模块,用线把它们连起来,这样就可以方便地搭建出各种复杂系统。
后来,我第一次看到别人给我演示的LabVIEW编程,就是把一些小方块用线连起来,完成了一段程序。
我当时就感觉到,这和我曾经有过的想法多么相似啊。
一种亲切感油然而生,从此我对LabVIEW的喜爱就一直胜过其他的编程语言。
LabVIEW的第一个版本发布于1986年,是在Macintosh机上实现的,后来才移植到了PC机上,并且LabVIEW从未放弃过对跨平台的支持。
这也给LabVIEW带来了一些麻烦。
最明显的就是LabVIEW开发环境的界面风格。
它总是与一般的Windows应用程序有些格格不入:
面板是深灰色的,按键钮是看起来别别扭扭的3D模样。
还有一些可能不太容易发现:
比如对于整数的存储,LabVIEW即便是运行在x86系统上,采用的也是高地址位存高位数据(big-ending)。
这与我们习惯了的x86CPU使用的格式正相反,这往往给编写存取二进制文件带来了不多不少的麻烦。
我接触过的最早的LabVIEW版本是4.0版,发布包是一个装有十几张三寸软盘的大盒子。
安装的时候要按顺序把软盘一个一个塞到计算机里。
尽管当时LabVIEW的界面不是很好看,但我还是非常喜欢它。
真方便呐!
比如说要画一个开关,用LabVIEW一拖就行了。
如果要自己动手用C语言设计一个好看的开关,,那得费多少时间啊!
我尤其喜欢它通过连线来编程的方式,尽管很多熟悉了文本编程语言的人刚开始时会对这种图形化编程方式非常不适应。
从4.0到现在的8.2,LabVIEW的一些技术革新给我留下了非常深的印象。
比如说LabVIEW5中实现了多线程运行;LabVIEW6里漂亮的3D控件,和对事件响应的支持;LabVIEW7中的ExpressVI以及LabVIEW8中的工程库。
这些新特性都已成为了现在LabVIEW版本中富有特色并不可缺少的一部分了。
我对使用LabVIEW编程的认识在这些年里经历了不少转变。
刚开始接触LabVIEW的时候,第一印象就是觉得这东西编程序比C语言简单多了,尤其在设计界面时确实方便简易。
LabVIEW是一种真正意义上的图形化编程语言。
与文本编程语言,如C、Basic等相比,它在编程过程中有更详细的提示信息,如函数的功能、参数类型等等,程序员再不需要去记忆这些枯燥的信息了。
编写风格良好的图形程序代码要比文本代码更加清晰直观,便于阅读。
刚开始用LabVIEW编程时,我连一本相关的书籍都没读过,差不多完全靠自己摸索。
当时,市面上几乎没有有关LabVIEW的中文书籍,而阅读英文资料又感觉得太累。
但是,靠自己摸索的方法也有好处,最明显的就是有成就感:
自己琢磨着解决了一个问题,比模仿别人的方法做更令人兴奋。
再者,他人的方案并不一定是最佳的,自己独自思索就不至于被他人的方案局限住思路。
当然,我不会满足于只用LabVIEW编写一些简单的程序。
我还希望能够用它来编写大型的软件,并且提高自己的开发效率。
这时,自己的编程水平有一个质的提高,不阅读相关的书籍资料就不行了。
有些问题,不读书,自己可能永远都得不到最佳的答案。
同样,有些LabVIEW的功能,如果不阅读原始资料,自己也许永远都掌握不了。
于是,我把能得到的LabVIEW的中高级教程都看了一遍。
因为自己有了一定的基础,我就可以在读书的过程中反思自己以前的编程方法是否合理,高效。
我觉得最好的LabVIEW教程还是NI自己编写的LabVIEW中高级教程。
但书本中一般原理讲得多,具体的编程技巧涉及得少,所以还必须大量阅读别人的代码,才能学习到更多更好的编程方法。
随着时间的流逝,我慢慢地产生了LabVIEW应当进一步改善的想法。
作为一名忠实的LabVIEW语言的使用者,我衷心地期望着LabVIEW在日后也可以成为一种被广为使用的通用编程语言,能够在更广泛的领域与C,Java等争得一席之地。
LabVIEW虽然有它独特的优势,但其不足之处也很明显。
我在编程过程中就曾感觉到它很多的使用不方便之处。
下一步,我追求的目标就是能尽自己所能,对LabVIEW作一些改进和完善,使它更适应于通用编程之用。
如何学习LabVIEW
根据我自己的观察,学习LabVIEW一般有以下三种方式:
系统型学习方法、探索型学习方法和目标驱动型学习方法。
这三种方法之间并不矛盾,可以在不同的时段使用不同的方法。
每个人可以根据自己的个性特点和所处环境选择一个适合自己的学习方案。
系统型学习方案是传统的学习方法,学生学习多是按此方法。
它是指按照别人制定好的学习方案一步一步学习掌握一门知识。
学习效果如何,主要取决于教师和教材的水平。
若选此方案学习LabVIEW,最高效的方法莫过于参加NI公司的LabVIEW培训课程。
基本上,完全没接触过LabVIEW的学员可以在一星期的时间内达到编写简单程序的程度。
此外,现在很多大学都开有LabVIEW课程,方便了在校生学习。
自学也可以采用此方案。
找一本教程类的书籍,按照书中指导一步一步学习。
教程类的书籍应当侧重于解释LabVIEW的编程思想以及原理;有些书仅偏重于罗列LabVIEW中每个函数或VI的功能,则不适合用于此种学习方案。
探索型学习方法适合喜好自己钻研的人。
同样一个技巧,如果是自己发现的,比从他人那里的来会更有成就感。
任何一个教程都不可能覆盖到LabVIEW的全部功能,有心得学员不妨自己打开书中未曾介绍到的那些菜单或者函数选板,尝试一下它们都是做什么用的。
在真正动手摆弄每个新东西之前,打开LabVIEW的即时帮助窗口,阅读一下相关说明可以大大加快学习过程。
比如,打开“应用程序控制”函数选板,发现这里有一项“选板编辑”。
好像没有任何一本书里介绍过这个功能嘛,这是干啥用的呢?
如果没任何提示,也是无从下手去尝试的。
打开LabVIEW的及时帮助,可以看到它对这个功能的简单介绍。
进入“详细帮助信息”,会得到更全面的说明。
再自己动手实践一下,就基本可以掌握此功能了。
阅读他人代码也是一个很好的学习方法。
自己的探索总是有思维局限性的,他人解决问题的方法可以大大拓宽自己思路。
我介绍过的编程经验中,很大一部分都不是我自己凭空想出来的,而是借鉴与别人的LabVIEW代码。
目标驱动型学习方法是公司员工中最常见的学习方式了。
工作后,如果不是个人有兴趣,多数人不会浪费时间去学习工作中用不到的知识。
等老板布置了具体项目或者工作任务后再学习相关知识,效率更高。
学也只要够解决眼前问题就行了。
针对这种情况,请教身边牛人或者公司前辈是最好的学习方法。
如果周围的人不能解决问题,到论坛上发贴,寻求更广泛的帮助。
推荐一个论坛。
首先是NI的官方论坛,这里会有NI的技术支持和研发工程师来回答问题。
如果英文够好,最好是到它的英文版面去提问,英文讨论区人气更旺,容易找到答案。
LAVA是官方之外最大的LabVIEW社区,也是寻求帮助的好地方。
如果平时用WindowsLiveMessenger,可以加入,这是个msn讨论LabVIEW的群。
在它上面讨论问题最大的好处是可以及时得到回应。
我见过几个工程师在项目中遇到了难题,于是来报名参加LabVIEW的培训课程,以为上完课可以解决自己的问题。
但实际上完全误解了培训课程的意义,培训课程是为了帮助那些想要系统学习LabVIEW知识的人,而不专注于任何一个具体问题。
LabVIEW工程资源管理器
从8.0开始,LabVIEW增加了一个工程资源管理器功能。
LabVIEW工程资源管理器就是一个可以方便查看、调整程序系统结构的工作区。
与VC,VB等语言中的project,workspace相类似。
Project的出现使得LabVIEW对于大项目的管理更加方便。
图1:
LabVIEW工程资源管理器
要想充分利用LabVIEW工程资源管理器带来的好处,那就需要我们改变一些以往的LabVIEW编程习惯。
譬如说,在开始一个新的项目的时候,在LabVIEW8以前的版本中,我们最先创建的是程序的主VI;而现在,我们首先创建的应该是一个空的工程(Project),再在这个工程中添加相应的VI和各种组件。
工程管理器还有如下优点:
工程的树形结构表示了程序中VI的调用层次关系,利用VI的快捷菜单可以查看到调用该VI的程序,以及该VI的子程序,而不必再使用VIHierarchy来查看。
在工程资源管理器的File页就可以直接调整文件存放的磁盘位置,而不必再另外打开操作系统提供的文件浏览器。
在工程资源管理器中集成源代码管理功能,不需要再使用源代码管理工具提供的界面了。
(源代码管理工具是用来进行软件源代码版本控制的。
大型软件开发通常需要这样的工具,用来记录每一次代码的修改、同时开发同一软件的不同版本、方便多人同时对同一段代码进行修改等。
)
一、工程的结构
图1是一个工程资源管理器的截图。
它用一个树形的结构来表示工程中所有的VI、各种组件和文件设置等。
树形结构的最顶层是工程的名称。
第二层是工程运行的目标机器。
假如我的机器上只装了普通台式机版本的LabVIEW,大家只能看到一个目标:
“MyComputer”。
假如我的计算机上还装了LabVIEWRT,FPGA等用于其它硬件环境的LabVIEW,那么在这一层还会出现其它那些目标设备。
第三层以下就是工程中所有使用到的文件了。
用户可以添加虚拟文件夹,按自己的喜好组织文件结构。
LabVIEW从8.0起,文件及其它组件种类一下子丰富了许多。
以前基本就只有VI和控件两种文件,现在又多了Library,Class,XControl,XNode,共享变量等等。
安装了其他功能模块,组件的种类还会更多。
右击树状结构中的每个条目,还可看到针对他们的更多设置。
在LabVIEW8之前,若要把VI源文件构建成可执行文件,必须使用Tools菜单下的APPBuilder工具。
现在这个工具也被集成到了工程管理器中。
在目标机器的最后一个条目“BuildSpecification”中包含了把源代码配置成为EXE,DLL等的信息。
在旧版本LabVIEW中,保存VI时的一些高级选项,比如添加密码、移除VI前面板,程序框图等选项;以及其它一些与运行有关的选项,例如禁止调试,自动弹出错误框等选项,也都被合并到此处了。
在BuildSourceDistribution中可以找到相应的设置。
在旧版本LabVIEW中,是绝对不允许把两个文件名相同,但内容不同的VI同时装入内存的。
这也可以理解,VI就好比是C语言中的函数,如果两个函数名相同,那到时究竟应该使用哪一个呢?
但这毕竟不方便,比如我们需要同时运行两个程序,他们当中都有排序的功能。
为了方便,VI的名字都起名为“Sort.vi”,但是他们的代码其实并不相同。
为了让两个程序同时正常工作,我们应该允许在这两个程序内分别使用两个文件名相同,但内容不同的VI。
在版本8中,LabVIEW对此作了两点改进,一是引进了库的概念,类似给VI增加了名字空间。
在不同的库中的VI,即时文件名相同,它们的VI名字实际上也是不同的,因为VI名还包括库名作为前缀。
(可以参考:
)
二是增加了运行环境的概念。
LabVIEW中,每一个工程都是一个独立的运行环境。
为每一个的程序建立一个单独的工程,它们就有了一个独立的运行环境。
一个运行环境中的VI不会影响到其它运行环境中的程序。
这样,同时运行分属不同工程的两个程序,它们之间即便用到了同名的VI,也不会相互影响。
但在单个工程中,还是不允许出现同名又不在库中的VI。
二、按照文件的物理结构来查工程
在需要创建一个新的类似工程,或版本备份时,程序经常被来回复制。
在这个过程中,很可能会引起子VI的错误链接。
比如,本来工程里应该使用的的是ProjectOne文件夹下的一个子VI,但实际上却链接到了ProjectTwo文件夹下的一个同名VI。
我们可以把文件的真实路径同时显示在工程资源管理器的Item,以及File页上,选取菜单Project->ShowItemPaths,如图2所示。
我们可以在这里检查每个文件的路径是否正确。
但是,文件比较多的时候,一条一条看下来,是比较麻烦的。
这时可以按照文件的物理结构来查看工程中的文件。
在工程资源管理器中选择“Files”标签页,看到的就是文件在物理硬盘上的真实结构。
我们只要在这里检查一下,有没有不需要的文件夹出现,就可以判定是否出现了错误链接。
如果发现某些文件所存放的路径不恰当,需要调整,我们可以直接在工程资源管理器中来调整,而不需要打开文件浏览器去修改。
图2:
按照文件的物理结构查看工程
三、VI交叉连接
前文提到程序可能会错误的链接子VI,这在LabVIEW中被称为VI的交叉链接。
除了前面提到的可能引起交叉链接的情况外,试图调用重名的VI,或把它加到工程里来等操作,都会引起VI的交叉链接。
VI的交叉链接会引起很多问题,比如你在修改VI的时候,改动了不应该改动的那份;引起程序不可预知的行为等等。
LabVIEW的工程资源管理器可以帮助检查、修复VI的交叉链接。
当工程资源管理器发现程序中试图使用两个同名VI时,就会在这样的VI上打出一个惊叹号。
如图2中所示的SubVI.vi。
工程中试图用到了两个同名的VI,分别在路径ProjectOne和ProjectTwo下。
你可以到引用这些VI的地方去把他们一一修正,也可以让工程资源管理器来修正它们。
回到“Item”页面,在有惊叹号VI上点击鼠标右键,选择ResolveConflicts。
这时候,就会出现修正冲突的对话框。
在这个对话框中选择应该被选用的正确子VI,工程资源管理器就会自动更新程序,使它们链接到正确的VI上去。
如何创建和使用LabVIEW中的LLB文件
最近接连有人问我,怎样在LabVIEW中创建一个LLB文件。
于是我就把它写了下来。
通常,需要新建一个文件时,我们很自然就会想到去选中菜单“File->New”。
可是,在LabVIEW8中,在“新建”菜单中是看不到LLB这种文件类型的;要创建或者管理一个LLB文件,首先要选择“Tool->LLBManager...”。
在打开LLBManager之后,再在菜单中选择“File->NewLLB”。
这样才能创建一个新的LLB文件出来。
我个人认为,在LabVIEW8及以后的版本中,LLB文件现在已经没有存在的必要了,使用它,弊大于利。
LLB文件的功能就是把一组相关的VI以及其他文件打包存储在一起。
其优点是节省磁盘空间,LLB文件是压缩了的。
但是,近年来计算机存储介质的容量迅速膨胀。
LabVIEW程序的存储空间再也不是一个需要考虑的问题了。
所以这方面已经不再有诱惑力了。
LLB文件有很多弊病。
1.内部文件没有层次关系,所有文件都是平级存放的。
这样一来,文件多了,就不能直接看出他们的调用关系。
此外,LLB也允许有同名文件存在。
2.内部文件名长度有限制,大概限制几十个字符吧,文件名太长会被自动截断。
3.不利于版本管理。
LLB中的一个文件被修改,整个LLB也就被修改了。
这样,一是没办法作增量存储,二是不容易定位到具体被改动了的文件上。
综上所诉,如果新建一个工程,最好不要考虑使用LLB文件了。
同时为了方便管理工程中的文件,应当尽量利用LabVIEW8的新功能:
Project和Library。
在VIProperties->Execution中可以选择VI的ReentrantExecution属性(中文译为:
可重入执行)。
我们在《LabVIEW程序的内存优化》一文中讨论过,尽量不要把VI设置为重入属性,因为这样就多占用了内存,降低了运行效率。
此外,如果不加注意的话,还可能引发多线程不安全的问题。
尽管可重入VI在LabVIEW中不是必须的,但是在某些情况下使用可重入VI可以简化我们的程序。
那么在什么情况下可以使用ReentrantVI呢?
首先看一下图1所示的程序,程序中调用的两个子VI是同一个VI,并且不是可重入的VI。
LabVIEW是自动多线程的语言,那么图中的两个子VI会不会同时执行呢。
一定不会的。
如果程序中调用的是两个不同的子VI,LabVIEW有可能会同时在不同的线程执行它们,但对于两次调用相同的子VI,LabVIEW一定要等一个执行完,再执行另一个。
图1:
并行的两个相同子VI
其原因是,LabVIEW会为每个VI都开辟一块内存用于数据存储。
作为子VI,每次被调用,它的局部变量的数据都是被存在同一地址的。
与C语言相对照,在默认情况下,VI是不可重入的,VI中所有的局部变量都是静态变量。
如果LabVIEW在不同的线程下执行同一VI,那么两个线程就会同时对这一块数据地址进行读写,就会导致这一块地址内数据的混乱。
为避免此类不安全情况的出现,LabVIEW必须等待一个子VI执行结束,再执行另一个子VI。
如果需要图1中的两个子VI同时运行,比如子VI所做的工作是读取文件这样一类耗时多、但CPU占用不大的操作,则并行执行可以大大提高效率。
这时,就需要把子VI设置为可重入了。
LabVIEW在不同的地方调用一个可重入VI时,会给它另外分配一个独立的数据地址空间。
这样就做到了线程安全。
在两个线程执行的子VI使用两份在不同的地址存储的数据,也就不会造成混乱。
但是千万要注意,这个“在不同的地方”调用:
不可重入的VI的局部变量与C语言中非静态变量的含义是不同的。
在后面提到的计数器的例子可以验证这一点。
我觉得我说得挺清楚了,出道题目给大家测试一下:
图2:
延时子VI
图3:
计算延时的主VI
图2是一个子VI的代码,功能是延时1000毫秒。
图3是主VI的代码,并行调用同一子VI两次,并计算程序的执行时间。
运行主VI,totaltime的值是多少?
答案在文章最后。
这是可重入VI的一种用途,即希望在不同的线程里同时执行同一个子VI。
另外还有一种情况下,也可以用到可重入VI:
即需要使用到子VI中局部变量保存的数据,而在不同的调用处,这些数据是独立不同的。
这句话可能解释得不那么清楚,看下面例子就会比较容易理解些。
图4:
计数子VI
图5:
测试计数的主VI
图4是一个可重入子VI的代码,功能是计算这个VI被运行的次数,每运行一次,输出的count值就增加1。
图5是调用它的主VI,用于演示这个计数器。
执行主VI一次,output1和output2的值分别是10和20,表示这个子VI在两处分别被调用了10次和20次。
如果把图4中的VI改为不可重入,则output1和output2的输出值是不确定的。
大家可以自己试一试,再想一下原因。
当使用递归结构时,参与了递归调用的VI是需要被同时调用多次的。
因此这些VI中的变量必须是局部的,也就是说参与了递归调用的VI必须都被设置为可重入。
参考:
在LabVIEW中实现VI的递归调用
测试题目答案:
如果图2的子VI没有设置为可重入,则totaltime=2000;如果设置为可重入则totaltime=1000。
为了解释清楚,先定义一下要用到的概念。
我们把以.ctl文件名定义的控件叫做用户自定义控件,把通过拖拽或打开这个.ctl文件在VI上生成的控件叫做实例。
LabVIEW的用户自定义控件包括了三种定义形式:
打开一个.ctl文件,在它上方的“control”下拉条中有三个选择,分别是无关联控件(Control)、类型定义(TypeDef.)或者严格类型定义(StrictTypeDef.)。
无关联控件是指这个控件与它的实例之间没有任何关联。
例如,你制作了一个漂亮的按钮控件保存在.ctl文件中。
需要用到它时,通过拖拽或打开这个.ctl文件就可以在VI中生成这个用户自定义控件的一个实例。
这个实例一旦生成,就和原用户自定义控件无任何关联了。
无论是你修改这个实例,还是修改原用户自定义控件,都不会对另一方产生任何影响。
类型定义控件是指实例控件与用户自定义控件的空间类型是相关联的。
比如,你的用户自定义控件是一个数值型控件,那么它的所有实例控件也都是数值型的。
如果我们在.ctl文件中把用户自定义控件的类型改为字符串,那么它已有的所有实例都将自动变成字符串类型。
有时候,只是类型相关联还不够。
比如对于Ring(Enum,ComboBox)这类的控件来说,如果在用户自定义控件中添加了一项内容(item),一般总是希望它所有的实例也同时添加这一选项。
如果使用类型定义控件,因为控件类型没变,还是Ring,实例们是不会自动跟随更新的。
这时就需要使用严格类型定义控件。
选择严格类型定义后,不但实例与用户自定义控件的类型是相关联的,其他一些控件属性,比如颜色等等,也是相关联的。
使用严格类型定义时有一点容易被误解:
严格类型定义只是与实例控件相关联,由它生成的实例常量的属性是不与之关联的。
实例常量是指通过拖拽或生成常量等方法,在程序框图上生成的一个与.ctl文件相关联的常量。
比如在Ring型用户自定义控件中添加了一项内容,相关的实例常量是不会发生任何改变的。
很多人按常理想,认为常量也应当自动更新,但事实上不行。
这也是我不采用它做常量定义的原因之一。
(参见:
在LabVIEW中使用常量定义)
LabVIEW在8.0版对控件和函数面板作了一次较大调整。
LabVIEW功能越来越强大,控件和函数面板上的东西越来越多。
如果增加面板的嵌套深度,用户每次选取面板上的一个控件和函数都要多点几下鼠标,而且对不熟悉位置的东西找起来也相当费劲;如果扩充每一个面板上的容量,一个面板上图标太多,用户会眼花,也不利于查找。
所以LabVIEW8调整了面板的显示方式:
最顶层面板所有栏目都以文字的方式显示,纵向排成一列。
其中第一个栏目是默认就展开的,可以直接看到次级面板的内容;其它栏目都收起,鼠标挪上去,才看得到它里面的内容。
我现在用的是LabVIEW8.2版,它的函数面板看上去是这样的:
(在程序框图的空白处点击鼠标右键)
图1:
用鼠标右键弹出函数面板
函数和子VI被分为几大类,每个类的名字被列在弹出的菜单上,其
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- cebd6decd7931b765ce0508763231126fdb7730