GitHub 项目地址:https://github.com/lidecong133/YModbus
信捷 PLC 在国产设备里很常见。
尤其是 XD、XL、XG 这些系列,包装机、切割设备、输送线、非标设备、改造项目里经常能看到。
现场问得最多的是:
“信捷 PLC 支持 Modbus,那我能不能直接用 YModbus 读?”
答案还是那句话:先确认它当前开的到底是不是 Modbus。
信捷 PLC 里会遇到好几种通讯方式:Modbus RTU、Modbus ASCII、Modbus TCP、XNET、自由格式通讯、以太网 TCP/IP 通讯。
这些名字看起来都和“通讯”有关,但对 YModbus 来说不是一回事。
YModbus 只处理标准 Modbus。
如果 PLC 端配置的是 XNET,那是信捷自己的协议方向,不能按 Modbus 硬读。
如果配置的是自由格式通讯,那就要看你自己拼的报文是不是 Modbus。
如果配置的是 Modbus RTU、Modbus ASCII 或 Modbus TCP,YModbus 才能按对应模式去连。
下面按信捷 XD / XL / XG 这类现场常见 PLC,把 Modbus 通讯怎么判断、怎么读、怎么排查讲清楚。
先分清通讯方式
信捷 PLC 做 Modbus,常见有三类入口。
第一类,串口 Modbus。
在 XDPPro 的 PLC 串口设置里,通常可以选择 Modbus 通讯,并在 Modbus-RTU 和 Modbus-ASCII 之间选择。
这时要确认:
- 使用哪个串口
- 是 RS232 还是 RS485
- 协议是 RTU 还是 ASCII
- 波特率、数据位、校验位、停止位
- PLC 站号
- 写入参数后是否需要重新上电
第二类,以太网 Modbus TCP。
带网口的 XD / XL / XG 型号,或者通过以太网模块时,可能会走 Modbus TCP。信捷资料里也能看到以太网侧会出现 Modbus-TCP 和 XNET 两种方向。
这里不要看到网口就默认是 Modbus TCP。
网口能下载程序,XDPPro 能连接,不代表外部主站就能按 Modbus TCP 读 PLC 数据。
第三类,PLC 主动访问外部设备。
比如 PLC 作为 Modbus TCP Client 或 RTU Master,去读扫码枪、仪表、变频器、远程 I/O。
这时 PLC 是主站或客户端,YModbus 就应该反过来做从站或服务器模拟器。
RTU和ASCII不要混
信捷串口配置里会看到 Modbus-RTU 和 Modbus-ASCII。
这两个不是同一个帧格式。
RTU 是二进制帧,靠 CRC 校验。
ASCII 是文本帧,冒号开头,靠 LRC 校验。
接线都可能是 RS485,但协议不一样。
所以第一次联调时,不要只问“是不是 485”。
要问:
协议:RTU 还是 ASCII 串口:COM3 波特率:9600 / 19200 / 38400 数据位:7 或 8 校验:None / Even / Odd 停止位:1 或 2 站号:1 到 247如果 PLC 配的是 ASCII,YModbus 就要用 ASCII Client。
如果 PLC 配的是 RTU,YModbus 就要用 RTU Client。
用错模式,表现通常就是超时。
信捷PLC做Modbus RTU从站
如果你希望 YModbus 读取信捷 PLC,最常见结构是:
信捷 PLC 做 Modbus RTU 从站,YModbus 做 Modbus RTU 主站。
PLC 侧要确认:
- 串口已经设置成 Modbus-RTU
- 通讯参数已经写入 PLC
- 站号正确
- 需要重新上电的参数已经生效
- 地址表里明确写出了 Modbus 地址
YModbus 代码示例:
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:3);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 3这里的address: 0只是示例。
实际项目一定要按信捷 PLC 侧的 Modbus 地址表来。不要看到 PLC 里是D0,就默认 YModbus 地址一定是0。
信捷PLC做Modbus ASCII从站
有些旧设备或特殊项目会用 Modbus ASCII。
这时 YModbus 要这样创建 ASCII Client:
usingSystem.IO.Ports;usingYModbus.Clients;usingYModbus.Serial;usingSerialPortport=new("COM3"){BaudRate=9600,DataBits=7,Parity=Parity.Even,StopBits=StopBits.One,ReadTimeout=3000,WriteTimeout=3000};port.Open();awaitusingModbusClientclient=ModbusSerialClientFactory.CreateAscii(slaveId:1,serialPort:port,leaveOpen:true);ushort[]values=awaitclient.ReadHoldingRegistersAsync(0,3);ASCII 项目最容易错的是数据位和校验位。
不要拿 RTU 的8,N,1去套 ASCII。
现场必须以 PLC 串口配置为准。
信捷PLC做Modbus TCP Server
如果信捷 PLC 带以太网,或者项目里配置了 Modbus TCP Server,YModbus 就可以作为 TCP Client 读取。
典型参数:
PLC IP:192.168.1.70 端口:502 UnitId:1YModbus 示例:
usingYModbus.Clients;awaitusingModbusClientclient=awaitModbusClientFactory.CreateTcpAsync(host:"192.168.1.70",port:502,unitId:1,readTimeoutMilliseconds:3000,writeTimeoutMilliseconds:3000);ushort[]values=awaitclient.ReadHoldingRegistersAsync(startAddress:0,quantity:3);CLI 示例:
ymodbusread-holding-registers--host 192.168.1.70--port 502--unit-id 1--address 0--quantity 3如果 TCP 读不到,先查:
- 电脑和 PLC 是否同网段
- PLC 网口是否真的启用了 Modbus TCP
- 项目是不是用 XNET,而不是 Modbus TCP
- 端口是否是
502 - UnitId 是否需要设置
- 地址是否真的映射了数据
- 是否有防火墙或交换机策略拦截
信捷这里很容易出现“编程软件能连,但 Modbus TCP 读不到”的情况。
这不是矛盾。
编程软件可能走 XNET 或其它连接方式,YModbus 只走 Modbus。
信捷PLC做主站或Client
有些信捷项目里,PLC 是主动访问设备的一方。
比如:
- PLC 通过 RTU 读取变频器状态
- PLC 通过 RTU 读取温控表
- PLC 通过 Modbus TCP 访问扫码枪或远程 I/O
- PLC 通过以太网 M_TCP 类指令发送 Modbus TCP 请求
这时 YModbus 的角色要反过来。
如果信捷 PLC 是 RTU 主站,YModbus 可以做 RTU 从站。
如果信捷 PLC 是 TCP Client,YModbus 可以做 TCP Server。
这种方法特别适合 PLC 程序调试。
真实设备还没到现场时,先用 YModbus 从站工具放几个固定值:
Holding Register 0 = 250 Holding Register 1 = 1000 Holding Register 2 = 0让信捷 PLC 去读。
PLC 能读到这些值,说明 PLC 端的站号、功能码、地址、数量、串口参数或 TCP 连接基本正确。
后面再换真实设备。
地址映射不要靠猜
信捷 PLC 里会看到很多软元件:
XYMSSMDHDTDCDFDSFD
这些名字对 PLC 工程师很直观,但对 YModbus 不够。
YModbus 需要的是功能码和数字地址。
更好的地址表应该这样写:
| Modbus地址 | 功能码 | PLC软元件 | 类型 | 说明 |
|---|---|---|---|---|
0 | 03 | 通信测试值 | UInt16 | 固定1234 |
1 | 03 | 设备状态 | UInt16 | 0 停止,1 运行 |
2 | 03 | 报警代码 | UInt16 | 0 无报警 |
10 | 03 | 温度原始值 | Int16 | 实际值 = 原始值 / 10 |
0 | 01 | 运行中 | Bool | Coil |
不要只写:
D100:温度 M10:运行中 Y0:输出这种表对上位机不够。
上位机还要知道它对应的是03还是04,是保持寄存器还是输入寄存器,是线圈还是离散输入,地址是十进制还是十六进制。
X和Y的编号要特别小心
信捷项目里,X和Y点经常会碰到八进制编号习惯。
比如Y10,很多新手会下意识当成十进制的 10。
但在 PLC 编号里,它可能表示八进制意义上的下一组点。
信捷资料里有一个很典型的提醒:Y0对应的 Modbus 地址是H6000,Y10对应的是H6008,不是H6010。
这句话很值得记住。
所以如果项目要读X、Y这种点位,不要靠肉眼换算。
让 PLC 侧直接给最终 Modbus 地址,最好写成十进制。
比如:
Y0 -> Coil 24576 Y10 -> Coil 24584这样上位机就不容易把八进制、十六进制、十进制混在一起。
40001和地址0
Modbus 资料里经常写40001。
YModbus 里传的是协议地址。
所以:
显示地址 40001 -> YModbus 地址 0 显示地址 40002 -> YModbus 地址 1 显示地址 40011 -> YModbus 地址 10如果信捷地址表里写的是4X类型地址,要问清楚它给的是显示地址,还是协议地址。
如果给的是H6000这种十六进制地址,要先转成十进制再填到 YModbus 里。
H6000对应十进制24576。
这个转换不要在现场临时心算。
写到地址表里。
浮点数和高低字节
信捷资料里也会提到高低字节交换、字节顺序这类问题。
这说明实际项目里确实会遇到数据顺序不一致。
比如一个温度、压力、重量或位置值,如果用 32 位浮点数表示,它通常占两个寄存器。
YModbus 读出来先是两个ushort:
ushort[]raw=awaitclient.ReadHoldingRegistersAsync(10,2);Console.WriteLine(raw[0]);Console.WriteLine(raw[1]);不要一上来就只看最终float。
先把原始寄存器记下来,再和 PLC 工程师确认:
- 高字在前还是低字在前
- 每个字内部高低字节是否交换
- 是否其实是整数倍率,而不是浮点数
- 正负数是否按有符号整数处理
现场最有用的说法不是“读出来不对”。
而是:
我从地址10读了两个寄存器,原始值是17142和59769。按高字在前解析是12.34,按低字在前不对。
这样 PLC 侧马上知道该查字序还是查映射。
写入要走命令区
信捷 PLC 支持 Modbus 写入时,不建议上位机直接写输出点。
尤其是Y点、伺服使能、气缸动作、切刀动作、加热输出这些,不要直接给上位机开放。
更稳的方式是做通信命令区:
Holding Register 100:命令号 Holding Register 101:参数 1 Holding Register 102:参数 2 Coil 100:命令触发 Coil 101:PLC 已接收 Coil 102:PLC 执行完成 Holding Register 110:执行结果码上位机只写命令区。
PLC 程序自己判断设备模式、互锁、急停、报警、伺服状态,再决定是否执行。
YModbus 写寄存器示例:
awaitclient.WriteSingleRegisterAsync(address:100,value:1);写线圈示例:
awaitclient.WriteSingleCoilAsync(address:100,value:true);第一次写入前,先在 YModbus 从站工具里模拟一遍。
确认主站写入流程没问题,再接真实 PLC。
一个推荐的联调顺序
第一次接信捷 PLC,我建议这样走:
- 确认协议是 Modbus RTU、Modbus ASCII、Modbus TCP,还是 XNET / 自由格式。
- 确认 PLC 是从站/Server,还是主站/Client。
- 如果是串口,确认端口、波特率、数据位、校验位、停止位、站号。
- 如果是 TCP,确认 IP、端口、UnitId,以及是否真的启用了 Modbus TCP。
- 让 PLC 侧给 Modbus 地址表,不要只给
D100、M10。 - 先放固定值
1234。 - 用 YModbus CLI 或主站工具读一个寄存器。
- 再读多个寄存器。
- 再读线圈。
- 最后处理浮点数、双字和写入命令区。
如果 PLC 是主站,就反过来:
先用 YModbus 从站工具模拟设备,让 PLC 来读。
常见坑
信捷 PLC 联调 Modbus 时,常见坑有这些:
- XNET 当成 Modbus TCP
- 自由格式通讯里自己拼的报文和 Modbus 不一致
- PLC 配的是 ASCII,上位机按 RTU 读
- 写入通讯参数后没有重新上电
- 串口参数只错了一个校验位
- RS485 A/B 接反
- 把
D100当成 Modbus 地址100 - 把
Y10当成十进制点位 - 把十六进制
H6000当成十进制6000 - 把
40001原样填进startAddress - PLC 是主站,却被上位机当成从站读
这些问题都不复杂,但很浪费时间。
所以还是那句话:先读固定值,再扩大范围。
小结
信捷 PLC 做 Modbus,关键是先把通讯方式和角色分清楚。
如果 PLC 配成 Modbus RTU / ASCII 从站,YModbus 就用串口主站去读。
如果 PLC 配成 Modbus TCP Server,YModbus 就用 TCP Client 去读。
如果 PLC 自己是 RTU Master 或 TCP Client,YModbus 就做从站或 Server 模拟器。
如果现场用的是 XNET 或自由格式通讯,那就不要拿 Modbus 硬套。
地址方面,D、M、X、Y都要落实到最终 Modbus 地址,尤其注意X/Y的八进制编号和H6000这种十六进制地址。
把这些边界说清楚,信捷 PLC 的 Modbus 通讯就不难调。
参考资料
- 信捷 XD3 系列标准型控制器资料页
- 信捷 XD/XL/XG 系列可编程控制器用户手册 软件篇
- Xinje TCP/IP communication based on Ethernet
- 信捷 XD 系列 PLC 基本指令使用第七讲:Modbus 通讯