做自动化上位机这么多年,三菱FX系列PLC是我在项目里打交道最多的控制器之一。FX3G、FX3U、FX5U这些小型PLC在产线上到处都是,而LabVIEW因为开发效率高、界面友好,非标设备的上位机里用的人特别多。两拨东西撞在一起,就产生了一个高频需求:用LabVIEW跟FX系列PLC通讯,而且不仅仅是单点读写,还要能做到批量读取软元件(M继电器、D寄存器、X/Y输入输出这些)。这个需求看起来简单,实操起来却有不少门道。
这篇文章把我个人的参考做法完整写一遍。前半部分讲方案怎么选、MX Component怎么安装和配置;中间部分是示范参考程序的具体架构和关键调用代码;后半部分聚焦批量读取软元件的实现细节,以及我在现场踩过的坑。看完你至少能照着一个Demo跑通LabVIEW→MX→FX3U的链路。
1. 整体思路与通讯方案选型
1.1 三种常见通讯路线的对比
很多刚接触LabVIEW和PLC通讯的朋友,第一反应是直接用LabVIEW的串口控件去怼PLC的编程口,觉得“PLC就是个串口设备,我发指令读数据就行了”。这么想不算错,但实操起来非常累,因为你得自己拼MC协议帧、算CRC校验、处理返回报文。三菱FX的MC协议虽然不复杂,但地址解析、批量读写的帧格式、超时重试这些全要自己写,一个项目下来光通讯调试就得耗掉好几天。
更省力的路线基本有三条:
| 方案 | 开发难度 | 稳定性 | 适用场景 |
|---|---|---|---|
| LabVIEW串口直接发MC协议 | 高 | 中等 | 不想装任何三方组件,纯裸通讯 |
| 使用OPC Server(如KepwareEX) | 低 | 高 | 跨多个PLC、同时给SCADA系统供数 |
| 使用三菱MX Component组件 | 低 | 高 | 专做三菱PLC项目、需要批量读写软元件 |
我最早用过裸串口方案,写一个精简的MC协议读取函数不算难,但后续维护很头疼。比如FX3U固件版本差异、站号变化、批量读取上限这些细节,协议文档不全的时候非常折磨。后来改用OPC Server,丢包重连倒是省心,但OPC在LabVIEW里的地址配置繁琐,而且轮询效率受OPC内部线程调度影响,快速采集场景下不稳。
真正让我觉得省事的是三菱官方出的MX Component(MELSOFT MX Component)。它把MC协议封装成ActiveX控件和DLL,LabVIEW直接调用即可,读写软元件就像操作数组一样简单。
1.2 为什么最终选择MX Component
MX Component解决了我最在意的几个问题:其一,它内部已经实现了三菱各种协议栈,包括串口的4C帧、以太网的3E帧/4E帧,不需要我自己拼帧;其二,它支持批量读取,也就是题目里说的“批量读取软单元”,这正好满足生产线上需要同时刷屏几十上百个M点和D点的场景;其三,通讯状态、超时、重连这些逻辑,组件内部有现成机制,比自研框架可靠。
另外,三菱GX Works2/3用户对MX的安装包并不陌生,它经常藏在安装盘的工具文件夹里,装起来也不复杂。跟OPC相比,它的一个明显优势是:LabVIEW通过ActiveX调用,返回的数据直接是数组和数值,数据流非常清晰,不需要经过OPC的Item映射。
当然,MX Component也不是没缺点。它毕竟是ActiveX/COM组件,在64位LabVIEW下有兼容性风险,这一点我后面会专门讲。另外它只能连三菱PLC,如果项目里同时有西门子或欧姆龙,你还得另想办法。但从“LabVIEW与三菱FX通讯”这个单一目标来看,MX Component是目前效率最高、最省心的选择。
2. 环境准备:LabVIEW、MX的安装与通讯配置
2.1 版本选择与安装避坑
先说版本。LabVIEW这边,我建议用32位的LabVIEW版本,例如LabVIEW 2018/2020/2021的32位版本。这不是因为我迷信老版本,而是MX Component的ActiveX组件多数是32位COM组件,在64位LabVIEW的ActiveX引用面板里经常找不到对象,即使找到了也会在运行时崩溃。所以踩过一次坑后,我的原则很简单:MX通讯项目一律用32位LabVIEW。
MX Component的版本我常用的是MX Component 4.x。它安装包一般几百MB,安装过程很简单,但有几个细节必须注意:
- 安装前先关掉杀毒软件,避免注册表写入被拦,导致ActiveX控件无法注册。
- 安装时使用管理员权限。右键安装包,选择“以管理员身份运行”。这个组件需要写注册表和系统环境变量,权限不够会出现“安装完成但没有可用控件”的诡异问题。
- 安装完成后,到“开始菜单 → MELSOFT → 通讯设置工具”里确认组件已经可用。不同版本名称略有不同,有的是Communication Setting Utility,有的是MX Component Setup。
安装完成后,MX一般会自动注册好ActiveX对象。打开LabVIEW,在程序框图中放置“容器”或直接使用“Automation Open”函数,如果能在类名列表里找到类似“MxComponent”或“MX Component ActiveX”的条目,就说明注册成功了。
2.2 新建逻辑站点与参数匹配
MX Component的使用有一个核心概念:逻辑站点号(LogicalStationNumber)。它不是PLC的地址,而是本地通讯配置的一个编号。你需要先在通讯设置工具里新建一个逻辑站点,配置好PLC型号、通讯接口(串口或以太网)、协议类型和站号,然后在LabVIEW里调用Open方法,传入这个逻辑站点号即可。
我以最常见的FX3U加串口通讯为例,说说配置步骤:
- 打开“通讯设置工具”,新建一个逻辑站点,起个好认的名字,比如FX3U_Serial。
- CPU类型选择FX3U/FX3G系列具体型号,或者选“近似型号”让组件自动匹配。
- 通讯接口选择串口(RS-232/RS-422/RS-485),填上实际COM口号。
- 协议类型一般选“MC协议(4C帧)”。波特率、数据位、停止位、校验位这些必须和PLC里设置的完全一致,三菱FX编程口默认常见的是9600、8数据位、偶校验、1停止位,具体以你的PLC参数页面为准。
- 站号默认0,注意PLC侧如果设置了别的站号,这里要对应改。
如果是FX5U或者装了以太网模块的FX3U,通讯接口就选以太网,填PLC的IP地址,端口号要跟PLC侧配置保持一致,常见的是5000系列端口。以太网方式的优势是速度快、抗干扰强,而且不用考虑串口被别的软件占用的问题。
配置完成后可以先在工具里点“通讯测试”,如果工具能读到PLC信息,说明底层链路已经通,下一步就是回LabVIEW写程序了。
3. 示范参考程序骨架:从连接、读写到关闭
3.1 程序整体结构与前面板规划
所谓的“示范参考程序”,关键不在代码有多花哨,而在于结构要完整、可复用。我通常把这类程序分成三层:
第一层是连接管理层,负责Open连接、检测连接状态、Close断开;第二层是读写操作层,封装单点读写、批量读取软元件、批量写入等方法;第三层是界面层,用事件结构或者生产者消费者结构把按钮、输入框、表格、指示灯串起来。
前面板的规划我建议做成这样几个区域:
- 连接参数区:逻辑站点号输入框、连接按钮、断开按钮、连接状态指示灯。
- 单点操作区:软元件地址输入框(如D0、M10),读取按钮,写入按钮,写入值输入框,读回值显示框。
- 批量操作区:起始地址输入框、读取点数输入框、批量读取按钮、数据表格或数组显示控件。
- 运行状态区:最后一次错误码、错误信息字符串、轮询周期或运行计数。
这样的布局既适合演示,也能直接改造成正式项目的底子。实际项目里可以把单点操作区去掉,只保留批量轮询。
3.2 核心代码:建立连接与基础读写
在LabVIEW里调用MX Component,最常用的方式是用Automation Open函数创建ActiveX对象,然后用Invoke Node调用它的方法。下面我把关键调用序列列出来。
先说建立连接:
- 放置Automation Open函数,在类名下拉框里选择MX Component对应的ActiveX类名。如果找不到,检查MX是否安装成功,或直接在函数板上选择“ActiveX → Automation Open”,输入ProgID。
- 调用Invoke Node,方法选择Open,输入参数是逻辑站点号(整数)。
- Open的返回值是错误码,通常0表示成功。所以第一次调用后立刻判断返回值,非0就需要弹出错误信息并停止。
- 连接成功后,可以再调用GetConnectState方法确认状态,返回True表示已连接。
然后是单点读取。用Invoke Node调用ReadDevice方法,输入参数是地址字符串(如"D0"),返回值为Variant类型。在LabVIEW中,把返回值接到“Variant to Data”转换函数上,转成U16或I16数值即可。如果是读M点这种位元件,转换类型选Boolean。
单点写入对应WriteDevice方法,参数是地址字符串和写入值。写D寄存器传整数,写M继电器传True/False。
这里我要多说一句:很多人第一次调用ActiveX方法时,被Variant类型搞得很烦。其实只要记住,MX返回的都是Variant,LabVIEW里用“变体至数据转换”函数,右键设置数据类型为期望类型即可。如果类型选错,读取会报错或者数据变成奇怪的数值。
关闭连接更简单:调用Close方法,然后对Automation引用调用Close Reference释放引用。这个顺序别反了,先Close再释放,否则会报ActiveX引用无效。
为了复现方便,我把核心流程整理成一个简单的调用顺序列表:
- Automation Open创建MX对象。
- Open(逻辑站点号)建立通讯连接。
- 检查返回值,非0则输出错误并中止。
- GetConnectState确认连接状态。
- 循环体里调用ReadDevice/ReadDeviceBlock/WriteDevice等方法。
- 程序退出前Close断开连接。
- Close Reference释放ActiveX引用。
3.3 批量写入与随机读取的补充实现
除了批量读取,MX还提供批量写入和随机读取,这两块在实践里也经常用到。
批量写入对应WriteDeviceBlock方法,参数是起始地址、写入数据数组。比如要给D100~D109这10个寄存器同时写入一组温度设定值,直接构造数值数组,一次调用就完成。注意数组类型和数量要和起始地址后的连续地址数量一致,否则返回错误。
随机读取对应ReadDeviceRandom方法,这名字容易让人误解,它并不是“随机数”那种随机,而是指一次性读取多个不相邻的地址区域。例如我想同时读D0、D100、D200三个寄存器,又不想调用三次ReadDevice,就可以把三个地址放进字符串数组,把每个地址读取的点数放进另一个数组,一次调用返回三个值。这个功能在做设备状态聚合采集时很好用,能显著减少握手次数。
不过要注意,ReadDeviceRandom的返回结果顺序和传入地址顺序一致,但封装在其专门的Variant数组中,你需要在LabVIEW里拆分成对应元素再映射到面板控件。用的时候建议先写个小Demo,自己验证一次返回顺序,免得对错位。
4. 批量读取软元件的进阶实现
4.1 软元件地址规则与数据类型
要说批量读取,首先得把三菱软元件的地址规则理清楚。FX系列常用软元件主要有这几类:
- 位元件:X(输入继电器)、Y(输出继电器)、M(内部继电器)、S(状态继电器)、T/C的触点。
- 字元件:D(数据寄存器)、R(文件寄存器)、Z/V(变址寄存器)、T/C的当前值。
- 特殊辅助继电器和特殊寄存器:M8xxx系列、D8xxx系列,常用于读取PLC状态和诊断信息。
地址编号上有个非常容易踩的坑:X和Y是八进制编号,也就是说X0~X7之后不是X8,而是X10。如果你平时用十进制习惯,写X8去读,返回的要么是错误,要么读到的是X10那个点。M和D都是十进制编号,没有这个问题,但跟PLC实物端子对映时仍然要仔细核对。
从数据类型角度看,D寄存器默认按16位整数处理,LabVIEW侧对应I16或U16。M继电器是位,批量读取时返回布尔数组。T和C的当前值要看PLC里的计时/计数格式,一般按32位或16位处理,具体取决于设置,我在实际工程中都是用U32读取,再根据PLC参数换算。
4.2 批量读取的函数用法与程序设计
批量读取的核心函数是ReadDeviceBlock,它可以一次性读取连续地址的软元件。比如要读取D0~D49这50个寄存器,调用方式如下:
- 方法名:ReadDeviceBlock
- 输入参数一:起始地址字符串,例如"D0"
- 输入参数二:读取点数值,例如50
- 返回值:包含50个数据的Variant数组
在LabVIEW里,把返回的Variant数组接到“Variant to Data”转换,数据类型设置为数组(元素类型I16),就能直接得到完整的数值数组。把这组数据接到波形图表上,就能做实时趋势显示;接到表格控件里,就能做数据巡检。
批量读取位元件同理,ReadDeviceBlock("M0", 32)返回32个布尔值数组。这里要注意,部分MX版本对位元件批量返回的是字节封装数组(比如1字节代表8个位的状态),而不是直接的布尔数组。碰到这种情况,需要自己写一个位解析循环,把每个字节按位拆开。
我自己的习惯是封装一个“批量读取D寄存器”子VI和一个“批量读取M继电器”子VI,子VI内部处理Variant转换和类型解析,外部只暴露起始地址、点数、返回数组和错误码四个接线端。这样主程序里调用起来非常干净,也方便其他同事复用。
4.3 性能优化:轮询周期、缓存与架构
批量读取优势的背后,其实是一个性能问题。我见过不少设备,上位机用100ms轮询一次,每次单点读数十个D寄存器,结果CPU占用高,偶尔还出现超时。换成批量读取后,同样100ms轮询,一次ReadDeviceBlock就完成,CPU占用断崖式下降。原因很简单,批量读取把几十次串行请求合并成了一两次,握手次数少了,通讯链路上的时间开销自然就小了。
但性能优化不只是把单点改成批量。根据我的调优经验,还有几个点值得注意:
- 轮询周期不要设太短。串口9600波特率下,单次报文交互需要几十毫秒,如果轮询周期小于报文交互时间,底层会积压请求,表现为通讯卡顿、超时。比较保险的做法是:先用通讯测试工具摸清单次批量读取耗时,再给轮询周期留出1.5到2倍余量。
- 使用缓存机制。如果PLC侧数据变化不快,可以在上位机维护一个“软元件镜像缓存”,轮询周期可以适当拉长,比如200ms,界面显示并不迟钝,但通讯负载大幅下降。
- 批量读取的数据量要合理。ReadDeviceBlock虽然支持大量连续读取,但一次读取几千个点会让报文过长,反而不稳定。我一般控制在512点以内,超过就分块读取。
- 如果项目需要高频率采集(比如10ms周期),强烈建议不要用LabVIEW界面线程来做通讯。改用生产者消费者架构,采集循环只管用MX读取数据并放入队列,界面循环从队列中取数据更新显示。这样通讯频率和界面刷新解耦,系统才稳定。
5. 常见问题与排查实录
5.1 连接连不上?先查这些
遇到“连接失败”是最常见的情况,我的排查顺序是固定的:先确认硬件链路,再查通讯参数,最后查软件配置。
硬件层面,如果是串口通讯,先确认串口线是不是三菱专用编程线,有些便宜的USB转串口线只是TTL电平,直接接PLC的编程口是收不到数据的。其次是COM口号,打开设备管理器,确认USB转串口模块的COM号跟通讯设置工具里选的一致。
参数层面,最容易出问题的是波特率、校验位和站号。尤其是站号,FX系列默认站号是0,但如果PLC里设置了非0站号,上位机这边必须匹配。还有一个容易被忽略的地方:部分通讯板卡(如FX3U-485-BD)上的拨码开关决定了通讯参数,拨码跟软件参数不一致,也会一直连接失败。
软件配置层面,我遇到过两次比较典型的:一是通讯设置工具里PLC型号选错了,比如FX3U选成了FX3G,导致连接后读写地址偏移;二是逻辑站点号在LabVIEW里写错了,Open时传了配置时没定义的站点号,自然连不上。
5.2 程序里读不到数据怎么办
如果连接成功了,但ReadDevice返回数据异常或超时,我总结下来主要有这些原因:
- 地址写错了。最常见的是X/Y的八进制问题,或者是地址字符串格式少写了字母,比如M0写成了0。三菱MC协议需要完整的元件类型前缀。
- 读取的数据类型不匹配。D寄存器按布尔去转,或反过来,都会得到乱码或报错。记住,读D用数值转换,读M用布尔转换。
- 批量读取点数太多或太少。ReadDeviceBlock如果点数设得过多,超过了PLC软元件的实际范围,会返回错误码;如果设为0或负数,也会直接非法参数错误。
- 连续区域里混入了不可读的特殊地址。某些系统寄存器或保留区域不能通过普通读写访问,此时可以缩小读取范围,绕开保留区。
在LabVIEW里,我习惯把每次Invoke Node调用的错误码拉出来,先转成字符串再显示在一个全局错误指示框里。这样读不到数据时,第一眼就知道是错误码还是空数组,省得盲目猜。
5.3 部署与兼容性:32位/64位、运行时组件
这一节是我特别想提醒的,因为现场出问题往往就在这儿。
第一,32位和64位的坑。LabVIEW 64位无法加载32位ActiveX组件,这是个硬性限制。如果项目是用64位LabVIEW开发的,MX Component这块大概率跑不起来。我建议要么统一用32位LabVIEW开发,要么把MX调用封装成一个独立的32位exe,通过共享变量或TCP与64位主程序通信。后者复杂度高,所以我个人不推荐。
第二,运行时组件。开发和测试环境没问题,但把exe部署到工控机上时,经常出现“找不到ActiveX类”或“Automation对象创建失败”的报错。这是因为目标机器上没装MX Component或其运行时。解决办法是,部署工控机上也要用管理员权限安装一遍MX Component,并且把通讯设置工具里的逻辑站点配置一起带过去。
第三,GX Works软件占用问题。如果工控机上同时开着GX Works2/3监控PLC,再把上位机程序连上去,会遇到串口被占用或通讯冲突。编程口和以太网都可能这样,这是因为MX和GX的通讯底层都争抢同一协议通道。我的习惯是:调试阶段用GX,运行阶段关掉GX;如果必须同时在线,就把GX改成以太网连接,上位机用串口,两边物理隔离。
还有一个我在现场踩过的小坑:部分精简系统缺少VC++运行库,MX组件安装时虽然没报错,但运行时动态库加载失败。装上对应VC++ Redistributable即可解决。
6. 写在最后的一些经验
做LabVIEW与三菱FX系列PLC的通讯,说难不难,说简单也不简单。关键是不要把时间浪费在重复造轮子上。MX Component这个组件我用了四五年,它虽然只是三菱官方提供的一个通讯封装,但在项目稳定性和开发效率上的确帮了大忙。
最后分享两个我实际总结的小技巧。第一个,批量读取D寄存器时,不要在每次轮询里都调用“Variant to Data”转换,这会带来额外开销。正确做法是连接建立后,在初始化阶段把转换函数准备好,轮询阶段只做数据搬运。第二个,如果现场通讯总是偶发超时,优先检查电源地线和通讯线屏蔽层,不要一上来就怀疑软件。工业现场的大部分“通讯抖动”,根子都在电磁干扰和接地不良上。
这套示范参考程序跑通以后,再往里面加配方下发、历史数据记录、报警推送都是水到渠成的事。希望这篇文章能让你少走几步弯路,顺利拿下LabVIEW与FX的通讯这个基础能力。