Labview-测量-仪器控制

参考笔记

 

LabVIEW小知识

程序编写的体会(by 阮奇桢):在做简单小项目的时候,希望程序能运行,出了结果就好,其它都是怎么方便怎么来。但是,如果编写一个大型项目的时候,最大的难题就变成了如何才能提高程序的稳定性,可扩展性,可维护性。这时候可能会发现,一个有隐患的程序能运行还不如不能运行。

软件配置

LabVIEW的特点: 图形编程、并行性运行、基于数据流、提供了大量外观与传统仪器(如:数字示波器)近似的显示控件,可以"拿来主义"快速使用,进而高效率的实现 "专业"的测试测量软件。

使用LabVIEW前,需要进行如下配置:

  • NI MAX (Measurement& Automation Explorer)是一个管理计算机中已经安装NI软件和硬件的独立软件。设置安装LabVIEW的组件时,默认安装包含NI MAX,其快捷方式也位于National Instruments程序目录。任何一个在本地计算机中安装的NI软件(开发环境、驱动程序)均能在MAX中查询、配置。利用NI MAX可完成下列操作:
    • 配置NI硬件和软件
    • 创建和编辑通道、任务、接口、换算和虚拟仪器
    • 进行系统诊断
    • 查看与系统连接的设备和仪器
    • 更新NI软件
  • LabVIEW Suite (LabVIEW套件)如果没有这些套件也可以用工具包实现类似的功能
    • 自动化测试套件
    • 嵌入式控制与监测套件
    • HIL和实时测试套件
  • LabVIEW Toolkit (LabVIEW工具包),有时似乎也叫add-on 附加组件或者模块module,总之这些都可以在NI Tools Network查询并下载,常见的几个如下:
    • 数据库连接工具包
    • FPGA工具包
    • Arduino™- Compatible Compiler for LabVIEW
    • Vision开发工具包
    • 数字滤波器设计工具
  • 外部互联功能:有时候所需的功能不太容易或者不能通过上面的LabVIEW套件/工具包来实现,但是如果通过与其他语言编写的程序互联的话就可以简单实现所需的功能,那么此时就可以使用该功能。LabVIEW可以连接或调用多种其它的外部程序与组件,参考Labview编程经验,常见的有如下互联:
  • NI Package Manager:With NI Package Manager, you can install available NI software and view recommendations for installing related software. You can use the NI Package Manager to install, upgrade, and manage NI software. 
  • VI Package ManagerUse the JKI VI Package Manager to discover, create, distribute, and install third-party add-ons for LabVIEW. Choosing between the NI Package Manager and JKI VI Package Manager
  • NI Tools Network:被称为工程师的APP商店,提供了经认证的第三方附加组件,以帮助用户扩展LabVIEW系统设计软件功能,提高开发人员的效率。

 

基础操作

  • 白底 —— 后面板 (程序框图面板,Block Diagram),网格 —— 前面板 (显示面板,Front Panel);输入控件(比如numeric control)和显示控件都在前面板。
  • 对于后面板的图标,右键visible item可以选择label,即可显示对应的文字说明;也可以直接在前面板修改,二者是关联在一起的。
  • 程序禁用结构,相当于标注起来了,这一部分到时候不会运行。
  • VI ↔ 图片:对于一个写好的VI,在程序框图面板,Ctrl+A(或者手动部分选中程序) → 工具栏 → Edit → Creat VI Snippet from Selection即可保存为png图片;想使用该png图片展示的程序,直接将其拖拽到一个新的VI的程序框图面板即可。牛逼!
  • 工具选版菜单栏 → View → Tools Palette,对于前面板和程序框图面板来说,工具选版都是通用的,作用是修改对象的一些外观样式。
  • 函数选版(Function Palette),也可以通过图钉固定,固定之后可以customize显示我们常用的子选版类型。
    • 将常用函数添加入收藏夹favorites,比如说点击instrument I/O,然后选择VISA,再点击大头针,然后可以右键 → add item to  favorites。
    • 处理不熟悉的函数,我们将其拖到程序框图面板之后,右键创建所有的输入控件和显示控件,可以帮助我们更好地了解这个函数。
  • 编程环境:有关labview的设置选项、函数和控件选版、工具选版的详细内容,可以参考Labview编程经验
  • 三种运行方式::
    • run——如果该右箭头图标破裂,那么可以点击该箭头,然后会弹出对话框告诉你哪里有错误,你双击即可定位该错误的位置。
    • run continously——它只在临时调试时使用,因为通常提供给最终用户的是VI生成的可执行文件,它是没有“连续运行”按钮的。并且,使用“连续运行”按钮,程序内所有的代码都会反复运行,没办法将程序中只需运行一次的代码和需要重复运行的代码区分开来。
    • Highlight execution——点击灯泡图标,然后就可以缓慢运行,可以看到数据流的传输和变化,可以用来排错/调试程序,此时可以通过探针监视窗口(probe watch window)看特定连线/结点上数据的变化。
  • 即时帮助,右上角的问号,有两种状态:Hide/Show Context Help Window,图标如果是灰黑色背底就是show的模式,那么鼠标hover你需要帮助的图标,就会显示图标的说明。另外也可以选择打开帮助文档,可以看到更详细的信息。
  • 标签(程序框图面板,Labeling),标签里面可以写注释,而且可以添加箭头(free labeling),帮我我们理解程序,右键structure-decoration即可选择,可以参考这里。For loop/while loop/ flat sequence structure/event structure,都可以给框图添加label或者subdiagram label
  • 标签标题(前面板,Label and Caption):每个空间都有对应的标签和标题,两者是有区别的。默认显示的是标签,而且标签和标题的默认值一样。在程序框图面板,只能显示控件的标签,无法显示其标题。标签和标题的区别
    • 通常标签名称比较短,用于程序框图使用;
    • 标题可以稍微长些,在前面板显示标题可以详细描述控件的功能,同时放在帮助信息中方便用户查询;
    • 不同控件的标签和标题都可以相同,但不建议这样做,标签是控件唯一的标识,每个控件的标签应当是唯一的,类似于人的学号,对标题的要求则宽松些,可同可不同;
    • 标签应该尽量只使用英文字符,因为LabVIEW没有完全支持unicode,如果在标签中使用了其它语言的字符,可能会导致某些程序在拷贝到一个不同语言的系统后运行出错;
    • 在运行状态下,不能修改标签,但是可以修改标题;
    • 软件本地化——标题。标签作为控件的唯一标识,在程序的各种语言版本中都应当相同,而能够改变文字的就是标题了。所以,需要本地化的软件,可以把控件的标签隐藏起来,只显示其标题。
  • Meaning of Different Wire Colors in LabVIEW
    不同颜色、宽度的线条的含义,如果忘记了,可以先点击右上角的帮助,然后将鼠标放在需要了解的线上(不用点击)即可知道是什么类型的线(什么类型的数据流)。
  • 点击目标连线的三种情形如下,和前面的对图标进行label类似,这里我们也可以左键选中目标连线,右键选择visible item—label,然后输入你想label的文字。
  • 快捷键
    • Ctrl + N 新建一个VI
    • Ctrl + E可以切换到程序框图面板
    • Ctrl + B,去断线
    • Ctrl + R,运行程序
    • Ctrl + S,保存程序
    • Ctrl + T 左右两栏显示/上下两栏显示
    • Ctrl + U 快速整理连线(有点类似小扫把的整理)
    • 对输入控件,也可以自己设置快捷键,右键 → property → key navigation-focus/increment等等
  • 优化显示的方法
    • 鼠标选中,然后点击小扫把,可以整理图标;
    • 如果觉得图标太大了可以右键 → view as icon;
    • 前面板,可以使用align objects/distribute objects/resize objects/reorder等等来整理图标;
    • 显示控件,如果内容太多,可以添加Show vertical scroll bar,即右键 → property → appearance → Show vertical scroll bar;
    • 对于大型程序框图,电脑屏幕可能给无法一次性完整显示,可以选择菜单中的“查看 → 导航窗口”,在导航窗口中查看整个代码框图的缩略图(出现在右下角);
    • 如果需要在代码比较密集的地方再插入一些代码,可以先按住Ctrl键,再在需要插入代码的地方按住鼠标左键,拖动鼠标,就会把原本附近的代码挤走,开辟出一块空白区域供插入新的代码;

 

 

 

