FX3U搭配ADP-MB实现Modbus RTU通讯:模板程序与现场调试全解析 1. 一台 FX3U 串起整条产线从硬接线困局到 Modbus 模板方案先说我为什么会被这个标题勾住。前两年做一条小型包装线的改造现场有九台智能仪表、三台变频器要接入 PLC。如果按传统做法变频器跑停信号加运行反馈至少 2 个 DI 点频率给定用模拟量又要一个 AO 口每台变频器占 3 个点9 台仪表每台至少 4~8 个模拟量输入算下来 FX3U-64MT 都不够塞。更麻烦的是模拟量信号在长距离传输时变频器一启动传感器信号就跳得没法看。后来全部改成 RS485 总线两根屏蔽双绞线把所有设备串起来PLC 只出两个通讯口把仪表、变频器全部纳入 Modbus RTU 网络改造那叫一个顺。这篇文章要分享的就是一套基于三菱 FX3U 小型 PLC 搭配 ADP-MB 通讯适配器与仪表、变频器做 Modbus 通讯的模板程序。标题里的ADP-MB指的就是 FX3U-485ADP-MB 这种 Modbus 专用适配器也可以换成 RS-232 口的版本程序逻辑一致区别只在物理接线。它能做什么一句话概括让 FX3U 充当 Modbus 主站按顺序轮询总线上的仪表和变频器完成数据采集、参数下发、启停控制和频率给定。适合谁看设备工程师、做非标设备的电气设计、工厂里维护 PLC 的电工师傅以及刚从梯形图入门想接触通讯编程的自学者。看完之后你可以直接把轮询逻辑、报文格式、CRC 处理这些框架抄到自己项目里省掉从零摸通讯的几个月时间。先说明一点这不是给你一个现成的 GX Works2 工程文件而是把程序逻辑和关键指令段拆开讲清楚。因为不同项目的从站数量、寄存器地址、报文内容差异很大真正能复用的是通讯骨架也就是初始化、发送、接收、超时处理、轮询调度这一整套机制。这套骨架我用了好几年换过不同品牌的仪表和变频器只需要改报文内容和轮询地址表程序主体基本不动。2. 硬件选型与接线为什么是 ADP-MB以及 RS485 端三个容易翻车的细节2.1 不带 -MB 的适配器和 -MB 版本是两个物种很多人第一次买模块时容易踩坑三菱 FX3U 有 FX3U-485ADP 和 FX3U-485ADP-MB 两个型号价格差一截功能完全不同。普通 485ADP 是给无协议通讯用的配合 RS 指令收发自由格式数据所有报文、校验、状态判断全都要程序自己拼。而 485ADP-MB 是 Modbus 专用适配器硬件层面已经把 Modbus 协议处理逻辑固化进去PLC 通过 FROM/TO 指令读写适配器内部的缓冲存储器BFM把要发的报文填进缓冲区置一个发送标志适配器就自动按 Modbus RTU 格式把数据发出去接收侧也一样完成后自动把数据放进接收缓冲区并给出状态位。选型建议很直接如果你要接的从站设备都支持 Modbus RTU而且不想自己处理 CRC、帧超时这些底层细节直接买带 -MB 的版本。如果哪天要跟非标自定义协议的第三方设备对接只能走无协议 RS 指令这时候买普通版。两种模块的安装位置都在 FX3U 主机的扩展接口不占用输入输出点数这点倒是一样的。2.2 安装位置和 A/B 端子别认死理ADP-MB 安装在 FX3U 主机的左侧扩展口打开前盖板能看到连接器模块上有方向标记插进去之后旋紧固定螺丝。接线方面RS485 一般是两根线模块端子上通常标着 SDA/SDB或者 A/B国内大部分仪表和变频器用 A/B 或者 D/D- 标识。但这里有个很阴间的细节不同厂商对 A/B 的定义不一定一致。有些仪表把 A 定义为同相端有的厂商把 A 定义为反相端接线前一定要翻说明书上的端子图确认不要想当然认为红色线就是 A。我调试时遇到过一台温控表怎么发都不回复后来发现它的端子标注和大部分设备正好相反把两根线对调之后一次就通了。这种问题用万用表很难测出来最靠谱的办法是先把单个设备单独接电脑串口调试助手验证通信确认 AB 定义后再接入总线。2.3 终端电阻、屏蔽接地和总线段数RS485 总线两端各需要接一个 120Ω 终端电阻。小项目、距离十米以内、设备就两三台不接也能通但设备多了、线长超过 50 米不接终端电阻大概率出现乱码、丢帧。有些仪表内部已经带了偏置电阻无需再外加有些模块侧面有终端电阻跳线或拨码短接就是接入 120Ω。如果设备都不带就买几个成品终端电阻座接在总线最远两端。屏蔽双绞线的接地也值得较真。原则是屏蔽层在 PLC 柜端单点接地现场仪表侧悬空。我见过一个现场屏蔽层两端都接地结果两台设备地电位有差屏蔽层里走了一圈地电流通讯反而被干扰得更严重。把现场端剪掉、用胶带包好问题立刻消失。另外RS485 通讯线务必和变频器动力线分开走线不要穿同一根穿线管、不要贴太近尤其是变频器输出侧 U/V/W 的电缆对通讯的干扰非常致命。2.4 从站侧参数统一清单所有从站接入总线前先把下面这张表逐台核对漏一项都会导致通讯失败参数项推荐值为什么必须统一波特率9600 或 19200主从必须完全一致否则收发错位数据位8Modbus RTU 固定 8 位校验位无校验N或偶校验E全总线只能选一种混用直接废掉停止位1 或 2常见 8N1 或 8E1统一即可从站地址1~247不重复地址 0 是广播地址不能用于单台通讯协议Modbus RTU有些设备支持 RTU/ASCII 两种务必选 RTU一个重要提示变频器改通讯参数后很多型号要重新上电才生效现场调完参数发现没反应先断电重启再测不要急着怀疑接线和程序。3. 模板程序的通信骨架BFM 配置、发送请求与接收完成的动作顺序3.1 先把关键 BFM 映射关系搞清楚ADP-MB 的核心工作方式是把数据放进自身缓冲存储器PLC 用 FROM/TO 指令访问。不同批次包装里的模块BFM 编号可能有改动我下面给的是我目前手头这版的常见映射大家动手前务必打开随模块附带的手册对着 BFM 分配表核对一遍再写程序。我项目里常用的映射关系如下BFM功能我的用法#0通讯格式设置波特率、校验、停止位按位写入#1协议/主从模式填入主站模式取值#2从站号主站模式下一般用不到#5发送请求写入待发送字节数后自动触发发送#10 起发送缓冲区逐字填入报文内容#40接收字节数模块接收完成后更新#41 起接收缓冲区从中读取从站回复帧#61通讯状态标志0空闲1发送中2接收完成3超时4错误#62错误码非 0 表示通讯异常对照手册查原因用 FROM/TO 指令访问时格式是TO [单元号] [BFM起始] [源D起始] [传送点数]、FROM [单元号] [BFM起始] [目标D起始] [传送点数]。ADP 通常作为 0 号单元具体看 GX Works2 系统配置里的单元号排列。3.2 初始化程序段通讯格式与主站模式上电初始化时用一条 TO 指令把通讯格式字写入 BFM#0。格式字的位定义类似 D8120波特率、数据位、校验位、停止位都按位拼。比如 9600、8N1写十六进制 0x0081如果是 8E1、9600写 0x0089。具体取值对照模块手册里的格式字位表不同模块定义会有细微差别。初始化还要把 BFM#1 清成主站模式值。某些固件里主站模式还要指定轮询是否开启如果只想自己手动逐帧控制就把轮询关闭保留最朴素的填报文-触发发送-等状态模式。我一般建议先用手动模式调通每台设备再去研究自动轮询这样排查问题简单得多。3.3 一次完整读请求的五个动作整个模板的通讯动作可以拆成五个步骤这也是主站侧发送任何命令的通用流程把目标从站想读的寄存器地址、功能码、数据长度组装成报文逐字写入 BFM#10 开始的发送缓冲区。把报文总字节数写入 BFM#5模块检测到数值变化后自动把缓冲区内容按 Modbus RTU 格式发出。轮询读取 BFM#61 的通讯状态标志等待接收完成或者超时。状态变成接收完成后先读 BFM#40 拿到实际收到的字节数再用 FROM 指令把 BFM#41 开始的接收缓冲区读入 D 区。在 D 区里解析数据根据功能码 03/04 的回复格式从第 3 个字节开始取寄存器数值即数据区。这个五个动作全程可以不用任何 RS 指令也不用自己管帧间隔和 CRC 校验ADP-MB 硬件已经在底层做掉了大部分工作这是它比无协议方案省心的地方。3.4 超时和错误码也要纳入状态机通讯这东西不是每次发送都能收到回复。从站掉电、线松了、屏蔽层干扰、变频器正在复位都可能导致没回应。主站程序如果死等整个 PLC 扫描周期都会被拖住。ADP-MB 会自己维护超时标志但我们还是要控制一个最大等待时间用一个定时器包裹整个等待状态比如设定 500ms 超时超过就不再看 BFM#61直接把这次通讯标记为失败然后跳转到下一个从站。后文第 5 节会展开讲完整的调度逻辑。4. 报文组包与 CRC 落地仪表读数套路和变频器控制命令的差异4.1 先背熟这张功能码速查表Modbus RTU 的报文结构是从站地址 1 字节、功能码 1 字节、数据区 N 字节、CRC 低字节、CRC 高字节。功能码决定了数据区的含义最常用的五个如下功能码名字常用场景回复特征03读保持寄存器读仪表数据、读变频器参数返回字节数寄存器数据04读输入寄存器读电量、流量等只读数据同上05写单个线圈控制变频器启停点原帧返回06写单个寄存器给定频率、写参数原帧返回160x10写多个寄存器批量写参数返回地址数量我绝大多数情况下只用 03 和 06。仪表数据采集用 03变频器启停和频率给定用 06简单直接。个别参数表比较大的场合才用 16 写多寄存器。4.2 仪表读数报文怎么拼假设有一台流量计从站地址是 01它的累计流量存在保持寄存器地址 0x0000占用两个字也就是 32 位浮点数。我要读它组包内容为01 03 00 00 00 02 CRC_L CRC_H含义向 1 号从站发送功能码 03从 0x0000 地址开始读取 2 个字。回复帧一般是 9 个字节从站地址、功能码、数据字节数 04、四个数据字节、CRC 低、CRC 高。四个数据字节代表一个 32 位浮点数具体字节顺序取决于仪表自己的浮点字节序设定常见的有 ABCD 顺序和 CDAB 顺序两种。实测时只要锁定一根数据曲线如果数值乱跳或者数量级不对把四个字节前后调换一下再试大概率能解决。这块极容易翻车建议在通讯调试阶段先用电脑串口助手把单台仪表的字节序摸清楚再写 PLC 解析程序。4.3 变频器控制命令和仪表的本质区别变频器和仪表最大的区别在于仪表主要是读变频器主要是写而且写的内容直接决定设备动不动作安全性要求高。以常见国产品牌变频器为例运行命令字寄存器通常在 0x2000用功能码 06 写入 1 表示正转启动写 0 表示停止频率给定寄存器通常在 0x2001数值一般要乘以 100比如给定 50.00Hz 就写 5000即 0x1388。报文长这样01 06 20 00 00 01 CRC_L CRC_H // 1号变频器正转启动 01 06 20 01 13 88 CRC_L CRC_H // 1号变频器给 50.00Hz往变频器写命令前有两件事必须提前确认。第一变频器的启动信号源必须设为通讯控制有些变频器有面板启动和通讯启动冲突的问题剩下一个面板 RUN 灯卡着通讯命令发过去没反应。第二频率给定源也要切到通讯同时确认频率上限、加速时间这些参数不会把给定值截掉。见过一个案例程序算出来 4000 对应 40Hz变频器只跑到 30Hz后来发现是上限频率挡着跟通讯一点关系没有。不同品牌的变频器寄存器地址差异很大日系、台系、国产品牌各有各的映射表动手前把对应说明书里的通讯地址表那一章复印一份放桌上对着抄。程序模板能复用的是框架寄存器地址一定以说明书为准。4.4 CRC 落地PC 上算好表PLC 里查表执行先纠正一个常见误解ADP-MB 作为主站发送报文时报文里的 CRC 到底要程序自己填吗至少在我用过的固件版本里缓冲区填的报文不需要包含 CRC模块发送时会自动追加计算好的 CRC。但也有个别版本要求完整帧包含 CRC。最稳妥的办法是先在模块手册里找发送缓冲区是否需要包含 CRC的说明不确定的话直接实测先不填 CRC 发一帧拿串口助手抓总线上的帧看看末尾有没有自动加上两个校验字节有就是硬件帮你算了没有就程序自己补。这个测试排错时非常有用。如果程序需要自己算 CRC强烈建议用查表法而不是梯形图逐位算。Modbus CRC16 的标准算法很统一先在电脑上用任意语言把高位表和低位表生成出来。比如下面这段 Pythondef modbus_crc(data: bytes) - int: crc 0xFFFF for b in data: crc ^ b for _ in range(8): if crc 0x0001: crc (crc 1) ^ 0xA001 else: crc 1 return crc # 生成高低两张查表 hi [0] * 256 lo [0] * 256 for i in range(256): crc modbus_crc(bytes([i])) hi[i] (crc 8) 0xFF lo[i] crc 0xFF print(hi) print(lo)把生成的两个 256 长度列表通过初始化程序一次性写入 D 区停电保持区域。轮询时每发一帧报文用 FOR/NEXT 配合变址寄存器 Z对每一个数据字节依次完成异或-右移-查表三步8 个字节的报文循环 8 次就能得到完整 CRC。最后注意 Modbus 协议要求 CRC 低字节在前、高字节在后如果通信时发现对端总是回错误帧先怀疑是不是 CRC 两个字节顺序放反了。这个坑我踩过两回一次是自己一次是帮同事排障。其实更省事的方法是调试阶段先用电脑串口助手对每台从站单发命令让它把回复的 CRC 和总线抓包对照确认模块是否自动补 CRC。确定下来之后程序里该不该算 CRC、算完怎么放置就有了明确结论不用瞎猜。5. 多从站轮询调度设计超时、掉线隔离和断线重连的完整思路5.1 轮询状态机用步号代替一堆散落的定时器接十几台从站时最忌讳的做法是给每台设备各写一段独立的通讯程序那样程序会冗长到没法维护。正确做法是做一个轮询状态机用一个数据寄存器 D 当作当前步号程序按步号跳到对应分支执行。我常用这样的步号定义步号动作0轮询指针复位从 1 号从站开始1组装读报文并触发发送2等待接收完成或等待超时定时器3超时或错误记录失败次数并递增指针4解析接收数据存入对应该从站的数据区5递增轮询指针返回步 0这样整个通讯程序只有一组收发逻辑所有从站的差别仅仅体现在当前从站号这个指针变量上。配合变址寄存器读取报文里的寄存器地址也可以做成表格实现一劳永逸。5.2 超时重试单次失败不能直接判死从站偶尔无响应是常态变频器上电瞬间、仪表在做内部自检时都可能在几十到几百毫秒内不回复。模板里我设置了同一从站连续失败三次才算真正故障前两次失败只记录不剔除。重试机制是在状态机里加一个计数器每次失败计数器加 1成功后清零连续三次失败就把该从站标记为离线本轮轮询直接跳过它不再白白消耗时间。这样一台仪表挂了剩下十几台设备的数据照常刷新生产线的其他检测功能不受影响。5.3 掉线恢复离线网段也不要永久放弃设备离线之后不能永远跳过否则哪天修好了也一直处于失联状态。恢复机制我放在轮询周期间隙里一轮正常轮询结束后额外插入一个离线设备探测分支把离线的从站按顺序尝试发一次读请求如果收到回复就把它的离线标记清除重新纳入正常轮询。以我接 12 台从站的实际经验每轮正常轮询加一次离线探测总线负载基本没压力而设备故障恢复后 1~2 秒内就能自动重新建立通讯操作工几乎察觉不到变化。5.4 轮询周期估算别让从站等着等着就烦了Modbus RTU 的轮询周期取决于波特率和数据量。9600 波特率下一帧 8 字节的报文发送时间约 10ms加上从站处理和回复时间单次通讯往返实测在 30~60ms 之间。如果 12 台从站每台读 2 个寄存器一轮完整轮询大概 0.6~0.8 秒再加超时重试的余量基本上 1 秒一轮比较健康。19200 波特率速度快一倍但现场距离长、干扰大时容易出错我宁可选 9600 求稳。轮询间隔不宜太短给从站留一点喘息的余地也防止模块缓冲区还在收发时下一帧命令就挤进来。6. 现场调试的踩坑记录与参数调优建议6.1 先把每台从站单独调通再挂总线我最想强调的调试纪律是先单台、后总线先电脑、后 PLC。仪表、变频器到位后我从来不会直接接 PLC 来测通讯而是拿 USB 转 RS485接一个从站用串口调试助手手动发 03 命令确认它能回复、能解析、字节序正常然后换下一台。全部单台都通再按站号从小到大挂到总线上接上 ADP-MB。这样做的好处是出了问题你永远知道是总线冲突还是单台设备参数不对不会在一堆设备里大海捞针。如果现场没有仪表实物还可以用电脑上的 Modbus 从站模拟软件当测试目标把 PLC 接 USB 转 485 后直接对模拟从站发请求效果基本一样。这个办法非常适合在项目交付前把 PLC 程序提前验证好。6.2 BFM 监视和总线抓帧并行排查程序写好但通讯不通时GX Works2 的软元件批量监视非常好用把发送缓冲区、接收字节数、通讯状态标志、错误码四个区域放在同一个监视窗口运行程序后肉眼观察它们在通讯瞬间的跳变。如果发送缓冲区有数据、状态标志却一直停在 1 或 3说明数据发出去了但没人回复问题在从站侧如果发送缓冲区压根没被填对比如地址字节顺序错了问题在组包逻辑。配合示波器或 USB 串口监视器在总线上抓帧能直接看到主站发出的报文内容和程序里填的缓冲区对照几分钟就能定位大部分通讯问题。6.3 典型故障对照表把我在不同项目里反复踩过的通讯故障整理成一张表调试时可以直接照着查现象最常见原因处理办法所有从站都不回复AB 接反或通讯线断路单台设备接交流调线确认个别从站偶发失败站号重复逐个检查从站地址设置波特率/校验混用从站参数没统一按 2.4 节表格逐台核对变频器一启动通讯就乱通讯线贴近动力线走线分开屏蔽层单端接地仪表数值明显不对浮点字节序反了调换数据字节顺序验证通讯状态一直停在超时从站没切换为通讯控制变频器面板/参数控制源切换另外有个小细节有些仪表和变频器在通讯参数修改后不重新上电就不启用新设置我在现场调试时被这个坑过很多次。改完参数先断电再上电很多时候问题自己就消失了。6.4 几个个人很受用的参数习惯最后分享三个我从多次项目中沉淀下来的设置习惯。第一单从站超时时间 300~500ms轮询间隔 100~200ms失败连续三次剔除这套参数在大多数 9600 波特率现场都稳定。第二把每个从站的最近一次通讯成功时间记录到断电保持区上位机或触摸屏可以实时显示哪个从站掉过线维护人员不用翻程序就知道哪台设备闹过脾气。第三程序里给每台设备的数据单独分配一段连续 D 区比如 1 号从站数据放 D100~D1092 号放 D110~D119以后触摸屏组态、数据上抛都方便不会改一处牵动全局。这套模板程序从第一版到现在帮我完成了好几条产线的设备接入。每次新项目要接更多仪表或变频器时我基本只改从站地址表和寄存器地址表通讯骨架不动。如果你也是第一次用 ADP-MB按文中的顺序先做单台测试、再上总线遇到问题优先对照 6.3 的表格能省下大量现场排查时间。调试时如果发现报文最后一个字节怎么都对不上先检查 CRC 的高低字节顺序再查模块是否自动补 CRC——这两个方向覆盖了九成以上报文看着对但设备不认的情况。