Palette API

    对函数和控件面板的调整,并不是只有手工调整着一个方法。LabVIEW 8.6 中提供了在程序中修改函数和控件面板的 API。通过这些 API VI,用户就可以在程序里读取或设置 .mnu 文件里的内容,从而通过编程来改变函数和控件面板。
   

美国有些商场刷信用卡是直接使用人民币结算的

    我在美国一直使用我国内的双币信用卡,一直是按美元结算的。前些天我帮人在 Dillard’s 买了一个化妆品,一看收银条,就然写着人民币多少多少钱。几天后查信用卡的记录,果然是直接从人民币账户扣款的。它的汇率是按照7.9几计算的,不知对我们用户来说是否划算。

在美国喝酒

    中国人都知道美国自由,美国的确实不像中国有那么法律法规限制个人自由,而且国家不会滥用法律惩罚不听领导话的公民。但是,已有的法律规章,在美国执行起来比在中国要严肃和严格的多。
    我以前就听说在美国只有成年人才能买酒,但是我自己不喝酒,所以也从来没见识过他们怎么执行这条法律的。昨天,几个同事一起去公园烧烤,有个同事非要喝啤酒不可,于是我们就到超市拿了一打。但是当店员朝我们的“酒鬼”要驾照的时候,他才发现自己没带护照,店员不认可它的中国身份正。另一个美国同事带了驾照,问店员就算是她买的行不行,但是店员还是不同意。没办法,我们只好换了一家店,由那个美国同事自己进去买了一打出来。
    在公园了,我们正吃的高兴的时候,突然就冒出来两个警察,对我们说:这里是公共场合,不能饮酒。因为我们是初犯,认错态度又比较好,就警告一下,如果一会再看到我们喝酒,就要罚款了(好像每个人几十块钱,具体数字忘了)。
    我们赶紧吧酒瓶友都收回到冷藏箱里去了,还是留着回家自己偷摸喝吧。

《生活随笔》

编辑

在文件夹下直接创建新的 VI

    在 Windows Explore 中,鼠标右键点击某一文件夹的空白处,弹出的菜单中有“新建”一项。通过修改 Windows 的注册表,可以给这个新建列表添加一项,从而直接在文件夹下创建一个新的 VI。如图1所示。


图1:在“新建”菜单中添加一项-创建VI

    下载 Create New VI.zip 文件,然后解压缩。运行里面的 Create Empty VI.reg,把它里面的内容导入到注册表。然后就会发现多出图1所示的新建 VI 的项目了。

    让 Windows 多一个新建项目,只要在注册表里添加上相关内容就行了。Create Empty VI.reg 文件中的 Data 数据其实就是新建出来的文件的内容。在这个例子中,他是一个空白的 LabVIEW 8.0 的 VI。我们可以改变 reg 文件中的数据,使得产生出来的 VI 有所不同。
    比如,你希望自己的新 VI 总是使用蓝色背景的,有一个特殊的图标等等,只要改变 reg 文件中的数据就可以了。ZIP 包中还有一个 Create New Reg Data.vi,这个 VI 可以读入一个文件,把它转换成注册表中实用的 Data 数据。使用者可以自己先造一个自己喜欢的 VI 作为模板,然后利用Create New Reg Data.vi 为它创建出一个注册表数据,导入注册表。这样每次在文件夹下用鼠标右键创建出的 VI 就是模板 VI 的样子了。


相关文章:
    我和 LabVIEW

调整控件和函数面板的首选项

    LabVIEW 在 8.0 版对控件和函数面板作了一次较大调整。LabVIEW 功能越来越强大,控件和函数面板上的东西越来越多。如果增加面板的嵌套深度,用户每次选取面板上的一个控件和函数都要多点几下鼠标,而且对不熟悉位置的东西找起来也相当费劲;如果扩充每一个面板上的容量,一个面板上图标太多,用户会眼花,也不利于查找。所以 LabVIEW 8 调整了面板的显示方式:最顶层面板所有栏目都以文字的方式显示,纵向排成一列。其中第一个栏目是默认就展开的,可以直接看到次级面板的内容;其它栏目都收起,鼠标挪上去,才看得到它里面的内容。
    我现在用的是 LabVIEW 8.2 版,它的函数面板看上去是这样的:(在程序框图的空白处点击鼠标右键)