时间

延时的作用:在一个简单的while loop里面,如果添加200 ms的延时,程序对 CPU 的占用率只有原来的几百万分之一。实际应用中,可能有时用户会非常频繁的调整输入“旋钮”的值,而有时候又会长时间不改变任何输入,所以这种固定 200 毫秒刷新一次的方案仍然不够完美。本书会在事件结构和程序界面一节介绍一个更加优化的界面程序设计方案。(by 阮奇桢)

延时控件:最常见的就是在顺序结构里面用Wait (ms)控件,但是这里存在一个问题,即如果程序运行中出现错误,都会执行该"等待"函数。一个理想的方案是一旦上一步出错,程序就没有必要再等待了,应当立即退出,解决方案是把程序的延时部分做成一个子VI。注意目前上述功能已经融合在"Time Delay" Express VI和High Resolution Polling Wait.vi(2016版本没有)。

 

 

数值、组/字符串/簇

数值(value):

  • 数值输入控件——可以设置左侧的两个增减按钮的步进(step),还可以设置其最大值,比如在电源的控制中,需要避免人为输入超过电路允许的外接电压;
  • 单位——可以给数值添加单位,这样在后续数值处理和计算中,labview能自己处理好单位(量纲)和数值换算,而且如果遇到两个数量纲不不同但是进行加减操作(或者赋值),程序会报错;
  • U16 or U32——对于单个数据而言,使用U16与使用U32表示法相比,不过相差两字节,这个长度上的差别可以忽略不计,对程序占用的存储空间根本不会有什么影响,为安全起见,不妨尽量使用长度较大的表示法;
  • 表示法——选择合适的表示法,可以优化数据存储和后续处理,比如我们利用光纤光谱仪测试,一般情况I32就够了,对应的表示范围为(-2,147,483,648 to 2,147,483,647)。
  • 特殊实数:
    • 如果数据超出规定表示范围,会显示Inf或者-Inf;
    • 1/0 = Inf;
    • 0/0 =NaN,表示这不是一个数值;
  • 比较两个数是否相等,如果都是整数当然简单,但是如果不是整数,要考虑误差;
  • 避免强制类型转换,红色的点就表示强制类型转换,如果实在是需要转换,那么可以使用表示法转换函数(在函数选板 "编程 -> 数值 -> 转换" 中)以避免潜在的错误风险
  • 数值计算
    • numeric—expression node,只能有一个输入;
    • Mathematics—Script & Formula—Formula/Formula Node/(Script Nodes, Matlab)
    • Formula Node采用的是C语言编写的。在实现算法时,人们往往更习惯于文本表达方式。我们在书本中学习到的公式,对计算过程的描述,都是用文本方式来表达的。并且,在具有较多选择结构的程序中,文本表达方式可以有顺序地显示所有分支中的内容;而 LabVIEW 在遇到选择结构时,每次只能显示一个分支的内容,其它的分支要点击鼠标后才能逐页读到,可读性差。因此,在较为复杂的数学运算程序中,使用公式节点可以让程序的可读性和可维护性得到提高。
    • Express—Arithmetic & Comparison—Formula,弹出一个计算器,可以有多个输入,但是只有一个输出。

 

数组(array):相同类型的数据类型元素组成的新的数据类型,其简单操作如下:

  • 程序框图面板,右键array constant,空的会报错,因为里面没有内容从而无法定义类型,需要创建一个数字/字符串常量,放到数组里面,即可横着拉或者竖着拉,但都是一维数组。想要二维数组,就将左侧的图标往下拉成两个(上面一个是行索引,下面的一个是列索引,索引都从0开始),然后图标右下拉即可拉出二维数组。
  • 前面板,选择数组array,也会报错,因为里面没有元素,比如可以放入一个输入控件(Numeric control),然后即可拉动出数组,二维的方法和上面的类似。注:数组:相同类型的数据类型元素组成的新的数据类型。
  • 数组索引,参考这里
  • 自动构建一个3×3的二维随机数组,右键下图的连接处tunnel mode可以选择last value/index/concatenating,为了满足我们扥需求我们选择indexing(索引)。

 

字符串(string)

  • 数值 ↔ 字符串之间:将不同类型的数据相互转换,很常用;
  • 正则表示式:用于查找匹配满足指定条件的字符串,匹配用到的是offset past match为-1的话就是没有匹配到。
  • 反斜杠\显示模式:字符串中有些字符具有特殊含义或无法显示,比如回车、换行等符号。这时,可以使用“'\' 代码显示”方式,把不能显示的字符用 '\' 转义代码表示出来。。 反斜杠模式适用于调试VI及把不可显示字符发送至仪器、串口及其他设备。在 LabVIEW 中,最常用的转义符就只有 "\n" 表示换行符、"\r" 表示回车符、"\t" 表示制表符、"\s" 表示空格、"\\" 表示'\'等几个。
  • Labview字符串控件有两种表现形式:正常显示十六进制显示
  • Backslash的各种code的含义,参见这里
  • 字符串输入控件:右键选择Password Display,可以防止被人偷窥。

 

(cluster):复合数据类型,它可以把多个不同类型的数据组织在一起,变成一个新的数据类型。和C语言的结构体(struct)、python里的元组(tuple,又叫作"多元组",多个元素(数字、字符串随意)按一定顺序排列得到的组合)差不多是同一个东西。

  • 簇控件开始只是一个空壳,不能使用,要给它添加其他数据类型的数据作为它的元素;
  • 簇可以嵌套,即一个簇可以是另一个簇的元素;
  • 只有元素数据的顺序是有意义的,与控件的摆放位置就不再相关了,除非你设置了相关性;
  • 簇数据的运算:涉及到将元素"解除捆绑"/"捆绑",以及"按名称捆绑"/"按名称松绑"
    • "捆绑"和"松绑"限制比较死板,每次都会捆绑或松绑簇中所有的元素,数据的顺序也是固定的,就是按照元素数据的逻辑顺序排列;
    • "按名称捆绑"和"按名称松绑"是长度可调的,用户可以用鼠标选择捆绑或松绑出哪几个元素,顺序也可自定义;
    • 在程序中应尽量使用"按名称捆绑"/"按名称松绑",因为它显示了元素的名称,不仅可读性比较好,还可以前后两个簇中元素顺序不一致等引发的错误:
  • 错误簇】(Error Cluster):是labview最基本的错误处理机制,当error in携带有错误信息时,对应的函数就会不做任何操作,直接将错误传递给error out 输出。
    •  由三个部分组成:
      • 是否有错误  一个布尔类型(T/F,T表示有错误,即显示×);
      • 错误代码 —— 一个数值类型(错误代码);
      • 错误信息 —— 一个字符串类型(错误信息);
    • 如果有两个sub VI的错误簇要合并,可以使用合并错误(Merge Errors)来将两个错误簇合并为一个错误簇;
  • 簇的应用场景:如果某些数据之间的相关性非常高,总是在一起被处理(比如错误簇的三个部分:是否有错误、错误代码和错误信息三个数据),那么就很适合被捆绑成一个簇,这样在不同节点之间传递数据时,只需要一根数据线,可以让程序变得更简洁。

 

File I/O

参看后面的每日一练以及我的部分实例

参考:LabVIEW编程经验

 

引用

