news 2026/10/21 19:14:43

FX3U搭配ADP-MB实现Modbus RTU通讯:模板程序与现场调试全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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 一次完整读请求的五个动作

整个模板的通讯动作可以拆成五个步骤,这也是主站侧发送任何命令的通用流程:

  1. 把目标从站想读的寄存器地址、功能码、数据长度组装成报文,逐字写入 BFM#10 开始的发送缓冲区。
  2. 把报文总字节数写入 BFM#5,模块检测到数值变化后自动把缓冲区内容按 Modbus RTU 格式发出。
  3. 轮询读取 BFM#61 的通讯状态标志,等待接收完成或者超时。
  4. 状态变成"接收完成"后,先读 BFM#40 拿到实际收到的字节数,再用 FROM 指令把 BFM#41 开始的接收缓冲区读入 D 区。
  5. 在 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写单个寄存器给定频率、写参数原帧返回
16(0x10)写多个寄存器批量写参数返回地址+数量

我绝大多数情况下只用 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 的标准算法很统一,先在电脑上用任意语言把高位表和低位表生成出来。比如下面这段 Python:

def 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~D109,2 号放 D110~D119,以后触摸屏组态、数据上抛都方便,不会改一处牵动全局。

这套模板程序从第一版到现在,帮我完成了好几条产线的设备接入。每次新项目要接更多仪表或变频器时,我基本只改从站地址表和寄存器地址表,通讯骨架不动。如果你也是第一次用 ADP-MB,按文中的顺序先做单台测试、再上总线,遇到问题优先对照 6.3 的表格,能省下大量现场排查时间。调试时如果发现报文最后一个字节怎么都对不上,先检查 CRC 的高低字节顺序,再查模块是否自动补 CRC——这两个方向覆盖了九成以上"报文看着对但设备不认"的情况。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 19:14:07

CAMX ChiFeature2结构体拓扑图:内存布局级依赖关系解析

简介:本资源是一份面向Android底层相机开发者的高通CAMX架构ChiFeature2框架深度解析资料,聚焦多相机系统下的实时图像处理、特征提取与资源管理设计,适用于具备嵌入式或图像处理经验的移动平台开发者,解决ChiFeature2系统集成、定…

作者头像 李华
网站建设 2026/10/21 19:14:06

软考高项第十八章下:四大绩效域实战解读与案例应用

你是不是也有这种感觉:教材里八个绩效域,学完上篇以为就是背五个词——干系人、团队、开发方法和生命周期、规划。可真拿到案例题,依然不知道项目经理该干什么。我备考信息系统项目管理师时也卡在这章。后来把第十八章(下&#xf…

作者头像 李华
网站建设 2026/10/21 19:11:35

2026年Agent岗位面试全攻略:考点拆解、系统设计与避坑指南

2026年,Agent相关的岗位需求肉眼可见地爆发了。年初我和几个在大厂做技术面试官的朋友聊天,大家共同的感受是:简历里写“会用LangChain调API”的候选人已经很难进入下一轮了,面试重点正在从“会不会用框架”快速转向“能不能理解A…

作者头像 李华
网站建设 2026/10/21 19:11:30

发电机中性点接地电阻柜选型设计与运行维护指南

1. 为什么发电机中性点必须经电阻接地 1.1 接地方式选择的底层逻辑 先说一个很多刚入行的朋友容易忽略的事实:发电机中性点不是想接地就接地,也不是越“实在”越好。中压发电机的定子绕组在运行中一旦发生单相接地,故障点会流过电容性电流和…

作者头像 李华
网站建设 2026/10/21 19:11:30

从零实现浏览器图表设计器:核心架构与交互实战

最近在做的内部项目代号叫 diagram-design,一个跑在浏览器里的图表设计器。简单说,就是让用户能在一张画布上拖拽节点、连线、框选、缩放、撤销重做,最后导出成一份结构化数据。这个项目从需求确定到核心逻辑跑通,前后迭代了好几版…

作者头像 李华