(十九)#三菱FX3U PLC Modbus通讯功能介绍
GitHub 项目地址:https://github.com/lidecong133/YModbus
FX3U 在老设备、改造项目、小型自动化设备里很常见。
很多现场问法是这样的:
“我这台三菱 FX3U,能不能用 YModbus 直接读?”
答案还是那句老话:先看它是不是真的在跑 Modbus。
FX3U 本体不是插上编程线就自动变成 Modbus 设备。它要做 Modbus 通讯,通常要配FX3U-485ADP-MB或FX3U-232ADP-MB这类 Modbus 通信适配器,然后在 GX Works2 或 GX Developer 里用程序设置通信参数。
如果现场只是有一块普通的 485 板,或者只是能用 GX Works2 在线监控 PLC,那还不能说明 Modbus 已经能通。
三菱这边还有一个常见误区:MC 协议、编程口通讯、无协议通讯、Modbus RTU,不是一回事。YModbus 只管 Modbus。对面如果开的是 MC 协议,就要用 MC 协议库;对面如果真正开了 Modbus RTU,YModbus 才能按 Modbus 去读写。
下面按 FX3U 最常见的 RTU 现场,把这件事讲清楚。
先确认硬件是不是对的
FX3U 做 Modbus,先看通信硬件。
现场常见会看到这些名字:
FX3U-485ADP-MBFX3U-232ADP-MBFX3U-485-BDFX3U-232-BD- 第三方 485 模块
- 第三方以太网转 Modbus 网关
这里最需要注意的是后缀里的MB。
FX3U-485ADP-MB和FX3U-232ADP-MB是面向 Modbus 串行通信的适配器。三菱官方 Modbus 串行通信手册讲的就是这类 ADP-MB 适配器。
普通485-BD或普通串口板,可能能做无协议通信、计算机链接、N:N 网络等,但不代表它自己就提供三菱官方 Modbus 指令环境。有人也可以用无协议方式手写 Modbus 帧,但那已经是另一种玩法了:CRC、超时、帧间隔、功能码都要自己处理,现场维护成本会高很多。
所以第一次确认时,不要只问“有没有 485”。
更准确的问法是:
这台 FX3U 用的是不是FX3U-485ADP-MB或FX3U-232ADP-MB?PLC 程序里有没有按 Modbus 串行通信方式配置 D8400、D8401 这些参数?
FX3U通常走Modbus RTU
FX3U 的 Modbus 场景,最常见是串口 Modbus RTU。
它可以做两种角色:
第一种,FX3U 做 Modbus 主站。
比如 PLC 主动读取变频器、温控表、电表、称重仪表。
这时 FX3U 会用ADPRW指令发起读写请求。
第二种,FX3U 做 Modbus 从站。
比如上位机、触摸屏、采集网关、YModbus 来读取 PLC 里的D、M、X、Y等设备数据。
这时 FX3U 被动响应主站请求。
这两个方向一定要先分清。
如果 FX3U 是主站,YModbus 不能也作为主站去抢同一条 RS485 总线。
如果你希望 YModbus 读取 FX3U,那 FX3U 侧就要配置成 Modbus 从站。
FX3U做Modbus主站
FX3U 做主站时,核心是ADPRW。
它的作用可以简单理解为:
让 PLC 按指定的从站号、功能码、Modbus 地址和数据区,主动发一条 Modbus 请求。
比如 FX3U 读取一台变频器的状态字:
从站号:1 功能码:03 起始地址:0 数量:2 结果保存到:D100 开始或者 FX3U 写一台温控表的设定温度:
从站号:2 功能码:06 写入地址:10 写入值:350实际梯形图里会比这复杂,因为还要处理触发、完成、错误、忙状态和轮询顺序。
现场最忌讳的是多个ADPRW一起常开触发。
三菱手册里也提到,FX Modbus 主站同时驱动多个ADPRW时,一次只会执行一条,当前命令完成后才执行下一条。现场写程序时不要把这个机制当成“随便并发也没事”。更稳的做法是自己写一个步骤链:
步骤 0:读变频器状态字 步骤 1:读实际频率 步骤 2:写运行命令 步骤 3:写频率设定 步骤 4:读报警码 完成后回到步骤 0每一步只触发一次ADPRW,等完成标志或错误标志出现后再进入下一步。
这样调试的时候也清楚:到底是读状态字失败,还是写频率失败。
如果 PLC 程序里一堆ADPRW都靠一个常开位使能,现场看到的通常就是“偶尔通、偶尔超时、错误码跳来跳去”。
FX3U做Modbus从站
如果 YModbus 要读 FX3U,最舒服的方式是让 FX3U 做 Modbus 从站。
从站侧要配置这些内容:
- 通信格式,比如波特率、数据位、停止位、校验
- 协议模式,比如 RTU 还是 ASCII
- 站号,范围通常是
1到247 - 是否做主站还是从站
- 通信状态保存区域
- 默认设备映射或用户自定义映射
三菱 FX3U 的 Modbus 参数不是在一个漂亮的“服务器设置页面”里点几下就完事,很多内容是通过特殊寄存器和特殊继电器在程序里设置的。
常见会看到这些设备:
| 设备 | 作用 |
|---|---|
M8411 | Modbus 串行通信参数设置请求 |
D8400 | 通信格式 |
D8401 | 协议和主从模式 |
D8414 | 从站站号 |
D8415 | 通信状态信息设置 |
D8416 | 通信状态设备范围设置 |
D8402 | Modbus 通信错误代码 |
D8403 | 错误详细信息 |
不要随手乱动M8411。
它是 Modbus 参数设置用的特殊辅助继电器。三菱手册对它的用法要求比较严格,参数设置段里不要乱插条件、线圈和其它逻辑。这个地方一乱,Modbus 参数可能根本没有生效。
我的建议是让 PLC 程序员单独做一段清晰的 Modbus 初始化程序,不要夹在业务逻辑中间。
默认地址映射怎么理解
FX3U 做从站时,默认会把 PLC 设备映射到 Modbus 地址空间。
常用的几个映射可以这样理解:
| Modbus区域 | 典型FX3U设备 |
|---|---|
| Coils | M、S、Y等位设备 |
| Discrete Inputs | M、S、X等只读位设备 |
| Holding Registers | D、R、定时器/计数器当前值等字设备 |
| Input Registers | D、R、定时器/计数器当前值等只读字设备 |
对上位机最实用的一条是:
FX3U 默认映射里,Holding Register 地址0x0000起,对应D0起。
也就是说,YModbus 读取保持寄存器地址0,通常就是读D0。
读地址10,通常就是读D10。
CLI 可以这样试:
ymodbusread-holding-registers--transport rtu--serial-port COM3--baud-rate 9600--data-bits 8--parity even--stop-bitsone--slave-id 1--address 0--quantity 10如果 PLC 里提前写入:
D0 = 1234 D1 = 5678 D2 = 100那 YModbus 从地址0开始读 3 个寄存器,应该能看到这几个值。
但这里有两个坑。
第一个坑,项目可能启用了用户自定义映射。
FX3U / FX3UC 支持把最多 8 段 PLC 设备范围按用户定义映射到 Modbus 地址区。一旦启用了自定义映射,默认地址关系就会失效。
所以现场不要死背“地址 0 一定是 D0”。
更准确的说法是:
在默认映射下,地址0对应D0;如果项目配置了 D8470 到 D8485 这些自定义映射寄存器,就要按项目里的映射表来。
第二个坑,很多资料会写40001。
Modbus 显示地址40001通常对应协议地址0。YModbus 里传的是协议地址,所以读40001时不要写40001,应该从0开始试。
YModbus读取FX3U从站
假设 FX3U 作为 RTU 从站,参数如下:
串口:COM3 波特率:9600 数据位:8 校验:Even 停止位:1 站号:1YModbus 代码可以这样写:
usingSystem.IO.Ports;usingYModbus.Clients;usingYModbus.Serial;usingSerialPortport=new("COM3"){BaudRate=9600,DataBits=8,Parity=Parity.Even,StopBits=StopBits.One,ReadTimeout=3000,WriteTimeout=3000};port.Open();awaitusingModbusClientclient=ModbusSerialClientFactory.CreateRtu(slaveId:1,serialPort:port,leaveOpen:true);ushort[]values=awaitclient.ReadHoldingRegistersAsync(startAddress:0,quantity:10);Console.WriteLine(values[0]);第一次不要读太多。
先让 PLC 程序员在D0、D1、D2里放固定值。上位机先读地址0,数量3。
如果这一步能通,再读M点、X点、Y点、浮点数、报警字。
如果一开始就读 100 个寄存器,或者直接读浮点数,出了问题你很难判断是链路问题、地址问题,还是字节序问题。
FX3U的线圈和输入怎么读
如果要读M或Y这种位设备,可以用 coils。
例如默认映射下,M0起始在 Coils 地址0x0000。
YModbus 可以这样读:
bool[]coils=awaitclient.ReadCoilsAsync(startAddress:0,quantity:16);CLI 也可以:
ymodbusread-coils--transport rtu--serial-port COM3--baud-rate 9600--data-bits 8--parity even--stop-bitsone--slave-id 1--address 0--quantity 16如果想读X输入,通常要看 Discrete Inputs 区域。
但X、Y在三菱里是八进制编号习惯,比如X0到X7,再到X10。上位机这边是连续的 Modbus 地址。现场沟通时要把这个编号习惯说清楚,不要把三菱显示的X10直接当成十进制地址 10。
写入FX3U要加保护
读数据还好,写 PLC 就要谨慎。
YModbus 可以写 Holding Register,也可以写 Coil。但写入前要确认这些问题:
- 写的地址是不是允许外部写
- 写入值会不会被 PLC 扫描程序下一周期覆盖
- 写入位是不是会直接控制输出
- 是否需要握手机制
- 是否需要上升沿触发
- 是否需要范围限制
- PLC 侧有没有做互锁
我不建议上位机直接写Y输出。
更稳的方式是写M或D作为命令区,让 PLC 程序自己判断条件后再控制输出。
比如:
D100:上位机命令号 D101:参数 1 D102:参数 2 M100:上位机命令触发 M101:PLC 已接收 M102:PLC 执行完成 D110:执行结果码这样比直接写某个线圈安全得多。
YModbus 写寄存器示例:
awaitclient.WriteSingleRegisterAsync(address:100,value:1);如果address: 100在默认映射下对应D100,这就可以作为一个命令号。
写入前最好先用 CLI 做一次非常小的测试:
ymodbuswrite-single-register--transport rtu--serial-port COM3--baud-rate 9600--data-bits 8--parity even--stop-bitsone--slave-id 1--address 100--value 1测试时让设备处于安全状态,不要在机器运行、气缸动作、伺服使能的时候随便写。
FX3U做主站时YModbus怎么配合
如果 FX3U 是 Modbus 主站,PLC 会主动向外发请求。
这时 YModbus 可以作为模拟从站来配合调试。
比如 PLC 工程师正在写ADPRW读取一台仪表,但真实仪表还没到货。你可以先用 YModbus Slave 工具或 YModbus.Slave 库模拟一个 RTU 从站。
模拟从站里预先放:
Holding Register 0 = 250 Holding Register 1 = 1000 Holding Register 2 = 0PLC 读到这些固定值,说明ADPRW的从站号、功能码、地址、数量、串口参数基本没问题。
然后再换真实仪表。
这个方法在现场很省时间。否则 PLC 工程师、上位机工程师、仪表供应商三个人一起猜,最后发现只是站号写错了。
常见排查顺序
FX3U Modbus 读不通时,我一般按这个顺序查:
- 硬件是不是
ADP-MB,不是只看有没有 485。 - PLC 端到底是主站还是从站。
- 串口参数是否一致:波特率、数据位、校验、停止位。
- 站号是否一致。
- RS485 的 SDA/SDB、RDA/RDB、SG 有没有按手册接。
- 终端电阻是否合适。
- PLC 里 Modbus 初始化参数是否真的生效。
D8402、D8403这些错误寄存器有没有错误码。- 是否使用了自定义地址映射。
- 上位机地址是否从
0开始,而不是直接写40001。
如果是主站轮询不稳定,再加查:
ADPRW是否保持触发到执行完成- 多条
ADPRW是否被同时触发 - 是否在通信忙时强行切步骤
- 是否把
ADPRW放进不合适的程序流程里
三菱 FX3U 的 Modbus 不难,但它比较“工程化”:硬件型号、特殊寄存器、初始化程序、地址映射,哪一环错了都不通。
一个现场例子
假设你要用 YModbus 读取一台 FX3U 的产量和状态。
建议让 PLC 程序员这样整理:
D0:通讯测试值,固定 1234 D1:设备状态 D2:当前产量 D3:报警代码 D4:运行速度 M0:设备运行中 M1:设备报警中先不要上来就读所有设备点。
第一步,只读D0:
ymodbusread-holding-registers--transport rtu--serial-port COM3--baud-rate 9600--data-bits 8--parity even--stop-bitsone--slave-id 1--address 0--quantity 1读到1234,说明链路、站号、串口参数、功能码和基本映射都对。
第二步,读D0到D4:
ymodbusread-holding-registers--transport rtu--serial-port COM3--baud-rate 9600--data-bits 8--parity even--stop-bitsone--slave-id 1--address 0--quantity 5第三步,读M0和M1:
ymodbusread-coils--transport rtu--serial-port COM3--baud-rate 9600--data-bits 8--parity even--stop-bitsone--slave-id 1--address 0--quantity 2这三步走完,再接入正式 C# 程序。
这样做比一边写代码一边猜线序快得多。
小结
FX3U 的 Modbus 通讯,核心不是“C# 怎么连三菱”,而是先确认 PLC 端有没有真正配置 Modbus 串行通信。
如果 FX3U 做从站,YModbus 就作为 RTU 主站读取它。
如果 FX3U 做主站,YModbus 就作为模拟从站配合它调ADPRW。
如果只是普通串口板或 MC 协议,那就不能直接按 Modbus 处理。
现场联调时,先读固定值D0 = 1234。这个值读通了,再往后扩展。这个小动作能少走很多弯路。
参考资料
- Mitsubishi Electric: FX3S/FX3G/FX3GC/FX3U/FX3UC Series User’s Manual - MODBUS Serial Communication Edition
- Mitsubishi Electric: MELSEC-F FX3 Series MODBUS Communication Sample Ladder Reference Manual