局部变量(Local Variable):显示为小房子图标,局部变量给编程者提供了一个获得数据的便利条件,既不用从接线端连线,也不受接线端方向的限制。想读就读,想写就写。总结一下棋特点:

  • 多用于VI内的数据传输,VI停止运行,在此VI内定义的局部变量自动消失;
  • 不用连线,简化程序,数值可以输入和输出,即有读、写两种属性,应用时要注意切换成不同属性;
  • 局部变量就是其相应前面板对象的一个数据拷贝,要占用一定的内存;
  • 在VI内部传递数据的功能应当由数据连线完成,只有在不得不使用局部变量的情况下,才应该考虑使用它(阮奇桢);
  • 创建方法:
    • 直接为前面板对象创建局部变量,右击创建;
    • 通过函数选板创建局部变量,此在编程-结构中找;

一般下列情况,可以考虑使用局部变量:

  • 左图:把数据写入控制控件,或从显示控件读取数据;每输入一个字符,程序都会自动检查一下,看看当前字符串的值是否需要做修改,若输入的文字少于或等于 4 个字母时,正常显示;否则,清空字符串控件。
  • 右图:应用于多线程间的共享数据;Stop控件的接线端控制了一个循环的结束条件,它的局部变量控制了另一个循环的停止条件。

 

全局变量(Global Variable):全局变量与局部变量类似,是一种可以让数据随时流入流出其间的对象,区别在于局部变量只能在其对应控件所在的VI中使用,而全部变量可以在一个程序中的任意VI中使用。数据被保存在某一固定的内存空间,作用域为项目(程序)中所有的VI程序,多用于在VI之间进行数据传输。

  • 创建方式:右键 → Structure → Global Variable,然后双击打开这个图标,让后在里面放置各种控件,比如数值输入控件,布尔控件等;
  • 容易被滥用,因为可读可写,不安全,在程序结构复杂的时候,如果你频繁地给它们赋值的话,可能你自己就不知道你需要的是哪一个值了,不利于调试排错、维护以及可读性,因此在程序中尽量避免使用全局变量/局部变量,而且全局变量缺点比局部变量还多尽量避免使用 by 阮奇桢
  • 适用场景:常量的定义,等同于一个子VI,而且里面可以有多份全局变量数据(多个空间);

 

属性节点(Property Node):

  • 可以转化为读取/写入;
  • 有的属性虽然可写,但是只有VI在编辑状态下才可以,比如label;
  • 一个属性节点可以同时读写多个属性。把鼠标移到属性节点下边框的中间部位,就可以将其拉长或缩短;
  • Property Node—Value,相当于上面提到的局部变量,但是程序运行时,属性节点的效率要大大低于局部变量
  • Property Node—Value (Signaling),用来作为该控件发出"值改变"事件信号的,用在事件结构;
  • 创建一个控件的属性节点-值的两种方法:
    • 右击该空间,创建属性节点-值;
    • 先在空白区域创建一个属性节点,然后右键link to目标控件,然后修改属性为值;
  • 复制一个link to某个控件的属性节点,如果是Ctrl C的方式复制,得到的copy并没有link to该控件,但是如果采用按住Ctrl拖动的方式复制,则得到的copy有link to该控件;
  • 下面是利用属性节点控制Boolean控件闪烁的例子:

 

调用节点(Invoke Node):调用节点的创建、使用方法与属性节点类似。区别在于调用节点用于选择方法,以完成控件的某些行为。每个调用节点只能选择一种方法。下面只展示其"对象高亮"的功能:

 

程序结构

基础知识

For/While Loop

  • 无论是 for loop还是while loop,都给出了该时刻对应第i(变量)次循环(循环计数,从0开始计数),但是for loop还给出了终止的值N(你指定的循环总次数),而while loop给的是loop condition(运行前不能确定循环的次数):
    • F —— 就一直执行下去;
    • T —— 停止然后跳出循环;
  • for loop—conditional terminal:在 for 循环结构,右键—conditional terminal(条件接线端),可以为for循环创建一个接收停止循环命令的接线端。它类似于C语言中跳出循环的break语句:有时候,循环尚未完成全部迭代,就已经得到所需答案,那么循环也没必要再继续。
  • 数据传递方式
    • 隧道、移位寄存器和反馈节点,for/while loop都适用;
    • 但在使用索引隧道时需要注意,while 循环的迭代次数只受控于传入“条件接线端” 的数据,而不受连接索引隧道的数组长度的影响;

 

Case Structure (条件结构):Case selector—Selects which case to execute based on the value of the input data. The input data can be a Boolean, string, integer, enumerated type or error cluster. The data type you wire to the case selector determines the allowed cases you can enter in the selector label. 

  • Case selector—内容:数字、字母等,注意event selector的选择空间更大,比如各种控件的变化;
  • 多对一:条件结构中的一个分支可以对应多个条件,不同条件间用逗号隔开。比如下图所示条件结构的第三个分支有三个条件,当输入分支选择器的数值为 2、4、6 时,都会执行这一分支:
  • default case
    • 有默认分支,程序不容易报错,适合初学者;
    • 没有默认分支,可以帮助定位错误信息,有利于程序后期的拓展和维护;
  • Case selector—枚举 or 下拉列表:二者可以相连,注意枚举和下拉列表的图标完全一样,但是功能有差异:
    • 枚举:传递给Case selector的是item
    • 下拉列表:传递Case selector的是value(第几个)
  • 避免出现条件结构的嵌套,一定要注意把输入输出控件放置在条件结构之外;
  • 条件结构的可读性比较差,但它又是程序必不可少的一种结构。不过,在某些情况下,可以使用选择函数(Select)来替代,使用选择函数最明显的优点是,所有候选数据都直接展现在程序框图上,用户一眼便可了解整个程序的逻辑,程序可读性大大提高。

枚举(Enum):在程序中,表示有限的几种物件、几个状态等含义时,应尽量使用枚举控件而不是下拉列表。因为枚举控件的数据类型更加严格,可以防止程序中的某些错误。并且,这样的数据在程序中通常会与选择结构相连,以对不同的状态、类别等进行分别处理。枚举控件能够让条件结构按照条目标签来选择分支,可以增加程序的可读性和可维护性。

下拉列表(Ring):当程序需要表示的依然是一个数值,只不过需要把用户的输入限定在某几个特定值的时候,应当使用下拉列表控件。 比如,我们编写一段程序,用于模拟一台示波器,它有三种触发模式:边沿触发,脉宽触发和斜率触发。此时程序应该选用枚举类型的控件表示触发模式。这台示波器可显示的波形幅值范围也有三档,分别是:0.1V、0.25V 和 1V。它们是离散的数值,应该用下拉列表来表示这三个幅值范围。

单按钮对话框(One Button Dialog):巧用对话框图,可以实现简单交互,特别是在case structure中用的多,或者用在event structure中的超时分支;

 

 

隧道/移位寄存器/反馈节点

隧道(Tunnel):数据线通过循环结构边框时,会在边框上形成一个颜色与数据线相同的小矩形(有实心的,也有空心的)。这个小矩形叫做隧道,负责把数据传进或传出结构。在其它结构中,也都有隧道,它们的功能十分类似。根据数据进出结构的方向,隧道可以分为输入隧道和输出隧道,下面分别讲解。

 

输入隧道(Input Tunnel):两种模式

  • 实心:表示没有开启隧道索引;
  • 空心:开启隧道索引,如果输入的数据是一个数组,那么该数组输入到该循环结构的内容就会随着循环次数的变化而变化;

 

输出隧道(Output Tunnel):三种模式

  • Last Value—实心方块:这种模式只输出最后一次循环迭代传递给隧道的数据。
  • Indexing—空心方块:与输入隧道的索引模式先对应,把每一次循环迭代传递给隧道的数据作为数组元素,合并成一个数组传递出去。如果输入的数据已经是数组了,那么就会把输入数组增加一个维度输出。
  • Concatenating—带横条纹的方块:这种模式只能应用于隧道的输入端数据的类型是数组类型的情况。与 Indexing 不同的是,输出的数组与输入数组维度相同,但是长度增加了。每一次循环迭代传递给隧道会被附加的数组的后面。