图1:用鼠标右键弹出函数面板

    函数和子 VI 被分为几大类,每个类的名字被列在弹出的菜单上,其中最前面一个类是展开的。因为第一个分类中的函数最常用。
    但是,有些人可能最常用的函数是在其它分类中的。这样可以调整一下,比如最常用的是 Express VI,就可以把它最常用挪到最前面来。

    用鼠标点弹出菜单左上角的图钉,就可以吧弹出菜单固定住。固定后的菜单每一项左端有两个竖线,和一个三角。点击三角可以展开和收缩这个类里的图标,鼠标放到两个竖线上,鼠标就会变成带箭头的十字花。这是就可以按下鼠标拖动这个条目了。点在 Express 项目的竖线上,然后把它托到最上面。如图2、图3所示:

 
图2, 3:鼠标点在连个竖线上可以拖动这个项目

    从此以后,Express 就在最上面了。看图4,再在程序框图上点鼠标右键,弹出的函数面板,最上面一栏展开的就已经变成 Express 了。


图4:新的函数面板

    你可能会发现,自己的 LabVIEW 在鼠标右击程序框图后,只显示出几个分类,其他的类别统统都缩了起来。用户是可以自己制定显示或隐藏哪些分类的。在函数或控件面板钉住的状态下(如图2这种状态),点击面板最上方的“View”按钮,就会出现让你更改显示或隐藏分类的菜单。

    如果你觉得 LabVIEW 的面板布局不是很合理,你要用的东西分散在不同的类别里,用哪个坐首选项都不太方便。那也没有关系,在 LabVIEW 8.5 中又多了一个类别,叫 Favorite (我的最爱)。在函数或控件面板钉住的状态下,右键点击其它类别的函数,或子面板标题,弹出菜单上有一项就是加入到 Favorite 中。把你最常用的函数都放到 Favorite 里去,再把 Favorite 移到面板的最上端作为首选项,就可以了。

相关文章:
    我和 LabVIEW

编辑

记录梦境 6 – 热带岛屿的植物

    前一段时间睡眠质量还不错,有阵子没做离奇古怪的梦了。这直接迟滞了一个伟大科幻作家的诞生:)
    昨晚不知身体哪不对劲了,做了一会科幻的梦,记录如下:
    我和几个同事一起去一座热带海岛上旅游,其他人整天就是在沙滩上晒太阳。我海边呆腻了之后,觉得应该为科学做点贡献,就顺便就考察了一下当地的生态环境。
    这个小岛面积不大,环岛走一圈也用不了一个小时。但是由于小岛从前一直没有人类居住,其生态环境被完好的保存了下来,森林覆盖了几乎整个小岛。我在小岛腹地转了几圈,发现岛上森林居然是由一种单一植物构成的。我给它起名叫耶柚,因为这种奇特的植物,每个植株上居然可以结出看上去完全不同的两种果实:一种像椰子,另一种像柚子。
    地上密密麻麻散落着像叶子一样的果实;而那种像柚子一样的果实,却不大容易在地上拣到。而我仔细搜索后,发现一些刚刚发芽的小耶柚,它们都是从柚子一样的果实中长出来的。看来,这些柚子一样的东西是耶柚真正用来繁殖的种子,一旦落地,就开始寻找机会生根发芽。
    但那些椰子一样的东西是干嘛的呢?我先也许可以像椰子一样喝汁,于是就拾起一个,企图把它弄开。不过这些“椰子”还真是坚硬,比真椰子有过之而无不及。我弄了半天都打不开一个,只好作罢。这是我突然想起,送我们来的游船上有一些盆栽植物。何不把它们移植到小岛上来,以后岛上的植物也不至于如此单调了。想到这,我立马就打消吃“椰子”的念头,兴冲冲跑到船上,抱回了一盆杜鹃,并且把它种在了地上。
    第二天上午再来看我的杜鹃的时候,我被周围突然发出的“啪”的一声吓了一跳。寻声看过去,竟然是杜鹃旁边的一颗“椰子”自己裂开来了。接下来,又是几声“啪”“啪”,不到半天的时间,杜鹃周围两米以内的“椰子”全都裂开了。而且他们一旦裂开,就会从裂缝出长出一根藤蔓,朝杜鹃的方向爬过去。藤蔓的生长速度快的让我难以置信,我傍晚准备回去睡觉的时候,一些藤蔓已经搭到杜鹃的枝杈上了。原来这些“椰子”静静的爬在这里,并没有死去,他们在准备着与到来的其它植物作战。
    到第三天,已经是我们离开小岛的时候了。我在出发前,特地又跑回我种杜鹃的地方看了一下。几十个“椰子”里伸出的藤蔓,死死缠在杜鹃上,挤成一团。杜鹃不但被从土里拔了出来,而且大部分的枝杈,根须都已经被耶柚的藤蔓扭断。真没想到,我的杜鹃会是这样一种死法。而岛上的耶柚成功的守护了它们的小岛,抵御了外来物种的入侵。
 

