十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

LabVIEW DQMH框架入门:核心原理、消息机制与实战避坑指南

LabVIEW DQMH框架入门:核心原理、消息机制与实战避坑指南 1. 为什么我会在一堆状态机写不下去之后翻出DQMH1.1 LabVIEW程序最大的敌人需求一直在变最近把手上几个LabVIEW项目重新翻出来维护越改越觉得真正决定程序能不能长期维护的不是某一个采集函数写得是否漂亮而是整个程序的骨架。也正是这时候我决定认认真真把DQMH框架再学一遍。这篇算是我LabVIEW_DQMH框架学习系列的第一篇定位就是浅析先把框架解决什么问题、核心组成是什么、怎么上手、有哪些坑讲清楚不涉及特别深层的源码改造。说句大实话很多LabVIEW工程师都经历过这样一个阶段写第一个完整程序时特别兴奋从串口读取、波形显示到保存数据几十个VI拼在一起用全局变量和状态机串起来最后能跑通觉得自己已经很行了。可一旦客户说这里加个功能那里改个流程噩梦就来了。状态机的枚举越来越多事件结构的分支越堆越长全局变量被十几个VI同时读写改一个地方崩三个地方。最要命的是你根本不敢随便动因为完全说不清哪个VI在哪个时刻改了哪份数据。我印象特别深的一次是给人写一个串口通信的小工具。第一版只有读取、解析、显示三步我用了最经典的while循环加状态机几天就交付了。结果客户后续提了一堆需求双击历史数据弹窗、运行中在线切换波特率、把某段数据单独导出。状态机从五个状态膨胀到十几个状态每个状态里还套着条件判断代码几乎到了只有我能看懂我自己也快看不懂的地步。那次之后我彻底明白了一件事LabVIEW程序最大的敌人根本不是功能写不出来而是需求一直在变代码却接不住变化。1.2 从「能跑」到「能改」的关键一步那怎么让代码接得住变化核心不是用什么了不起的高深算法而是把程序拆成可以独立修改、独立测试的模块让模块之间通过明确的消息通信而不是通过全局变量和控件引用互相纠缠。我当时很自然地想找一个现成的方案。LabVIEW社区里能搜到的架构很多从简单的生产者消费者模式到NI官方的Actor Framework再到各种个人的框架封装。在比较了一圈之后我注意到DQMH这个名字反复出现很多成熟项目都在用它。它的全称是Delacor Queued Message Handler直译过来就是Delacor队列消息处理器。单看这个名字关键点已经全暴露了队列、消息、处理。每个模块都有自己的消息队列外界想调用这个模块的功能时不是直接去拖它的子VI、也不是去读写它的控件而是向它的队列里投递一条消息。模块内部的循环从队列里取出消息按顺序处理该响应就响应该干活就干活。这套思路最直观的价值是把模块和模块之间的关系从直接改内部数据变成了发工单、等回执。写模块的人和调用模块的人之间多了一层缓冲代码之间的耦合被击穿了。后来我把那套串口工具按这个思路重新拆了一版后面再加需求时基本只动对应模块的内部逻辑其他部分完全不受影响。那也就是从那一刻起我决定系统地把DQMH学透。1.3 DQMH是谁写的为什么NI生态里它这么火DQMH最早是Delacor公司推出的开源框架作者之一是Delacor的联合创始人Fabiola De la Cueva后来这家公司被NI收购DQMH也顺势进入了NI生态的官方工具链可以在工具网络里免费下载。说它是LabVIEW社区目前应用最广的开源架构之一一点不夸张。为什么它能火起来我总结有三个原因。第一它把架构从靠经验设计变成了靠模板生成。普通人不用先吃透面向对象、队列、事件驱动所有细节只要会填模板就能产出一个结构规范的模块门槛一下子降到可接受范围。第二很多大厂官方Demo和培训资料都基于DQMH工程师在客户现场遇到的程序大概率就是这套风格会它的人有天然的沟通优势。第三它自带单元测试生成支持能把模块单独拉出来测CI集成也方便这一点非常戳中工业项目工程师的痛点。我第一次用DQMH的时候其实并没有感觉到它有多神奇反而觉得它啰嗦一个简单的功能绕来绕去。但当我把它用在一个多模块项目里并且顺利经历了三轮需求变更之后我才真正意识到之前那种能跑的状态跟能改之间差的正是这样一个看起来有点啰嗦的消息中间层。2. DQMH的核心思想一个模块就是一个带信箱的小团队2.1 队列消息处理器五个字拆开理解想学DQMH第一件事不是急着点鼠标生成代码而是先搞懂它最底层的模型。我用一个生活化的比喻来解释你可以把每个DQMH模块想象成一个独立的小团队。这个团队有自己的办公室、自己的资料库和自己的做事流程。外界想找这个团队办事不能直接冲到办公室翻人家的抽屉只能往门口的信箱里投一份工单然后等团队处理完给你答复。这个信箱就是消息队列。工单就是消息。团队里的值班人员就是事件结构加while循环。工单投递支持先进先出所以消息处理的顺序是确定的不会出现两条消息抢资源导致结果错乱的问题。更重要的是团队内部怎么组织、怎么干活完全是它自己的事外界不需要知道。只要它对外提供的接口不变内部随便重构都不影响别人。这里有一个容易被忽略的关键点队列本身天然具有异步缓冲能力。发送方发完消息不需要阻塞等待接收方可以按照自己的节奏处理。这一特性让模块之间不再存在谁等谁的硬依赖系统整体的并行性一下子就出来了。很多初学者在接触DQMH之前都用过队列但只是把它当成传数据的管道没有意识到它其实是整个并发模型的基座。2.2 模块内部的标准三段式状态机DQMH的每个模块脚本生成出来的主VI都是同一个结构套路。我建议拿到模板后别急着改代码先把它的标准状态摸清楚。一般来说模块内部会有一个核心状态机包含三个阶段Initializing初始化、Normal正常运行、Shutting Down关闭。初始化阶段处理资源打开、参数设置、硬件自检等动作。比如一个控制NI 6221采集卡的模块初始化时就要打开设备、配置采样率、设置触发模式。只有初始化完成后模块才会进入Normal状态开始处理外界发来的Request和Message。正常状态下事件结构会响应各种消息分支执行具体业务逻辑。关闭阶段则负责释放资源比如关闭设备引用、写入缓存数据、释放文件句柄。这个三段式状态机为什么重要因为它把模块整个生命周期里的边界条件都给定义好了。比如初始化没完成时收到新消息怎么办模板会自动让这些消息排队等待。比如关闭过程中又收到新请求怎么办模板会拒绝处理或交给关闭逻辑。如果没有框架约束这些边界条件全靠工程师临时想很容易漏而DQMH直接用模板把坑填平了。2.3 Request、Broadcast、Message三种消息到底怎么分工DQMH模块之间通信时消息不是只有一种它分成Request、Broadcast和Message三种分工非常明确。这块搞不明白项目做到一半必乱。Request是一对一、同步的请求。发送方发出请求后会等待目标模块处理并返回响应。它适合我要你干活并且等结果的场景。比如UI模块向采集模块发请求把采样率改成1000Hz并且告诉我改成功了没有。这中间有个等待过程所以在UI线程里不能随便用否则界面会卡住。Broadcast是一对多、异步的广播。发送方发出广播后不需要等任何响应所有订阅了这个广播的模块都会收到通知。它适合我完成了一件事通知所有关心的人的场景。比如采集模块采完了一帧数据广播一条NewDataUI模块拿去画波形存储模块拿去写TDMS文件两个模块互不干扰。Message则是模块内部给自己发送的异步消息相当于团队内部自己给自己派活。它最大的用途是把一个耗时很长的任务拆成多个步骤避免一个模块的Event结构被长时间占用从而阻塞其他消息的处理。比如采集模块收到Start Acquisition请求后不直接在大循环里执行耗时操作而是给自己发一条Message让采集任务在后台被逐步处理。这三种消息我整理成了一张表方便对比记忆消息类型方向同步/异步等待结果典型场景Request一对一同步会等待返回读取设备ID、设置参数、请求启动Broadcast一对多异步不等待数据采集完成、错误发生、状态切换Message自我投递异步不等待长任务分步处理、延迟动作2.4 模块之间为什么不允许直接调VI这一点可能是DQMH学习过程中最反直觉、也最容易被无视的一条规则模块与模块之间绝对不能直接调用对方的内部VI更不能去读写对方的控件和局部变量。我见过太多人刚做完第一版DQMH模块扭头就在UI模块里拖出采集模块的温度显示控件开始连线取数据。当时跑得确实很爽但等下一轮需求变更时就会发现两个模块的内部实现紧紧缠在一起想改其中一个另一个立刻报错最后还是绕回了当年全局变量到处飞的老路。DQMH之所以强制你走消息通道本质上是把依赖关系从隐式变成了显式。当你通过Request和Broadcast通信时模块A依赖模块B哪些能力一眼就能从代码里看出来。而当你通过直接访问控件通信时这种依赖是隐藏的、散落的、难以追踪的。你可以在工程里做个快速自检如果发现一个模块的VI大范围引用了其他模块的私有控件那基本可以断定通信方式用错了。正确做法是停下来重构UI模块需要数据就发Request去拿或者直接订阅数据模块的Broadcast。3. 跑通第一个DQMH项目一个模块需要多长时间3.1 装环境VIPM装DQMH Template那几步我第一次装DQMH时浪费了不少时间所以这里把完整流程放出来照着走就行。首先你需要一个LabVIEW开发环境理论上2014之后的版本都能用我自己在2020和2023上装过都比较稳。旧版本建议至少2018后面装依赖时会更省心。然后准备VIPM全称VI Package Manager也就是LabVIEW的包管理器。VIPM社区版可以免费使用能从Tools Network拉包。安装完VIPM后在LabVIEW的工具菜单里会出现VI Package Manager入口。打开它在搜索框里输入dqmh就能看到Delacor DQMH Template。我习惯装当前最新的Release版本不会去选Beta。装的时候VIPM会自动解析依赖常见依赖包括OpenG工具包等一般会自动拉取。装完后重启LabVIEW工具菜单里就会多出一个DQMH Module Creator入口。有一个容易栽的坑某些电脑上VIPM搜索不到DQMH大多数原因是VIPM源没有配置好或者网络被限制访问了Tools Network。这时候可以手动从NI Tools Network网页下载DQMH的安装包再用VIPM的从文件安装功能装进去。3.2 用Module Creator生成模板先别急着改代码安装完成之后点Tools菜单里的DQMH Module Creator会弹出一个生成界面。你要做的第一件事是给你的模块起一个合理的名字。这里请记住我踩过的坑模块名只允许英文和数字别用中文、空格和特殊字符。我最早给自己的采集模块起名DAQ模块结果脚本直接报错之后排查了很久才发现是这个原因。改成DAQModule之后一次通过。界面里还有几个选项比如是否需要初始化、是否需要Message处理、是否需要Shutdown处理以及是否生成单元测试。如果你是第一次学习我建议全部默认先跑一遍后面再慢慢研究每个选项的含义。点击Generate后工程目录里会多出一个以模块名命名的文件夹里面放着模块的.lvlib、.lvclass、主VI和Helpers库。打开主VI你会看到一个已经搭好的while循环加事件结构框架。这个框架里预设了好几个消息分支初始化模块、正常处理消息、关闭模块等。你可能会觉得这个模板很空但在DQMH里规整的空框架恰恰是它最大的价值。模板帮你把所有边界条件和通信机制安排好了你只需要在正确的位置填充业务代码。3.3 亲手添加一个Request和Broadcast验证模块间通信只看模板不动手永远学不会DQMH。最直接的验证方式是亲手给一个模块添加一个Request和一个Broadcast然后让两个模块互相通信。假设项目里有两个模块一个叫DAQModule负责产生数据一个叫UIModule负责显示数据。我想让UIModule向DAQModule发一个Request请求读取当前的采样率。在DAQModule上右键找到DQMH编辑菜单选择添加Request名字取GetSampleRate。脚本会自动重新生成代码模块主VI里会多出一个专门处理这个Request的事件分支同时模块的lvclass下会生成一个对应的GetSampleRate API VI。然后给DAQModule添加一个Broadcast名字取NewData。同样生成完成后模块里会多出一个广播发送节点。接下来我在DAQModule主VI的某个循环里模拟采集数据得到新数据后调用Broadcast NewData把数据推给所有订阅者。最后在UIModule里调用DAQModule.vi中的GetSampleRate API就能拿到采样率返回值再订阅NewData广播就能实时接收数据并显示。重点在于UIModule从头到尾没有访问DAQModule的任何内部控件所有交互都是通过DQMH自动生成的API完成。这一步跑通之后你对DQMH的信任感会立刻建立起来原来模块之间可以这样干净地通信。3.4 生成代码之后哪里是留给你的改动区很多新手在DQMH上放弃其实不是学不会而是喜欢手痒去动模板自动生成的代码结果再添加新消息时脚本找不到原来的结构直接报错。所以这里最重要的是明确改动边界。可以放心改动的地方是每个事件分支内部的业务逻辑。比如初始化分支里打开设备、Normal分支里处理数据、Shutdown分支里释放资源这些地方都是留给你的业务填充区。模块的自定义属性比如你希望模块内部保存的配置参数、状态缓存也可以自己加。尽量不要动的地方是消息循环的主框架、事件分支的分支名、队列的创建和销毁逻辑、脚本生成的API VI的连接板。如果你改了这些下次用脚本添加Request时它可能无法识别现有结构导致重新生成失败。我见过有人为了修一个bug直接改消息队列逻辑结果整个模块都无响应最后花了半天重新生成模板。这也是DQMH的使用哲学框架生成的代码是骨架业务代码是血肉。你把血肉填进骨架里两者分工明确合作才能长久。4. DQMH和Actor Framework、经典状态机比到底赢在哪4.1 和传统状态机、生产者消费者模式对比很多工程师接触DQMH之前最常用的架构就是状态机和生产者消费者模式。这两种模式在小型项目里确实够用但一旦规模上来问题就很明显。经典状态机的核心是一个枚举变量加一个while循环通过切换枚举值来控制程序流程。单设备、单任务的小工具非常适合代码直观、调试简单。但当你有多个设备、多个并发的任务时状态机的状态数量会像排列组合一样膨胀而且每个状态里往往还要再嵌套条件结构最终变成一个又大又脆的if-else城堡。生产者消费者模式比状态机前进了一步它已经把队列这个核心组件引入了让数据生产与数据处理解耦。但它也只解决数据流问题消息的定义、模块间的请求响应、错误传播通道全部都要你自己搭。你会发现每一个项目搭出来的队列模型都不一样团队成员之间互相看不懂。DQMH的定位就是把上面这些公用脚手架全部标准化。它用同样的模板、同样的队列逻辑、同一套Request/Broadcast/Message消息体系把架构层面的设计决策提前替你做了。你不需要每做一个项目就重造一套轮子只需要照着模板填业务逻辑。4.2 DQMH vs Actor FrameworkLabVIEW圈子里常常有人拿DQMH和Actor Framework比较我对这两个框架都有过实际使用经历说说我的感受。Actor Framework是NI的官方框架功能确实更底层、更强大。它基于面向对象和消息传递支持Actor的动态创建和销毁消息体系也更灵活非常适合那种需要动态管理大量并行任务、运行时拓扑会变化的复杂系统。但它的学习曲线非常陡峭。新手需要先掌握LabVIEW面向对象的基本概念理解Actor的生命周期、消息邮箱、嵌套关系否则写出来的Actor项目经常出现消息丢失、资源无法释放之类的诡异问题。DQMH可以理解为一个轻量化的Actor Framework。它也使用模块和消息的模型但通过代码生成器把最复杂的设计模式固化成了模板你不需要深入理解队列消息底层机制就能上手。代价是它的灵活性不如AF模块之间的嵌套和动态管理能力偏弱。我的建议是分阶段来。如果团队刚接触架构先学DQMH用DQMH把队列消息模型理解透等真遇到DQMH满足不了的大型动态系统时再迁移到Actor Framework平滑过渡别一上来就追AF否则大概率会劝退。4.3 什么时候不该用DQMH虽然我一直在推荐DQMH但它并不是银弹有些场景我明确建议不要硬上。第一种是硬实时控制。DQMH的消息处理本质是队列加事件结构延迟是微秒到毫秒级别的对于严格的PID闭环或μs级触发控制它并不合适这种场合应该用FPGA或者RTFPGA的架构。第二种是非常简单的单任务程序。如果程序一共就一个采集循环加一个显示你硬拆成三个DQMH模块反而增加了理解成本。架构不是装饰品它是要解决问题的问题本身很小就没必要上大杀器。第三种是团队完全没有队列和模块化开发经验的情况下直接铺开大项目。我之前吃过这个亏团队里几个人一起写DQMH结果有人偷偷绕消息直接调子VI最后代码风格五花八门。后来先做了两轮内部分享把核心思想统一了效率才上来。4.4 选型建议什么场景该用什么方案我根据自己的项目经验做了个选型表你可以参考项目场景推荐方案理由单设备、单任务的简单采集显示状态机 生产者消费者结构直观开发速度快多设备、多模块的桌面测控系统DQMH框架规范模块解耦团队协作友好复杂动态系统运行时模块增删频繁Actor Framework生命周期和嵌套能力更强μs级硬实时控制RT FPGADQMH/AF都无法保证确定时序需要大量自动化测试的长期项目DQMH 单元测试模块独立测试方便回归成本低我个人的判断基准很简单凡是你会因为加一个功能就要动好几个地方而头疼的项目就值得考虑DQMH。反过来如果需求基本固定、模块之间没有多少交互那保持简单反而更好。5. 学习DQMH一定会踩的坑含排查思路5.1 模块命名和生成顺序造成脚本失败我学DQMH时踩的第一个坑就是命名问题。当时我兴冲冲地创建了一个模块名字直接写中文采集模块结果生成脚本报了一长串错误。一开始我还以为是VIPM安装有问题反复重装了三次都没用。后来静下来看报错日志发现脚本明确提示模块名里包含了不支持的字符。把名字改成AcqModule后一次通过问题解决。这个坑的排查思路其实很简单凡是脚本生成报错不要用眼睛猜先去找到生成日志。在DQMH Module Creator的运行界面通常会有一个生成日志窗口里面会写明哪一步执行失败、涉及哪个文件或哪段脚本。大部分错误都能直接定位到文件名、路径或者字符问题上。第二次遇到重新生成失败时我就学乖了先看日志再决定是改名字还是删除旧文件。5.2 把模块当普通VI用绕过消息直接连控件这是我在团队协作中见过最多、破坏力最大的坑。某个模块需要把数据传给另一个模块有人觉得写Request麻烦直接在目标模块的VI里把控件的值引出来接到自己的模块里。当时跑得好好的代码审查也没人发现。结果后面目标模块内部改了一次界面这个引用就断了程序在运行时弹出一堆错误。排查过程特别折磨人。因为直接控件引用不会在调用链里留下任何Request或消息记录你只能靠搜索工程中所有引用关系慢慢找。我后来给团队定了一条铁律模块之间的数据访问一律只能通过Request和Broadcast。凡是直接访问其他模块内部控件的代码一律打回重构。这条规则执行一个月后整体代码质量提升非常明显。正确的排查方法是当你怀疑某个模块被外部直接访问时右键模块主VI选择查看VI层级关系搜索是否有来自其他模块的引用。一旦发现先看清楚它是访问了模块的哪个公共入口还是直连了私有控件后者必须要改。5.3 Broadcast消息丢了多半是接收端还没启动有一段时间我的UI模块老是收不到采集模块发来的广播。数据在采集模块里明明已经产生了广播节点也执行了但UI界面就是没有刷新。我一开始以为是事件结构配置错了反复检查分支名称、消息类型都没发现问题。后来我在广播节点上放了一个探针确认广播确实执行了又在UI模块的广播接收分支上放探针发现那个分支一次都没被触发。这时候我才意识到问题出在订阅时机上。DQMH的广播订阅是运行时的接收模块必须在广播产生之前启动并注册才能接收到消息。如果发送方先广播了接收方还没启动这条广播就相当于投递给了空房间直接丢失。排查链路就是先确认广播发送端有没有执行再确认接收端有没有订阅最后确认两者的启动顺序。实际上我那次问题就出在UI模块启动比采集模块慢等UI启动时第一批广播早就发完了。解决方法是约定模块启动顺序先启动被依赖的采集模块再启动UI模块或者在UI模块初始化完成后主动通过Request请求一遍当前最新数据。5.4 阻塞和死锁Request等待不正确时会发生DQMH里另一个常见问题是界面点了一个按钮之后整个程序卡住。我之前做一个数据导出功能时UI模块向存储模块发送了一个Request要求导出TDMS文件。存储模块在处理这个Request时内部做了一个超大的写入循环耗时几十秒。由于存储模块的Event结构一直被这个Request占用队列里其他消息全部排队UI模块则一直等到天荒地老。这个问题的根因是Event结构本身是单线程的。一个Request内部如果做了耗时很长的动作会阻塞整个模块的消息处理这在DQMH里被称为长任务阻塞。正确的做法是耗时操作不要放在Request的事件分支里同步执行而是通过模块内部的Message事件把长任务拆分。具体来说存储模块收到Export Data请求后立即回复UI已受理然后自己给自己发一条Message在Message分支里慢慢写文件。这样UI不会卡死其他请求也能继续处理。另外所有调用Request的一方都要设置一个合理的等待超时比如3000毫秒超时后主动提示用户目标模块繁忙而不是无限等下去。排查这种问题时我通常会在模块的Dequeue节点上放探针看队列里积压了多少条消息。如果队列长度持续增长说明某个事件分支卡住了。再结合模块的初始化状态灯基本就能定位是哪个分支的问题。5.5 四个非常实用的调试技巧最后分享几个我用下来非常顺手的调试方法。探针是DQMH调试的第一利器。在模块主VI的消息队列取出节点、事件结构的数据出口、广播发送节点上都可以放探针实时观察消息类型、数据和顺序。之前排查广播丢失问题时就是靠三级探针锁定了原因。模块状态灯非常有用。每个DQMH模块模板默认都会在界面上显示当前模块的状态比如初始化中、正常运行、关闭中。如果程序卡住先看所有模块是否都进入了Normal状态再查哪个模块状态异常。我给自己的每个项目都加了一条诊断广播模块内部每隔几秒广播一次模块的健康状态和运行参数汇总到一个总览界面。发现异常时一眼就能对比出几个模块的状态是否同步。单元测试也值得养成习惯。DQMH模板可以生成针对Request和Message的测试代码不需要启动整个系统就能单测一个模块。我在重构采集模块时就先用测试用例把每个Request的输入输出锁死保证重构不破坏原有功能。6. 一个完整的上手练习温度采集小系统6.1 系统拆分UI、采集、存储三个模块到这里我把DQMH的核心概念和常见坑都讲得差不多了但如果你只是看不去动手做一遍这些知识很难变成你自己的。所以我最后给你留一个完整的练习项目也是我用来带新人入门的标准Demo一个温度采集小系统。硬件上可以模拟但思想是通用的。假设你有一块NI 6221数据采集卡外加一台2182纳伏表做同步采集这正好是LabVIEW社区里常被问到的同步采集场景。我们分别建三个DQMH模块AcquisitionModule负责打开设备、定时采样、广播数据StorageModule负责监听广播把数据写入TDMS文件UIModule负责显示波形、接收按钮事件、展示状态。这三个模块之间不允许任何直接控件连线。所有通信都通过Request和Broadcast完成。这样设计的目的是把数据生产和数据消费彻底分开以后想增加一个报警模块或者数据库模块只需要让它订阅同样的广播不需要动采集模块一行代码。6.2 关键Request和Broadcast设计在设计通信时我会先把流程画在纸上再落到代码里。UI模块会向采集模块发送Start Acquisition和Stop Acquisition两个Request都是同步请求这样UI能知道启动是否成功。如果启动失败UI可以直接弹错误提示不用再等一个异步的广播。采集模块正常运行后会在每次采完一帧数据时发送NewData广播。这个广播携带波形数据和时间戳。UI模块订阅NewData拿到数据后更新波形图存储模块也订阅NewData把数据追加写入TDMS文件。这里一帧数据同时被两个模块消费彼此之间没有任何依赖这就是Broadcast的价值。再设计一个错误通道采集模块如果设备异常就广播DeviceError。UI收到后弹框提示存储模块则可以把错误信息记录到日志文件。错误流和正常数据流分离调试时非常清楚。6.3 调试顺序和验证结果新人在练习这个项目时我建议不要一上来就把三个模块同时跑起来因为出问题时根本分不清是谁的问题。我的调试顺序是先跑采集模块单模块让它自己产生数据并广播自己用探针确认数据帧是完整的。然后再启动存储模块观察TDMS文件里是不是有数据写入。最后才启动UI模块用UI上的按钮控制采集的开始和停止。这个顺序能帮你在每一步都只面对一个未知数。如果UI点了Start没反应先检查Request有没有到达采集模块再看采集模块是否处于Normal状态再看是不是设备初始化失败。按照这条链路排查基本一次能定位。验证成功的标准有几个UI波形能实时刷新刷新周期和采集周期一致TDMS文件里的数据条数和UI显示的数据帧数一致停止后三个模块都能执行完Shutdown并干净退出不会出现程序都关了循环还在后台跑的情况。6.4 个人体会与下一步建议把这一套自己动手做一遍之后你对DQMH的感受会完全不一样。我第一次做完这个练习时最大的改变不是学会用了三个API而是彻底改变了写LabVIEW的思维方式。以前拿到一个需求我第一反应是我要写哪些VI、拖哪些控件、怎么连线现在第一反应是这个系统应该拆成哪几个模块、每个模块对外提供哪些Request、广播哪些事件。不要小看这个转变它是从写功能的程序员朝设计系统的工程师转变的关键一步。如果你已经把这个Demo跑通下一步我建议你研究一下模块的嵌套用法也就是在一个模块内部再创建子模块这在做复杂设备驱动时非常有用。另外还可以看看消息超时策略和动态模块创建这些是DQMH进阶绕不开的话题。这篇LabVIEW_DQMH框架学习笔记先到这儿后面我会继续更新更深入的内容争取把实际项目中那些书本上没有的经验都写出来。
返回列表