条件结构隧道要不要设置“未连线时使用默认值”的考量:虽然条件结构每次只执行其中某一分支的代码,但编程的时候并不知道某一次运行会执行哪个分支,所以每个分支都必须为输出隧道的输入端接上数据线。这样编程是比较繁琐的,多数情况下,可能只有某个分支中才会产生一个有意义的输出数据,供结构外代码使用,其它分支只需提供一个默认值就可以了。所以,一个偷懒的编程方法是把输出隧道设置为“未连线时使用默认值”。这样,如果某一分支不传递任何数据给这个输出隧道的输入端,输出隧道就使用该数据类型的默认值作为输出。

 

移位寄存器(Shift register):隧道负责在循环结构内外传递数据。当循环的不同迭代间需要有数据传递时,需要使用另一种机制:移位寄存器。在循环结构边框的鼠标右键菜单中选择“添加移位寄存器”即可为循环结构添加一对移位寄存器。一对移位寄存器由两部分组成,分别位于循环结构的左右两侧。一次迭代结束时,数据流入循环结构右侧的移位寄存器;在下一迭代开始时,该数据会从同一移位寄存器的左侧端流出。尽管一对移位寄存器总是包含左右两部分,但这两部分中的数据是同一份;而隧道则有输入隧道和输出隧道之分,某个输入隧道是与其它输出隧道毫无关系的独立节点

 

反馈节点(Feedback Node):

  • 在循环结构框图中,如果单纯为了让下一次迭代使用上次迭代的数据,也可以使用如下图所示的反馈节点;
  • 通过移位寄存器的右键菜单,可以把一个移位寄存器替换为反馈节点,反之亦然;
  • 反馈节点和移位寄存器的功能与本质是完全相同的,反馈节点的优点在于它不需要从循环的边框上连接数据线,程序写得更简洁美观;
  • 反馈节点的初始化有两种方式:
    • Initialize On Compile Or Load:反馈节点的图标会变成“米”字符号,它表示这个反馈节点只在被装入内存或者被重新编译后初始化一次,之后再运行并不会初始化;
    • Initialize On First Call:反馈节点的图标会变成“人”字符号,它表示每次启动运行 VI,反馈节点都会被初始化。

 

事件结构—重难点

事件结构是与条件结构类似的一种结构。它们的区别在于:事件结构是根据发生的事件决定执行哪一个分支中的代码的,即不需要数据线的情况下自动感知事件的发生。事件结构相比其他结构来说更复杂,但是实操中用处很大,要点如下:

  • 必须跟while循环一起用,也就是说while循环套在事件结构的外面,不然事件触发一次后就没用了(一次性的),while循环相当于让程序持续监测有没有新的事件产生,从而触发对应结构分支,我们把这种一个事件结构外套一个while循环结构的程序模式成为"循环事件结构";
  • No while loop inside,否则会陷入死循环;
  • 额外增加一个停止分支
  • 超时(timeout)分支
    • 默认为-1,表示永不执行超时(永远等待你触发其他事件结构)分支里的内容;
    • 如果设置为3000 ms就表示如果3秒内没有触发任何事件结构其他分支,那么就会执行该超时分支里的内容;
    • 对于小型程序,可以不设置超时(默认),真要用超时,可以在对应分支里面放一个对话框,一旦触发超时,可以弹出该对话框;
  • 事件结构可以给予的信息:
    • 发生了什么事;
    • 事件发生的时间;
    • 发生在哪个控件上;
  • 六种Event sources,但是最常用的就是"控件事件",包括与界面上控件相关的所有事件,比如控件的值被改变等;
  • 一个事件处理分支可以处理多个事件,只要把不同的事件加入这一分支的事件标签即可;

 

例子:程序设定了每隔 200 毫秒做一次加法运算,并更新“量表”显示控件的值。但在软件运行的绝大部分时间里,两个输入控件的值是不变的。也就是说,在这绝大部分时间里,程序所做的加法运算和更新显示控件工作都是无效的。但是,我们又不能够把每次计算的时间间隔调整得过长,否则在控制控件更新后,会明显地感觉到显示控件的更新滞后。

理想的解决方案应当是,让程序一直处于空闲状态,而一旦任何一个控制控件的值更新了,就立即进行运算并刷新显示控件。循环事件结构恰好可以满足这一需求。事件结构还需要有另一分支,用于处理“停止”按钮的“值改变”事件。当“停止”按钮值改变时,按钮的值“真”传递给了 while 循环条件接线端,于是 while 循环停止运行,程序结束。

上图中,程序停止按钮,放在事件结构内和事件结构外,没区别,但是都必须给停止按钮设置值改变的分支。如果没有设置停止按钮设置值改变的分支,停止按钮放在事件结构外,程序运行起来,即使按下该停止按钮,程序也不会停止,会卡住。

参考资料:
(1) 视频-1视频-2
(2) labview编程经验—事件结构

 

用户自定义事件

xx

 

 

 

图形化显示数据

Waveform

Waveform横轴是等时间间隔,纵轴是Y轴的数据。Waveform可以分为Waveform Chart和Waveform Graph。

图表(Chart)和(Graph)的区别:图表和图的功能非常类似,最主要的区别在于当图表控件自带一块缓存,历史数据会被保存在缓存中。当图表接收到新的数据时,它不会把原来显示的图形清除,而是在原图形基础上再把新数据添加上。图控件没有缓存,每次接收到新的数据,就会把旧图清除,只显示新的数据。

  • 图表chart适合显示低速变化的数据,特别是单个数据点比如温度、湿度、压力随时间的变化,具体一点比如某一程序每秒钟读取并显示一次锅炉的温度数据,这个程序可以使用波形图表控件,这样不但能够显示当前数据,还可以为用户提供历史数据,直接观察到温度的变化趋势;
  • 图graph适合高速采集数据,这个数据往往是一维数组或者二维数组,每次显示的是一个完整图谱;
  • chart其实就是类似爱丁堡光谱仪测PL,graph其实就是类似光纤光谱仪(CCD)测PL;
  • 对于上面的程序,如果把waveform chart的图标放在循环外面,那么两个图显示的结果(效果)是完全一样的;
  • 清除chart的历史(缓存):对于上面的程序,我们会发现,再次运行 VI,会发现chart上的旧数据并没有被清除,而是在后面继续添加的新数据。如果希望每次程序运行时,都是一个全新的开始,可以在程序中通过波形图表右键—property node—history data,每次运行都给它赋值(清除数据)。

波形数据类型:补充

XY Graph

适合每次输入是X的一组数据(不用等间隔),Y是元素一一对应的另一组数据。例子:

  • 光谱每次输入的X是一维向量即波长,Y是每个波长下对应的强度值,也是一个一维向量;
  • 在测控领域,常常用它来展示一组采集数据中两个通道的数据之间的关系;
  • 在数据统计或人工智能等领域,常常用它来展示一个数据集中,某个特征量的分布,或者两个特征之间的关系等;
  • 在绘制XY Graph时,比如下面绘制Lissajous图的例子,需要将对应于X的数组和对应于Y的数组捆绑成簇,然后再利用XY Graph控件显示:
  • 绘制Lissajous图,采用Express VI里面的控件会更简单,另外NI自带了显示动态Lissajous的例子(即相位随时间变化),可以查看学习,该例子用的也是express VI,关于Lissajous,还可以看这里的html5展示

 

 

Intensity Graph

用二维图显示三维信息,也就是用点的颜色深浅表示该(x,y)处的Z值大小。最简单的例子如下图:

当然了,我们也可以使用表格作为输出控件,但是并不利于我们直观地观察数据整体的变化的规律。关于强度图的更多信息,可以参考这里

 

Labview项目管理器