编辑

 

VI 中的数据空间

    LabVIEW 由于比其它语言采用了更多的值传递方式,这必然会影响它的运行效率,也使得 LabVIEW 在这方面要采取一些其它语言不需要的应对措施,尽量提高效率。优化之一是子 VI 中局部变量使用的内存的分配方式。
    C 语言中,函数的局部变量存在于栈中。在调用某一函数时,程序才为这个子函数开辟一块空间作为用于保存函数中局部变量的栈。子函数运行结束后,栈空间即被释放。下次再调用这个函数,程序会重新非配栈空间,这时的空间可能与上次分配的并不在同一内存地址。为了节约反复开辟空间的时间,LabVIEW VI 中并没有采用栈的方式。一般情况下,静态调用 VI,每个 VI 专门有一块存数据的数据空间,这块数据空间所在的内存地址在 VI 每次运行时是不会变化的,尤其是上次 VI 运行后所留有的数据还可以被使用。

    LabVIEW 这种做法最大的好处是节约了大量开辟、回收内存的开销;但它也有个严重的缺陷,这也是其他语言不采用类似措施的原因:每次函数调用没有独立的数据区,因此无法实现递归调用(LabVIEW 静态调用的情况下)。经过权衡,LabVIEW 最终牺牲了递归来换取运行效率。

    对于一般的子 VI(非可重入的),不论在程序的哪里被调用时,都使用的是同一块数据区。如果主 VI 上有两个并排被调用的同一个子 VI(如图1所示的两个 Delay VI),理论上的数据流驱动语言是应该在两个线程内同时运行两份子 VI 的代码。但是,由于这两次调用会使用到同一块数据区,为了避免两次运行之间互相干扰,引起数据混乱,LabVIEW 实际上是顺序执行这两次调用的。至于那部分代码被先调用是不确定的。


图1:并行调用同一子 VI 两次

    LabVIEW 只能顺序执行这两次调用,在很多时候并不是一件坏事。比如,子 VI 中的操作是读写某一串口。LabVIEW 的这一特性恰好防止了多线程同时对这个串口读写而引发的错误。但这种行为也会引起一些糟糕的问题。比如,子 VI 是用来读写所有串口的。我在一个线程内对串口1做了操作,另一个线程要对串口2操作。读写串口是比较慢的,本来应该两个串口同时操作,来节约一点时间。但是如果串口读写子VI不能重入,那其中一个线程就只好慢慢等着了。
    LabVIEW 解决这个问题的办法是为 VI 增加了一个可重入(reentrant)属性。非可重入的 VI 的数据区是和这个 VI 其它内容(比如执行代码、界面、源代码等)放在一起的,所以不论这个 VI 在哪被调用,使用的都是同一数据区。设置为可重入的 VI,它的数据区被开辟在调用它的父 VI 那里。在父 VI 的程序框图上每一个可重入子 VI 的图标,都意味着父 VI 的空间内为这个 VI 开辟了一块数据区。所以,并行的两次调用同一可重入子 VI,这两次调用它们使用的是不同的数据区,所以可以同时运行而不需要担心数据被互相干扰;如果是循环内有一个子VI,那么循环多次执行,每次调用这个子 VI,使用的还是同样的数据区。

相关文章:
    我和 LabVIEW

编辑

