LabVIEW高级编程技巧内容概要•NationalInstruments公司简介•LabVIEW高级编程技巧1.用户定义的调试指示器2.定时循环3.基于事件触发的编程4.改善VI的性能5.调用动态链接库NationalInstruments:虚拟仪器倡导者•建立于1976年•超过1,000种测试测量产品•在40个国家设有直属分支机构,600家系统联盟商•中国:研发,区域咨询,技术支持,市场NIHQNI客户的分布•超过25,000个客户分布在多达80个国家•财富500强中95%的制造型企业1.调试指示器•灵活的调试工具,可详细显示数据线上通过的数据•指示器的操作可以体现VI的灵活性和强大功能•传统的调试指示器存在一些缺点,如只能显示数组中的一个元素用户定义的调试指示器•能显示各种数据类型•可定制指示器外观•可定制指示器处理功能•设置条件断点定制你的需求指示器不仅仅可以显示数据•将数据录入文件•对两个指示器之间的执行进行定时•计算总的调用次数或是每秒的调用次数内建的定制指示器•在数据连线上点击鼠标右键•菜单显示所有相关的指示器•指示器存放在目录vi.lib\_probes\[default]下Keepgraphicsbelowthetextandtotheright客户指示器的结构•包含一个控件–控件的数据类型就是所指示的数据线•包含一个指示器–Boolean,类似条件断点•True=暂停执行•False=继续执行Keepgraphicsbelowthetextandtotheright2.定时循环•精确的定时while循环•多个时钟频率的定时•反馈,动态定时特性•多达128个循环优先级•examples\general\timedloop.llb定时循环的配置定时循环3.基于事件的编程•管理用户界面,通常采用的方法有中断响应和事件驱动•中断响应采用轮询机制处理,非常占用CPU资源,还可能会丢失用户界面的响应•事件驱动无需轮询即可捕捉到相关事件,顺序处理捕捉到的所有事件,不会丢失也不会颠倒顺序事件举例事件结构不需要轮询就可以捕捉到自定义菜单上的用户选择ItemTag返回菜单条目MenuRef返回菜单的refnumVirtualInstrument事件类型Application事件举例:•退出应用程序•超时Control事件举例:•关闭前面板•VI上的鼠标移动事件举例:•改变控件数值•特定控件上的鼠标移动通知事件和可滤除事件通知事件通知LabVIEW发生了一个用户行为;只能在EventDataNode中使用可滤除事件在用户界面处理之前验证或改变事件数据,避免影响VI;可在EventFilterNode和EventDataNode中使用LabVIEW7新事件•更多的用户界面事件•动态注册的事件•用户定义的事件•ActiveX事件事件结构的组成部分•EventSelectorLabel–确定观察的事件•Timeout–等待事件的毫秒数;缺省值–1(无限期)•DefaultedTunnels–新型tunnel,允许未连线的事件案例提供缺省值•DynamicEventTerminals–用于动态事件的注册事件结构的组成部分•EventDataNode–确定事件发生时LV提供的数据,与UnbundleByName函数类似•EventFilterNode–确定EventDataNode中可提供的数据子集,可供事件案例修改事件结构的基本使用•通常在While循环中使用•每次循环只处理一次事件,其它时间休眠•在事件结构的左侧边框端口上可获得事件数据事件结构的配置通过对话框来配置事件,右击事件结构的边框,选择“EditEventsHandledbyThisCase…”事件注册和面板锁定•包含事件结构的VI被预留以后,事件就成为已注册的•已注册事件发生后,会进入队列等待直到相应的事件结构开始执行,事件不会丢失也不会出现顺序混乱•默认情况下,前面板被锁定直到事件被处理完–可以关闭锁定,但只针对过滤事件•VI变成空闲后,事件被注销3.1动态事件下列情况时,需要动态注册事件:–事件注册只能发生在应用程序的某些部分–在程序运行过程中需要改变哪些VIs或控件可以发生事件–在subVI中处理事件,而不是仅在注册事件的VI中动态事件RegisterForEventsEventStructureUnregisterForEventsCreateUserEventGenerateUserEventDestroyUserEvent编程模型注册事件连接到事件结构选择动态事件注销事件3.2程序产生的(用户)事件RegisterForEventsEventStructureUnregisterForEventsCreateUserEventGenerateUserEventDestroyUserEvent用户事件编程模型创建并注册用户事件产生用户事件注销用户事件消灭用户事件用户事件举例3.3ActiveX事件RegisterEventCallbackActiveX编程模型注册ActiveX事件选择事件创建和编辑CallbackVI总结:事件处理结构•允许在subvi中处理事件代码•提供统一的,简化的事件处理机制–用户界面–接口控制–外部代码–硬件触发–用户定义事件–注册和非注册事件4.改善VI的性能•改进内存使用–使用高效数组函数–谨慎处理字符串和数组–避免不必要的复杂数据结构•减少I/O开销–减少I/O调用的次数–减少开启和关闭资源的次数•减少屏幕更新4.1改进内存使用•LabVIEW处理了大部分内存管理的细节–资源分配,复制,释放,溢出–减少程序框图的大小–提高可读性和稳定性•内存管理自动进行,你不需要过多的干预–理解LabVIEW是何时并如何为你“代劳”内存管理的可以大大提高对内存使用的效率VI在内存中的数据结构•FrontPanel•BlockDiagram•Code–框图编译成机器码•DataSpace–Control/indicator数值–Blockdiagram常量–动态定义的数据FrontPanelBlockDiagramCodeDataSpaceVI何时加载到内存中•始终载入data•平台符合时载入Code(MacOS,Windows,Sun,Linux)•Panel和Diagram在必要时载入(recompiling)MainVISubVIAlwaysinmemoryResidentsometimesFrontPanelBlockDiagramCodeDataSpaceFrontPanelBlockDiagramCodeDataSpace内存使用情况•ToolsAdvancedProfileVIs…•勾选“ProfileMemoryUsage”&“MemoryUsage”•在执行应用程序之前点击“Start”•状态只在程序执行完成后更新•程序执行过程中内存使用情况不能被查看监测内存使用显示内存分配•FileToolsAdvancedShowBufferAllocations内存优化LabVIEW尽量减少内存再分配需要重新分配内存的函数•BuildArray•ConcatenateStringsHighMemoryReallocationLowMemoryReallocation最佳内存使用•尽量使用subVIs•不要滥用全局和局部变量•只在必要时打开subVI前面板•高效地创建和处理数组•不使用大的、复杂的数据类型coerciondots构建和处理数组使用具有inplaceness特点的数组函数Inplaceness是指函数‘inplace’操作数据,而不会另外建立一个数据备份。ReusesBuffersMayAllocateNewBuffersAllocatesNewBuffers子数组•LabVIEW尽可能的重用内存缓冲•子数组不存储实际的数据•子数组在必要时会生成真实的数组•由于子数组不要对数据进行拷贝,因此提高了程序的执行速度子数组子数组函数返回一个7499x2的子数组这个例子程序需要执行2秒钟2GHzPentium4子数组在函数ArraySubset之前引线执行只需5毫秒子数组到真实数组的生成发生在循环之前4.2减少I/O开销•I/OVIs比计算操作多花很多时间•把I/O调用降低到最少–每次调用传递尽可能多的数据–使用多点DAQVIs而不是单点VIsSlowMethod(manyI/Ocalls)FastMethod(OneI/Ocall)减少开启和关闭资源SlowMethodFastMethod•使用底层VIs来减少开启和关闭资源的次数•SlowMethod中,文件被打开和关闭100次FastMethod中,文件只打开和关闭1次保持资源的打开状态•使用底层的文件打开和关闭函数•连接文件读写函数open,read/write的引用提高读速度操作系统不需检查权限、分配新的文件描述符等提高写文件的速度允许操作系统缓冲写操作标准化•LabVIEW以“大字端”形式读写数据•X86机器采用“小字端”形式存储数据•选择不需要转换的数据类型如:–U8,I8,String(data),SGL,DBL•可以编程转换-Flattentostring-Typecast-Manualcode4.3减少屏幕显示的更新•使用高效的controls和indicators•Graphs和charts在接收新数据的时候会重新画图,从而影响执行速度•设计subVI的前面板在执行中保持关闭来减少显示开销•使用多点更新的画图方法–最小化chart更新的次数–获得最高的数据显示速率屏幕显示实例SlowMethod(每次更新一点)FastMethod(每次更新100点)减少循环中不必要的计算•避免将产生相同结果的运算放在循环内•避免在循环中不必要的访问全局变量减少SubVI开销•每个subVI都会有一些开销(大概几十微秒);虽然看起来不大,但如果是在一个循环结构中,就会累加出一个很大结果。•在高速运行的循环结构中,不要显示subVI的前面板•如果可能,将循环结构移到subVI中完成。全局和局部变量•每一次变量的读操作都会给数据生成一个新的缓冲区•在使用大数组、字符串或复杂数据结构时会带来很大影响•从内存使用和执行速度来看,使用数据线永远是更有效的方法属性节点•使用属性节点会引起线程间的交换,从而降低效率•如果只是为了更新控件的值,不要使用属性节点•如果同时改变其它属性,更新数值不会造成更大损失,因为线程交换已经发生了更新前面板控件GoodBetterBest创建高效的平行框图•LabVIEW周期性地在平行循环间切换•使用Wait(ms)function–确保不太重要的循环占用较少的处理器时间5.共享库函数What?Windows中的.dll,UNIX/Linux中的.so,等等Why?降低磁盘空间和内存占用How?•应用程序只在需要的时候调用库函数•程序开始执行以后,由运行链接编辑器来处理所有调用动态链接库(DLL)MicrosoftWindows中的一种软件模块•包含可执行代码和可被Windows应用程序或其它DLL调用的数据•函数和数据只有在运行状态下,被Windows应用程序或其它DLL调用时才被加载和链接•一个DLL包括:-一个特殊函数(DllMain)-几个编程者自定义来完成常用任务的函数DLL特性•不能单独运行的可执行文件•应用程序要求时,由操作系统加载•应用程序把DLL代码作为自己二进制文件的一部分来使用•应用程序不需要知道原始DLL是由什么语言编写的,也不需要清楚这些功能是如何实现的。•DLL就像一个有输出函数的黑盒子LabVIEW中调用SharedLibrary/DLLAdvanced»CallLibraryFunctionNode右击CallLibraryFunctionNode,选择Configure来调用DLL中的特定函数CallLibraryFunction的配置指定需调用的DLL函数和函数参数选择dll的调用规则;对于Win32dl