子VI

  • 子 VI 相当于文本编程语言中的子函数。
  • 一个功能十分复杂的 VI,其程序框图上会有大量节点和连线,甚至于电脑屏幕都无法一次完整地显示出其全部代码。这种复杂的框图,难以阅读和理解。为此,通常需要把复杂的程序划分成若干小的程序模块(子VI),每个模块只完成简单功能。
  • 合理使用子VI,可以大大提高代码的可读性和可维护性。
    一个理想的项目的 VI 层次结构应当是金字塔型的:打开 VI 层次结构窗口(在项目主 VI 的菜单中选择“查看 ->VI 层次结构”),可以看到,主 VI 调用了数个子 VI,第二层的每个子 VI 又分别调用第三层的数个子 VI,依次层层调用。这样层次分明、又没有交叉调用的程序结构是最容易阅读和理解的,比如下图所示的一个复杂程序的 VI 层次结构:

项目浏览器(project explorer):

  • 如果项目涉及到多个labview文件或其它形式(非labview)的文件,我们可以用项目浏览器进行集中的管理,比如可以创建多个文件夹分别存储主VI、数据、子VI、控件等等。
  • 创建程序生成规范Build Specifications,也就是生成可执行的exe;
  • 将程序部署或者下载至终端;

几种文件:参考

  • 项目名称.lvproj:是项目文件,用于保存项目中的文件引用、配置信息、部署信息、程序生成信息等;
  • 项目名称.aliases:是计算机和IP地址的映射关系文件,该文件通过LabVIEW自动创建,且每次打开项目时都会创建一个新的.aliases文件;
  • 项目名称.lvlps:是用于保存本机所持有的项目配置文件(保存项目同时会保存该文件)。
    (PS:在项目开发过程中,所使用的文件只有.lvproj文件,另外两个文件是开发环境自己的管理文件,删除后对项目的运行和性能不会产生影响)

生成exe和installer

在项目管理器中,将labview文件和非labview文件放置到项目中后,选择Build Specifications-New-Application(EXE),然后在弹出的My Application Properties对话框中,进行后续必要操作:

  • Information:编辑"程序生成规范名称"、"目标文件名称"以及目标目录;
  • Source Files:选择部分Project Files分别放置到Startup VIs和Always Included中;
  • 完成上面两步即可点击Build生成相应的exe,注意该exe只能在安装对应版本labview的电脑上运行,否则别人的电脑即使有labview但是版本不对,也会提示什么缺少runtime engine;

其他可选/要注意的操作

  • icon:可以自己画,或者网上找.ico格式的图片作为程序的图标;
  • 如果在主VI里面调用了其他子VI,那么在子VI一定要放置到上面提到的Always Included中;
  • 生成installer:即生成可以在没有labview的电脑上运行的安装程序,在已经成功生成exe的前提下,点击Build Specifications-New-Installer,然后在Source Files中选中自己的exe文件,add到右侧面板,然后点击Buid即可;
  • installer:安装的时候,相当于给你安装了一个labview运行的配置环境,应该就是上面提到的runtime engine;

参考资料:
(1) LabVIEW从零开始-23-LabVIEW_生成exe以及安装包—B站
(2)
(3) labview生成exe和安装包—CSND

 

 

LabView仪器控制

总线与串/并行通信

总线(bus):电子设备或电子芯片之间交流的方式与渠道,目的是团队作战。总线是面对现场设备的数据交换, 它主要由下面三大部分构成:

  • 电气标准:比如规定什么是高低电平;
  • 机械标准:总线接口或线路的物理标准,比如总线外观形式,什么样的保护等等;
  • 通信标准:通讯规则,保证两个设备之间正常的通讯;

通信协议(Communication protocol )其实就是通信标准,是设备之间进行数据交换的规约,也就是说A和B设备交换数据的时候,A设备发出的数据可能是先寻址,然后再握手,然后在数据发送等等,然后B设备必须要知道A的发送规则才能读懂发来的数据是什么意思。

总线,按照传输数据的方式分为串行总线(serial bus)和并行总线(parallel bus),串口是串行总线其中的一种。Serial connections, which use relatively few wires, are generally simpler than parallel connections. USB(Universal serial bus) is a common serial bus. Parallel buses have a relatively large number of wires bundled together that enable data to be transferred in parallel.

串行通信:

  • 通信双方使用一根或两根数据信号线相连,同一时刻,数据在一根数据信号线上一位一位地顺序传送,每一位数据都占据一个固定的时间长度;
  • 与并行通信相比,串行通信的优点是传输线少、成本低、适合远距离传送及易于扩展。缺点是速度慢、传输时间长等;
  • 实际上,随着技术的发展串行通信速度慢的缺点逐渐被克服,其相对并行通信的优势也在逐渐扩大,串行通信也越来越流行。早期处理器频率低,并口更快;频率上去后,串口才有优势。现代设计中很少会出现并行信号,一个重要的原因就是并行的频率很难提上去(高频的并行会互相之间会有干扰而出现传输错误),以至于比不上高频的串行信号。
  • 如计算机上常用的COM设备、USB设备和网络通信等设备都采用串行通信
  • 串行通信,按照数据传送方向可分为:单工(simplex) 、全双工(full duplex)和半双工(half duplex)
  • 串行通信的协议
    • RS232、RS422、RS485、USB;
    • Sbus、PPM、JTAG、UART、I2C、CAN、SPI、MIDI、Morse Code;
  • 串行通信,根据使用时钟的不同,可以分为:
    • 同步通信】(synchronous communication):比如I2C和SPI,双方需要使用频率一致的时钟,接收方需要时刻准备好接收数据,只需要辅助bit串作为启停标识,因此传输效率高,也可以一对多进行通信;
    • 异步通信】(Asynchronous communication):典型代表是UART协议,双方使用各自的时钟,接收方是通过识别数据包中的起始位和结束为来实现信息的同步的,因此传输效率低,只能一对一通过信。通信前,需要知道波特率、数据长度和开始停止位。关于其他参数比如奇偶校验位、空闲位等一般不用设置,详细信息可以参考UART串口协议详解—知乎。UART通信,需要三根线:
      • 发送数据线:TX
      • 接收数据线:RX
      • 参考线:GND,给定参考电压

并行通信:

  • 以字节(Byte)或字节的倍数为传输单位;
  • 一次传送一个或一个以上字节的数据,数据的各位同时进行传送;
  • 由于并行数据无法携带时钟信息,为确保信号时序一致,需要额外的时钟信号线;
  • 适合于外部设备与PC之间进行近距离、大量和快速的信息交换。计算机的各个总线传输数据时就是以并行方式进行的;
  • 并行通信的特点就是传输速度快,但当距离较远、位数较多时,通信线路复杂且成本高

串口通信的原理

串口参数:

  • 波特率:下面有解释
  • 起始位:低电平,逻辑0
  • 数据位:数据位可以是5、6、7、8,9位等,构成一个字符(一般都是8位)。如ASCII码(7位),扩展BCD码(8位)。先发送最低位,最后发送最高位
  • 校验位:也称奇偶校验位,那是因为UART中,为了验证数据传输无误,通过计算'1'的个数来校验数据。大多数情况下都不使用校验位,串口校验分几种方式:
    • 无校验(no parity)
    • 奇校验(odd parity):如果数据位中“1”的数目是偶数,则校验位为“1”,否则校验位为“0”
    • 偶校验(even parity):如果数据为中“1”的数目是偶数,则校验位为“0”,否则校验位为“1”
    • mark parity:校验位始终为1(不常用)
    • parity:校验位始终为0(不常用)
  • 停止位:它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。 由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备之间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟的机会。停止位个数越多,数据传输越稳定,但是数据传输速度也越慢。

每次发送的数据都是10位二进制的数据,第一位永远是低电平,最后一位永远是高电平,中间是8位二进制的数,上图中的65正好对应的ACSII码的字母A,即微控制器向电脑发送这一串二级制数其实就是发送字母A。串口通信采用的是TTL逻辑,高电平范围2.4~5 V,低电平0~0.4 V。