传值和传引用

    在现在常用的文本编程语言(C++, Java, C#)中,调用子函数时的传参方式主要是传引用方式,就是说,告诉被调用的函数的是参数所在的位置,而不是参数的数据。C++ 为了保持和 C 语言的兼容,一般的简单数据还是使用值传递,但对于大块的数据,比如数组,字符串,结构,类等等,也基本上都是引用形式传递的。
    值传递的方式的缺点是显而易见的:每次调用子函数的时候,需要把数据拷贝一份,耗费大量的内存。传引用的方式,不需要每次都拷贝数据,节省了内存空间,和复制数据的时间。但是传引用的安全性不如直接传值,因为传引用的时候,数据所在的内存也可以被其它函数访问,这在单线程下,问题不大。但是多线程下,就不能保证数据的安全了。

    理论上,一个数据流驱动的编程语言,可以只采用值传递。数据在每一个联线分叉的地方,都做一个拷贝。这样任何一个节点所处理的数据都是它专用的,不需要担心线程之间会相互影响。在设计 LabVIEW 程序时,可以假设 LabVIEW 就是这样子工作的。但是 LabVIEW 的实际工作情况比这要复杂些,它在不违背数据流原则的前提下,做了一些优化以避免过多的复制数据。

    在某些时候,一个节点得到了输入数据,LabVIEW 如果能够确认这个输入数据的内存肯定不会被其他部分的程序代码使用到,并且恰好节点的一个输出需要一块内存,LabVIEW 就不在为输出数据令开辟一块内存了,而是使用那个输入数据所在的内存。这叫做缓存重用
    这种行为实质上和传引用是一样的,告诉函数一个数据的地址,然后函数直接在这个地址上处理数据。LabVIEW 程序员是不能够直接设置某个参数是传值还是传引用的。到底采用那种传递方式,是由 LabVIEW 来决定的。LabVIEW 决定采用哪种参数传递方式的原则是:首先保证数据的安全,其次才估计效率。LabVIEW 并不能总是准确的判断出某段代码采用传引用的方式是否安全。LabVIEW 本着宁枉勿纵的原则,对凡是拿不准的地方一律不优化,全部采用传值的方式,多拷贝一份数据。
    虽然不能够直接设置某个参数是传值还是传引用的,但追求效率的的程序员,可以通过改变程序风格,来帮助 LabVIEW 准确判断出那些代码可以优化,无需拷贝数据,从而让自己编写出来的 LabVIEW 代码效率最高。比如,使用移位寄存器缓存重用结构告诉 LabVIEW 在某个地方使用传引用的方式。

    LabVIEW 中有些节点的输入输出数据类型完全不一样,比如数组索引节点,输入是一个数组和索引,输出是一个数组的元素。输入和输出的数据类型一般情况下完全不同,所以必须未输出数据新开辟一块内存,根本不可能做到缓存重用。有些节点,总是有相同类型的输入输出,比如加法节点,输出值的数据类型总是和其中一个输入同类型(fixed-point 数据类型是个例外)。LabVIEW 要考虑尽量在这些节点使用缓存重用。
    如果输入值是数组数据,它通过分叉的连线被同时输入到一个数组索引节点和一个加法节点。假设其它数据都已就绪,LabVIEW 作为数据流驱动的程序,理论上应该同时运行着两个节点。但实际上,为了内存优化,在类似的情况下,LabVIEW 总是运行不可能做缓存重用的节点(比如这里是数组索引节点),然后再运行可以做缓存重用的节点(加法节点)。
    原因是这样的:如果先运行加法节点或者同时运行两个节点,因为加法节点的输入数据所在的内存还要被数组索引节点读取,因而加法节点是不能够改变这块内存中的数据的,那么加法节点只好再为输入数据开辟一块新内存;相反,如果先运行完数组索引节点,在运行加法节点的时候,加法节点输入数据所在的内存就不会再被别的节点使用了,这是加法节点就可以放心的把输入数据放到这块内存里,做到缓存重用。

    LabVIEW 虽然不能设置数据传递给一个节点时,使用值传递还是引用传递,但是 LabVIEW 中有一类专门的“引用型控件”,用来保证大块的数据不被频繁复制,或者在不同的线程内对同一内存做数据操作。一般叫做 xxx refnum 的控件都属于之一类,他们所代表的数据(也可用于表示某个设备)是不随着数据线流动的。程序上的连线出现分叉,虽然 refnum 这个值本身可能会被复制,但它所指向的数据是不会被拷贝的。

    另外,如果一定要在 LabVIEW 代码中实现传引用,可以通过以下的方法:做一个全局数组变量,把数据存在数组里。VI 间传递的信息是数据在数组中的索引,一个表示序号整数值,就相当于是这块数据的引用。这样,所有对块数据的操作都是在同一内存中的,并且不同线程可以同时对这块内存做修改。

相关文章:
    我和 LabVIEW