波特率(baud rate):在我们发送上述信号的时候,必须要有时间间隔,这个时间间隔取决于串口通讯的波特率,波特率9600的意思就是在1秒内发送9600位这样的二进制数位,也就是每一位数据的时间间隔为104 微秒。如果选择115200的波特率,则在一秒内可以发送更多的数据位。我们发送的时间间隔和波特率要严格对应上,否则你把数据发送过去,对方可能已经错过了接收时间,出现数据错乱。波特率设置得越高,采样出错的可能性越大。由于是异步通信,数据采样就难免会有误差,为了减小这个误差,实际采样检测到开始位之后,等待半个位时间(0.5*1/baud rate,对于9600波特率,就等待52 微秒)后,以此为基准进行采样,这样可以保证采样点可以在每一位的中间。

labview的visa使用中,或者arduino等其他设备的串口使用中,一般就关注波特率、数据位(长度)、停止位就行了,校验位和控制流等一般不用管。现在的实际应用中,串口发送数据没有上面的那么麻烦,很多底层的东西都封装起来,以arduino为例,发送字母C的程序如下。

RS232/RS485

正如我们前面讲的总线的三种标准,RS232/RS485总线的硬件标准,即电气特性不一样,但是软件标准,即UART协议是一样的,因此我们可以用同样的windows底层驱动程序。

串口通信的TTL高低电平可能会被其他外界电场干扰,这就导致了其通信距离很短,为了提高其稳定性,美国电子工业联盟制定了一个RS232标准,其中RS表示Recommended Standard。RS232的接口虽然有很多线,但是一般我们只用其中的三根,分别对应TX、RX和GND。串口通信是全双工通信。

TTL电平转换为RS232电平之后,可以增大高低电平的范围,增强信号的抗干扰能力。注意TTL的高电平对应RS232低电平,TTL的低电平对应RS232的高电平。

RS232也是全双工通信,通讯距离可达15米,但是速率只有20 K(对应19200的波特率),面对更为严苛的工业环境和更远的距离需求,这显然不够用,于是人们又制定了RS485标准。RS485使用差分信号+双绞线,这样在某一处受到干扰的时候,两条线路是同时受到差不多程度的干扰,但是二者的差值变化并不大,于是对应的电平也会保持不变。另外RS485也不需要GND作为参考电平。

RS485一般是半双工通信,即在某一时刻要么在发送数据,要么在接收数据,不能同时进行。这样的好处是它可以进行一主多从的组网通信,也就是可以和很多设备进行通信,而串口通信和RS232只能进行简单的点对点的通信。无论是串口通信,还是RS232或者RS485只是定义了不同的高低电平,对我们的编程几乎没有影响,我们只需要会简单的串口通信就能进行RS232或者RS485通信。

拓展资料:串口、COM口、TTL、RS232、RS485区别详解

双绞线(twisted pair,TP):是一种综合布线工程中最常用的传输介质,是由两根具有绝缘保护层的铜导线组成的。把两根绝缘的铜导线按一定密度互相绞在一起,每一根导线在传输中辐射出来的电波会被另一根线上发出的电波抵消,有效降低信号干扰的程度。 双绞线一般由两根22~26号绝缘铜导线相互缠绕而成,“双绞线”的名字也是由此而来。实际使用时,双绞线是由多对双绞线一起包在一个绝缘电缆套管里的。如果把一对或多对双绞线放在一个绝缘套管中便成了双绞线电缆,但日常生活中一般把“双绞线电缆”直接称为“双绞线”。 与其他传输介质相比,双绞线在传输距离,信道宽度和数据传输速度等方面均受到一定限制,但价格较为低廉。

虽然RS-485 并不直接指代电缆类型,而是指数据通信的电气特性和协议规范。 通常情况下,RS-485 使用双绞线电缆,其中一对绞线用于数据传输,而另一对绞线用于信号地(ground)。这种双绞线的结构有助于减小电磁干扰,提高通信质量。 

 

VISA、串口调试、驱动

VISA:Virtual Instrument Software Architecture的缩写,是仪器编程的标准I/O API(应用程序接口)。 LabVIEW的VISA是一种虚拟架构,无论你用的是什么通讯协议或者接口,都可以用VISA调用。VISA可以控制GPIB、串口、USB、以太网、PXI或VXI仪器,并根据使用仪器的类型调用相应的驱动程序,用户无需学习各种仪器的通信协议。VISA独立于操作系统、总线和编程环境。换言之,无论使用何种设备、操作系统和编程语言,均使用相同的API。

VISA的安装:安装完labview就可以找到VISA的相关图标,但是不能用,还需要额外安装VISA。可以在NI MAX或NI Package Manager里查看是否成功安装VISA。

四个VISA函数:(常用)

  • VISA配置——首先,拨对方号码,号码肯定要配置正确吧,不正确肯定达不到对方的,VISA配置串口相当于你给对方拨电话;
  • VISA写入——其次,给对方说要说的话,这个相当于VISA串口写;
  • VISA读取——你说话,当然也也听对方说话,那就是VISA串口读;
  • VISA关闭——通话结束,要挂电话,挂电话相当于关闭VISA。
    注:不关闭 VISA,你的串口的控制权,一直没被释放,你的 串口就工作不正常了。

 

COM串口(Communication Port):查看串口的方法:

  • 右键我的电脑(此电脑) → 管理 → 系统工具 → 设备管理器 → 端口
  • NI MAX里查看
    注:端口可能被隐藏起来了,这时候用点击查看 —  显示隐藏设备

串口虚拟软件:可以帮助你调试设备连接,确认硬件连接是否正常,参考视频。实际程序运行的时候需要用一个或多个USB连接多个仪器串口,但是在程序编写和调试过程中,电脑并没有和仪器相连,这种情形就需要串口虚拟软件。比如我们可以利用该软件虚拟出两个串口(不常用的串口名COM10和COM11)并配对,可以在NI MAX里面确认是否创建成功,然后进行相应的程序编写测试。

串口调试助手:一个用小软件写的,占用COM10,另一个用labview写的,占用COM11,两个串口相互收发信息。串口调试助手(CM精装版),下载地址

 

 

 

Instrument Driver(设备驱动):所谓的驱动,也就是封装好的底层的串口通信程序,也是程序而已,只不过别人帮你做成了子 VI,让自己容易用。国外的很多仪器,都是有现成的 LV 程序驱动的。如果你要做仪器驱动,你最好先到网上搜搜,看有木有现成的。 有现成的,开发速度就好多啦。 每个仪器驱动,会提供对应的调用例子,大家看下例子,大概知道怎么用就好了。有时候,自己把例子稍微改动一点点,就变成自己的程序了。如果手边的仪器搜不到现成的驱动,那就只能自己写了,看仪器的 SCPI 指令是很麻烦的。

四种找驱动的方法

  1. 可以在NI官网的IDNet下载对应设备的驱动,参考使用视频
  2. 自己在仪器厂家官网或者谷歌上搜;
  3. 打开labview,在菜单栏 → Help → Find Instrument Drivers → 扫描仪器安装对应的驱动(不一定都支持)/或手动输入仪器品牌型号;
  4. labview也会自带仪器驱动的例子;

说明

  • 第三种方法安装的驱动:在程序框图面板-右键 → Instrument I/O → Instr Drivers,即可进行编程。但是第一种方法或第二种方法,你需要自己在程序框图面板-右键 →select a VI然后找到你安装驱动的路径。
  • 第三种和第四种方法都会把驱动放在一个默认的文件夹里\National Instruments\LabVIEW 20xx\instr.lib,比如我的电脑里面的位置是C:\Program Files\National Instruments\LabVIEW 2016\instr.lib。

SCPI 指令(Standard Commands for Programmable Instruments)——使用方法:在NI MAX——Devices and Interfaces——COM X——Open VISA Test Panel。

比如电脑连接上Velleman PS3005D电源,然后刷新NI NAMX by VIEW—Refresh,然后进入Open VISA Test Panel——Input/Output,然后输入*IDN? (波特率9600),于是返回的内容是仪器的型号。如果输入的命令是OUT1,那么电源就处在输出状态。

SCPI是一种基于ASCII的仪器命令语言,SCPI命令是通过ASCII字符串形式在命令与仪器进行交互的。SCPII命令定义了一套用于控制可编程测量仪器的标准语法和命令,它包含两种类型的命令:通用命令和子系统命令。 通用命令主要用于控制重设、自我测试以及状态操作,以星号“*”开始,没有层次结构. 具体的仪器特定控制命令则因厂家而异,可查阅各厂家对外公开的通信命令手册。拓展阅读参考【SCPI】基础知识—CSDN

 

参考资料:
(1)《 小草手把手教你 LabVIEW 串口仪器控制》(提取码:57k9)

 

 

 

Labview每日一练

1.计算1+2+3+......+100的两种方法:
(a) for循环的移位寄存器,对for循环右键选择Add shift register。
(b) 反馈节点,Move initializer loop out,可以显示每次迭代结果。
对于反馈节点,要右键勾选Move Initializer One Loop Out(将初始化移出一层循环),然后赋值为0。
两种方法的区别:移位寄存器在比较复杂的程序经常用到,但是只有整个循环结束后,才能显示出最后的结果;反馈节点的方式更直观,而且每次计算的结果都能实时显示出来。

2. 利用三种方法实现对公式 \(Y=A X^2+B X+C\) 的计算:

  • 复合运算
  • 公式节点:里面其实是运行C语言编写的计算程序;(注:如果只有一个输入,那么可以采用numeric—expression node)
  • 快速公式VI

3. 把上面练习的程序生成子VI,并对子VI的图标进行编辑。生成后在其他VI中调用。目标是学习子VI的制作和调用。

  • 第一步,将目标子VI的参数分别对应到右上角的图标,左侧是输入,右侧是输出;
  • 第二步,根据个人喜好,编辑图标;
  • 第三步,将子VI放在同一个文件夹中,在新的VI中,直接拖动到新的VI中即可进行调用。,

4. 给程序框图面板加密。

5. 在实现对公式 \(Y=A X^2+B X+C\) 计算的基础上,加上事件结构,实现单击一次按钮计算一次。

  • timeout默认是-1,也就是永远不超时,超时限制是为了避免程序长时间运行不出结果,这样通过超时的时间限制,可以让程序强行终止。我们这里的timeout设置为比较合适的50 ms足够;
  • 这个停止按钮,触发的选择也是多种多样的。值改变是从布尔代数的角度看这个按钮,另外也可以从鼠标或者键盘的操作来触发程序停止。
  • 该程序相比原始程序的好处是,原来的没有循环的程序,运行完一次程序就终止了,而这里的设计更像一个计算器,一直待机,只要输入值改变+点击计算按钮,就会出现新结果。

6. 设计评分程序

  • 这里展示了“判断范围并强制转换”图标的运用,如果左侧两个斜着的正方形是实行的,表示能取到上下限,其实就是开和闭;
  • 这里的数值输入控件,我们使用了属性节点——值;
  • 这里的两个字符串显示控件,我们使用了属性节点——值——change all to write;
  • 此题,可以利用条件结构的分支选择,分支选择器既可以是上面的布尔型,也可以是数值型,比如60...90表示大于等于60,小于等于90。

7. 分别手动创建和自动创建一个二维数组,然后实现对此数组的元素替换、行替换、列替换和子集替换。

8. 产生一个\(4 * 4\)的整数随机数组, 随机数在0到100之间。找出 数组中的最大值和最小值,找出数组中是否存在数值50,若存在,指出此数组元素位于数组中的位置。

9.
(1) 在前面版输入一段字符串,如果字符串的长度小于10,弹出"输入长度过短"的提示,如果内容中有"SB",把"SB"替换为"LabVIEW"。
(2) 输入一段字符串,把字符串中的空格转换为回车换行符。

10. 把IP地址转换为整数数组,每个数组元素存储一段IP。

11. 把一段文字存储到txt中,然后再读取出来。这里学习一下文件I/O操作。

不能一边写一边读,所以都是先写完,然后再读取,这就要选择flat sequence structure,另外对于文件I/O中的read from file,可以选择read lines和convert EOL(End of Line,你换行它就换行),来变化显示效果。

12. 随机产生1~100之间的1000个整数数字,把这100个数字存储到txt中。

13. 模拟生成10组温度和湿度数据,每隔1秒模拟生成1组数据,模拟生成1次存储1次,把模拟生成的数据存储到同一个txt中。

对一个txt进行多次写入的话,往往后一次存储的内容会覆盖前一次的内容,解决办法是open/creat/replace file命令。如果1234.txt原来就存在,就直接往里面写内容,如果不存在就创建一个,这就是open or creat。

14. VI可以多次运行,产生的数据存储到同一个txt中,不得把上次存储的数据清除,如何修改上面的VI,结果如下,只需要修改左侧少部分即可。

 

 

 

我的Labview实例

 

实例1:labview + arduino控制板子上的LED(默认引脚)的开关:

对应的arduino程序为

int comData;     //定义从串口接收过来的数据

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);       //初始化串口,波特率设置为9600
  pinMode(LED_BUILTIN, OUTPUT);     //设置数字引脚为输出模式
}

void loop() {
  // put your main code here, to run repeatedly:
  if (Serial.available() )   //检测串口缓冲区是否有数据
  {   
    comData = Serial.read();    
    if (comData == '1')        //接收到该命令,则执行关灯
    {
      digitalWrite(LED_BUILTIN, LOW);
      Serial.write('1');
    }
    if (comData == '0')        //接收到该命令,则执行开灯
    {
      digitalWrite(LED_BUILTIN, HIGH);
    }
  }
}

说明:接通之后,单击button virtual那么右侧的LED virtual和板子上的LED都会变点亮,再次单击,就会熄灭。

改进-实例-1:我想通添加一个数组,将数据依次写入到arduino,控制板子上灯多次亮的时间长度,目前的问题是,数组的数据都是一次性传给arduino,执行完毕了,需要想想怎么修改。

改进-实例-1:另外,由于实验测试过程中,LED点亮的时长,对应于shutter打开的时长,我们这里可以直接固定该时长,然后arduino收到点亮的命令(比如字母"o"),那么就点亮LED,持续亮一段时间后,再关闭该LED,然后arduino给labview写入一个数据(比如字母"f"),那么labview就可以去执行下一个循环。(重要)

 

实例2:labview上位机 + arduino 下位机
实例1中,只是labview往arduino发送命令,并没有arduino向labview传递信息。这里展示的例子是labview和arduino之间“打电话”,而不是单向传输信息。(可以参考别人的视频)

上面的程序不能单独运行,因为必须要有下位机,这里我们用arduino作为下位机,其接收到的信息,又print出去,然后被上图的read 函数读取出来。arduino的程序如下:

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);       //初始化串口,波特率设置为9600
}

void loop() {
  // put your main code here, to run repeatedly:
  while (Serial.available() )   //检测串口缓冲区是否有数据
  {   
    char pos = Serial.read();    
    Serial.print(pos);
  }  }

 

实例3:labview控制ocean optics的光谱仪

参考视频-OmniDriver & LabVIEW Part 2,点击运行,然后点击run,然后设置积分时间。

 

另外,通过在菜单栏 → Help → Find Instrument Drivers安装驱动的方法,可以安装ocean optics的驱动。然后可以在程序框图面板-右键 → Instrument I/O → Instr Drivers进行编程,比如下面的建议测试程序。注意:需要点开initialize,然后按里面的文字说明安装Ocean Optics QE65000_vista.inf或其它ocean optics光谱仪对应的文件才能运行。

.inf文件——是一种纯文本文件,通常用于描述设备或文件等数据信息,特别是在Windows操作系统中用于安装设备驱动程序。它由标准的ASCII码组成,可以用任何文本编辑器打开和编辑。INF文件包含设备安装组件用于在设备上安装驱动程序包的所有信息,包括支持设备的一个或多个驱动程序以及使设备联机的设备特定的配置或设置。

 

实例4整合步进电机+舵机+光谱仪(HR2000+)进行radio-photo-luminescence的测试

步进电机的初始化:先把步进电机转到完全挡住X射线源的位置,然后设置反转600步,即为测试的步进电机的初始位置。调试程序如下:

#include<Stepper.h>
// 这里设置步进电机旋转一圈是多少步(可以根据步进电机实际进行修改,28BYJ-48 八拍为64步,单四拍为32步)。
//根据您的步进电机参数修改。
#define STEPS 64
//设置步进电机的步数和引脚(就是注意点2里面说的驱动板上IN1~IN4连接的四个数字口)。
Stepper stepper(STEPS, 8, 10, 9, 11);
void setup()
{
// 以每分钟转速设置电机速度,此功能不会使电机转动,只是设置调用step()时的速度。
stepper.setSpeed(500);
// 初始化串口,用于调试输出信息
Serial.begin(9600);
}
void loop()
{
stepper.step(600); //4步模式下旋转一周用2048 步。8拍模式下旋转一周用4096步。
delay(500000);

}

舵机的初始化:将舵机设定到90的位置,然后正好挡住LED光源,然后0的位置是没有挡住光源的地方。调试程序如下:

#include <Servo.h>
 
#define PIN_SERVO 6
Servo myservo;
 
void setup()
{
  myservo.attach(PIN_SERVO);
}
 
void loop()
{
  myservo.write(0);  // 0对应于舵机没有挡住的情况,有UV
  delay(3000000);
  myservo.write(90);   // 90对应于舵机有挡住的情况,没有UV

  delay(100000);
}

调试完毕后的步骤:
(1) 启动交互的arduino程序,然后电机会逆时针转动300步。

#include<Stepper.h>
// 这里设置步进电机旋转一圈是多少步(可以根据步进电机实际进行修改,28BYJ-48 八拍为64步,单四拍为32步)。
//根据您的步进电机参数修改。
#define STEPS 64
//设置步进电机的步数和引脚(就是注意点2里面说的驱动板上IN1~IN4连接的四个数字口)。
Stepper stepper(STEPS, 8, 10, 9, 11);

#include <Servo.h>
#define PIN_SERVO 6   //设置舵机的引脚为6
Servo myservo;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);       //初始化串口,波特率设置为9600
  //Serial.setTimeout(50);
  stepper.setSpeed(500);  
  stepper.step(-300);   // 对应于电机转到挡住X射线,没有X射线
  myservo.write(90);    // 对应于舵机有挡住的情况,没有UV
  //delay(30000);
  Serial.write('s');
  myservo.attach(PIN_SERVO);
}

void loop() {

  // put your main code here, to run repeatedly:
  if(Serial.available()>0)   //检测串口缓冲区是否有数据
  {   
    char comdata=Serial.read();
    switch(comdata)  {
    case 'a':
    stepper.step(-300);   // 对应于Cu片挡住的情况,没有X射线
    myservo.write(0);     // 对应于舵机没挡住的情况,有UV
    delay(5000);          //  单次 PL测试需要的时间,完成一次PL测试(第二到第n次)。
    myservo.write(90);    // 对应于舵机有挡住的情况,没有UV
    Serial.write('d');        //  告诉labview命令执行完毕。
    stepper.step(300);    // 对应于没挡住的情况(回到有X射线),

    break;

    case 'c':   // void setup() 中只执行一次给labview写入s,labview等待一段时间(数组第一个数)后(开启XRD),labview给arduino写入c
    myservo.write(0); //  对应于舵机没有挡住的情况,有UV
    delay(5000);     // 程序第一次开始PL
    myservo.write(90);  // 对应于舵机有挡住的情况,没有UV
    stepper.step(300);  //对应于Cu片没有挡住的位置,有X射线
    Serial.write('d');  // 告诉labview,第一次PL测试执行完毕
    break;
}  
  }
}

(2) 启动labview程序并进行如下的设置:(a) 积分时间设定为2秒。 (b) 选择arduino对应的com端口。 (c) 导入辐照时间的txt程序。 (d) 给保存数据的txt起一个名字。

(3) 点击labview的run,然后点击START/PAUSE for Spectrometer,即可开始测试。首先会等待一定时间(由辐照.txt决定),这个时候可以启动X射线源,然后舵机会打开,测试没有辐照的第一个光谱数据,测完后舵机挡住LED,然后挡住X射线的步进电机打开,让X射线辐照。

实例-5,配合爱丁堡测反射率

实例-6,Avantes_Labview

实例-7 智能电源-KA3003P  ( 提取码: smbv)

方法-1,虽然上面链接的程序对应的电源型号是KA3003P,但是可能对其他厂家的也适用,比如我们手头的Velleman PS3005D程序来源-三易电子。

方法-2, 直接通过VISA,结合电源的仪器控制指令来实现简单功能,比如给串口输入OUT1那么等同于按了电源上的ON键。

方法-3,就是利用网友写好的驱动(各种子vi)来实现对KA3005P的控制。驱动安装完成后,在程序框图面板,右键 → Instrument I/O → Instr Drivers →  PSU KA3005P。

来自Stefan Penov个人网站,为了防止失效,特摘录如下

PSU KA3005P Driver

Couple of years back I needed a lab power supply and I bought one, which supports computer control. RND Lab 320-KA3005P is the model. Nothing fancy, but does its job. It came with software for computer control. I immediately recognized LabVIEW controls and looked for LabVIEW driver, but couldn’t find one. I decided to write one myself. The instructions manual was not bad and provided most of the commands. For some I had to search for manual of other similar power supplies. It turned out that there are multiple companies, which use the same commands (perhaps same firmware and maybe even same hardware made in the same factory).

The driver I wrote should be fully compatible with the following brands and models:

  • RND Lab 320-KA3005P
  • Tenma 72-25xx series
  • Velleman PS3005D
  • Korad KA3005P

Other models of same manufacturers with two channel outputs are also supported. I only own the first one and haven’t tested with the others, but according to their manuals they use the same commands and type of communication. Future firmware changes might make some models incompatible with my driver, so if it doesn’t work, that might be the reason.

The driver requires VISA installed in LabVIEW. This is needed for serial communication with the power supply. VISA can be downloaded from National Instruments’ website. I did not include it in the package to keep its size small (VISA is a few hundred Mb).

You can download the driver zip file here: download link (改成了我的网盘地址). It includes the full source code and VIP installer for JKI VIPM.

 

实例-8 智能电源-QL355

注:QL355连上电脑,并不出现新的串口,不知道是我用的那个电源有问题还是什么原因。

这个型号不同,实例7中的程序并不适用。对应TTI-QL355,由于这个是比较大的厂家,我们可以在TTI官网-QL Series II下面的Data and Downloads找到QL-P series Power Supplies LabVIEW and CVI driver V1.8.0 - (ZIP / English)并下载,然后将得到的LLB转化为vi文件。然后在labview运行这些子vi的时候提示需要ivi.dll,于是又通过NI Package Manager下载安装了IVI Compliance Package。

通过上述操作后,labview中使用子vi不报错了,但是是否能控制QL355还有待检验。

另外之前提示需要ivi.dll的时候,又在TTI官网-QL Series II下面的Data and Downloads下载了QL-P series Power Supplies IVI driver V1.8.0 - (ZIP / English),安装的时候提示需要ivi.dll。目前时候还需要这个IVI driver还未知。

下载界面的USB Driver V2.11 - (ZIP / English)可以干啥用还不知道,可能是和虚拟串口有关。

 

 

 

Leave a Reply