干工控这些年,欧姆龙PLC的通信协议算是我交学费最多的地方之一。从CP1H的串口折腾到NJ/NX的EtherNet/IP,从HostLink到FINS再到Modbus-RTU,每一套协议都有不少让人抓狂的细节:节点号对不上、帧格式错一位、波特率设错、地址偏移算错……表面上看到的都是“通信不上”,背后原因五花八门。这篇文章把我踩过的坑和最后搞明白的事按协议类型、按排查路径整理出来,希望能让刚接触欧姆龙的朋友少走弯路,也让已经在跳坑里的人尽快爬出来。
1. 欧姆龙通信协议全景:先把“家族成员”认明白
欧姆龙的PLC通信协议,其实是一套“家族体系”。很多人一上来就搜“欧姆龙PLC通信协议”,以为只要知道一个协议就行,实际上欧姆龙至少有四五种常用通信方式。如果不先搞清楚你手上这台PLC支持哪些协议、上位机或触摸屏打算走哪种,后面调起来会很乱。我在现场见过不少同行把CP1H当西门子那样用,上来就写Modbus却不知道怎么映射数据区,也见过有人把NJ的网口当成普通Modbus TCP去读标签,结果死活读不到。所以第一步很重要:认清楚欧姆龙这套通信家族里都有谁。
1.1 串口时代的三大协议:HostLink、FINS、Modbus-RTU
先讲串口。虽然现在网口普及了,但大量老设备、仪表、变频器、触摸屏还在用RS232/RS485,串口协议仍然是绕不开的。欧姆龙PLC在串口上最常见的协议有三个:HostLink、FINS、Modbus-RTU。
HostLink是欧姆龙自有的串口命令协议,也是很多触摸屏选“欧姆龙”驱动时默认走的协议。它的报文是ASCII字符帧,格式大概是“@单元号 命令 数据 FCS * 回车”。因为是人可读的ASCII码,调试时拿串口助手直接看就能发现格式问题,非常直观。代价是效率偏低,一个命令只能干一件事,批量读写DM区或CIO区时帧比较长,适合数据量不大的上位机、文本屏场景。CP1H自带的RS232C口和外设口都能跑HostLink,默认参数是9600、7位数据、偶校验、2停止位,单元号0。这个默认参数我要特别提醒,很多人拿8N1去连,门都摸不到。
FINS是欧姆龙更底层的协议,分串口版和以太网版。串口版FINS主要用于SYSMAC WAY方式连接,报文是二进制帧,比HostLink紧凑得多,功能也强很多,能读指定内存区、执行远程程序控制、查PLC状态。FINS报文的头部字段比较多:ICF、RSV、GCT、DNA、DA1、DA2、SNA、SA1、SA2、SID,后面才是命令码和数据。新手看着这些缩写头大,其实拆开看就是“从哪个网络、哪个节点、哪个单元来,到哪个网络、哪个节点、哪个单元去”,再加上一个“服务ID”用于匹配应答。用熟了以后,批量读写内存比HostLink顺畅很多。
Modbus-RTU则是工业通用协议,欧姆龙很多型号内置了Modbus主站/从站功能。比如CP1H的串口可以配置成Modbus-RTU简易主站,用一条指令轮询变频器、温控表、电表;也可以配置成从站,让组态软件或别的PLC来读。Modbus的好处是通用性极强,任何品牌的设备几乎都支持。坏处是欧姆龙的内存区和Modbus寄存器之间不是天然一一对应,需要做地址映射,这里非常容易踩坑,后面单独讲。
这三个协议怎么选?我一般按通信对象来定。触摸屏和文本屏优先HostLink,简单稳定,面板上填好单元号就行。上位机软件或者机器人的PLC通信库,优先FINS,尤其是网口FINS,功能强、速度快。带一堆变频器、仪表,优先Modbus-RTU,因为这类设备几乎都只认Modbus。
1.2 网口时代的两大主力:EtherNet/IP 与 FINS/TCP
现在的欧姆龙PLC基本都带以太网口,像NJ/NX、CJ2、CP1H加扩展模块也有网口。网口上的通信比串口丰富,但也更容易让人混淆。最常见的是FINS/TCP、FINS/UDP和EtherNet/IP。
FINS/TCP和FINS/UDP是把FINS命令封装进TCP或UDP包里。端口固定,TCP/UDP都是9600。这里有个很多人忽略的机制:FINS/TCP通信建立时,上位机需要和PLC协商节点地址,一个连接对应一个FINS节点。如果你的上位机程序只做了socket connect就直接发FINS命令,没有先协商节点,有些PLC会直接拒绝。FINS/UDP则不一样,它默认就是无连接的,把FINS报文发过去就行,但需要考虑路由器、防火墙以及应答端口的问题。我在现场遇到过几次:FINS/UDP命令发出去了,PLC也处理了,但应答发到了一个固定端口,上位机却只监听发起端口,导致“看起来没反应”。抓包才发现应答包在另一个端口上躺着。
EtherNet/IP则是基于CIP协议的工业以太网,欧姆龙NJ/NX系列支持得特别好。它分显式报文和隐式IO报文两种:显式报文适合来回读写下数据,像访问标签;隐式IO是周期性交换数据,适合PLC和PLC、PLC和视觉系统之间实时交换大量点位。EtherNet/IP的坑主要在配置上:第三方上位机需要安装EDS文件才能识别设备型号;连接类型要选对是“定时IO”还是“未连接”;IO映射表和PLC标签数据类型要匹配。相比之下,FINS/TCP更像一个“通用网口协议”,不用装EDS,自己做报文,适合上位机开发。
1.3 选型思路:先问“谁和谁通信”再选协议
我见过很多朋友一上来就问“欧姆龙PLC为什么连不上”,其实是还没想清楚到底要完成什么通信任务。选协议不是越高级越好,也不是哪个流行用哪个,而是先回答三个问题:谁发起通信?通信对象是什么设备?数据量多大,实时性要求多高?
如果PLC和触摸屏通信,HostLink永远是稳妥选择,触摸屏组态里直接选欧姆龙HostLink驱动,填单元号,不用写PLC程序。如果PLC和PC上位机、机器人控制柜通信,我会优先用FINS/TCP,因为它不需要在PLC里组态数据标签,直接读CIO、DM地址,和三菱的MC协议一个思路。如果PLC要读一堆变频器、仪表、传感器,那基本就是Modbus-RTU轮询,走485总线,注意终端电阻和从站地址。
PLC和PLC之间则另说。同品牌欧姆龙之间可以用FINS/UDP或者FINS/TCP,也可以用EtherNet/IP标签数据链接,后者更适合周期性同步生产数据。跨品牌的话,西门子和欧姆龙之间经常用PROFINET或者EtherNet/IP网关,这时EtherNet/IP反而是通用语言。想清楚“谁和谁通信”,再回头查协议手册,效率会高很多。
2. 通信失败?我踩过的坑大多集中在这几个地方
通信协议本身并不难,难的是工程现场一堆变量叠加。我这些年遇到的“死活连不上”,九成问题出在物理层参数、FINS地址字段、PLC侧设置这几类。把这几类坑记牢,排查速度能快一倍。
2.1 电缆与串口参数:通信第一关是物理层不是协议
先说说最容易被忽视的RS232和RS485接线。CP1H自带的RS232C口是标准DB9母头,但很多调试线是“公母转接头”组装出来的,针脚定义对不上就完蛋。外设口更是特殊,它不是标准DB9,需要欧姆龙专用编程电缆,或者按外设口针脚定义自己做线。现场没有示波器的话,接线错了根本看不出来,只能拿万用表量。
RS485接线则要注意A/B标号混乱。不同厂家对A/B、D+/D-的定义可能刚好相反,同样的线接A家设备能通,接B家设备就乱码。我在调485时习惯先看对方设备的说明书标号,再统一用“同名相接”原则,而不是凭经验。另外485总线两端要接终端电阻,尤其距离超过几十米、波特率又高的时候,没有终端电阻会出现偶发通信错误和CRC校验失败。
串口参数更是重灾区。欧姆龙HostLink默认是9600、7位数据、偶校验、2停止位,也就是7E2。很多人上位机默认8N1就去读,结果连响应都没有。还有一点,PLC的串口参数不是改完立即生效,改完通讯设置后需要断电重启或者让PLC重新上电,否则上位机看到的还是旧参数。CP1H还容易忽略一个设置:串口通信模式在PLC系统设置里必须选“HostLink”,如果选成了“无协议”,不管上位机发什么命令,PLC都不会回。
2.2 FINS三号缺一不可:网络号、节点号、单元号
FINS报文里有一串地址信息:DNA(目标网络号)、DA1(目标节点号)、DA2(目标单元号),还有对应的源地址SNA、SA1、SA2。这里最容易犯的错,就是只改IP地址,没有改报文里的目标节点号。
我见过一个实际案例:上位机程序里IP设对了,PLC的IP也Ping通了,但FINS指令一直超时。查了半天发现FINS报文里的DA1还是默认值1,而PLC的FINS节点号被设成了10。PLC收到帧后一看目标节点号不是自己,直接丢弃,根本不回。FINS节点号不等同于IP地址,它是FINS层独立的编号。以太网模块或内置网口的FINS节点号需要单独去设置,在CX-Programmer的IO表、或者Sysmac Studio的网络配置里能看到。
同样容易错的是单元号DA2,CPU单元号一般为0。如果有多CPU系统或扩展通信单元,DA2要填对应单元号,不填0就找不到目标。建议调任何FINS通信前,先把三号写在一张纸上:网络号填多少、节点号填多少、单元号填多少,然后再对照报文逐字节核对,能省下大量时间。
2.3 FINS/TCP与FINS/UDP:各自藏着不一样的坑
FINS/TCP和FINS/UDP虽然命令格式一样,但坑各有各的坑。
FINS/UDP的坑在对端口的理解和防火墙。UDP不需要建立连接,但要保证上位机发送请求的端口和接收应答的端口一致。部分PLC型号会把应答发到请求IP加固定端口,而不是原样发回源端口。我建议先用网络调试助手抓包,看PLC是否回了包、回包发到哪个端口,再决定上位机绑定哪个端口监听。防火墙也是老问题,Windows防火墙默认可能拦截UDP 9600,调完记得加白名单。
FINS/TCP的坑则在连接建立和连接数限制。FINS/TCP不是连上TCP就能直接发FINS命令,要先做节点地址协商。很多开源库会自动处理这个协商,但如果你自己写socket,就要先搞清楚协议:PLC会分配一个FINS节点号给上位机,协商成功后才能正常收发。另外FINS/TCP连接数有上限,比如NJ系列某些型号默认只允许几个并发连接,调试时开了一堆上位机软件不关,新连接可能直接被拒绝。遇到连接不上的情况,把其他上位机断开再试,常常就好了。
2.4 PLC程序侧被忽略的三个晴雨表设置
很多通信问题不在上位机,而在PLC侧。我归纳了三个最常被忽略的设置项,顺手记下来能少踩很多坑。
第一是串口协议模式。CP1H和CJ系列串口默认可能是“无协议”模式,只能通过串口指令功能收发自定义数据,不能响应HostLink或Modbus命令。必须进PLC系统设置,把端口模式改成HostLink或Modbus-RTU,下载后重启生效。
第二是Modbus从站的数据映射。如果欧姆龙PLC做Modbus-RTU从站,不是把CIO/DM随便暴露出去就行,需要在设置里选择映射区。默认映射关系往往是从40001开始对应一段连续保持寄存器区,而这和PLC内部地址不一定对得上。做从站前先查清楚映射表。
第三是EtherNet/IP标签刷新。NJ/NX上用标签通信时,如果标签的数据类型和上位机里定义的不一致,会出现数据错位或者读取失败。此外,如果PLC的IO周期设置得很短,而上位机RPI周期设置得很长,两边数据刷新不同步,会出现“读到的数据跳变”的假象。
3. 走通一条完整链路:从接线到上位机读到DM区数值
光讲概念不够,我拿一套最小可复现的配置,把从物理连接到成功读数据的完整步骤走一遍。这套路我只要换现场就会重复一遍,几乎可以复制到任何欧姆龙PLC通信场景。
3.1 硬件准备与连接:先把电缆和参数固定下来
这里以最经典的CP1H-XA40DR-A为例,PLC自带一个外设口和一个RS232C口。我要用串口走HostLink,所以把USB转RS232调试线连到PLC的RS232C口。注意不要插到外设口上,外设口需要专用编程电缆,普通DB9线直接插上去针脚定义完全不同。
串口参数按HostLink默认来:9600,7位数据,偶校验,2停止位,单元号0。用串口调试助手打开COM口,设置好参数,发送区勾选“发送新行”或手动在帧尾加回车。有的调试工具默认以文本模式发送,如果FCS计算出来的字符是十六进制,要确保发送的是ASCII字符而不是十六进制字节。
我在现场经常遇到一个问题:“PLC串口助手发了命令没反应”。先确认三件事:PLC供电是否正常,PLC有没有处于运行或监视模式(编程模式下HostLink也能通,但个别功能受限),串口设置有没有下载并重启。如果都正常,那问题大概率在命令格式上。
3.2 手工发送一条HostLink命令:算FCS校验再发
我们来读DM区D1这一个字的当前值。HostLink读DM区命令格式:
@00RD00010002xx*
拆开看:
- @固定起始符
- 00是单元号,默认0号,固定两位
- RD是Read命令,读内存区
- 00是内存区代码,00代表DM区
- 0001是起始地址,D1就是地址0001,注意要写成4位十六进制
- 0002是读取字数,这里读1个字就够了,但HostLink按字读取,写0001表示读D1这一个字
- xx是FCS校验码,两个字符
- *是结束符,后面跟回车
FCS的计算方法是对@后面的所有字符逐字做异或,直到*之前。我们算一下字符串“00RD00010001”(起始地址改成0001,读取字数0001):
字符依次为:0、0、R、D、0、0、0、1、0、0、0、1。 对应ASCII码逐字节异或: 0x30 XOR 0x30 = 0x00 0x00 XOR 0x52 = 0x52 0x52 XOR 0x44 = 0x16 0x16 XOR 0x30 = 0x26 0x26 XOR 0x30 = 0x16 0x16 XOR 0x30 = 0x26 0x26 XOR 0x31 = 0x17 0x17 XOR 0x30 = 0x27 0x27 XOR 0x30 = 0x17 0x17 XOR 0x31 = 0x26
最后结果是0x26,即ASCII字符“26”。所以完整命令是:
@00RD0001000126*
发送后,PLC正常情况下会回复类似:@00RD000100010026*这个帧里“0001”是读的字数,“0026”是数据,表示D1当前值是0x0026。如果你看到响应代码不是0000而是其他值,说明命令格式有问题,或地址超出范围。
顺带提一句:地址换算特别容易错。读D100时起始地址是0064而不是0100,因为D后编号是十进制,而地址字段是十六进制。读W100也一样,W后的编号要转十六进制再填入地址。这个坑我在现场见过不止一次,上位机程序读出来全是对的,就是地址不对,数据全是0。
3.3 用Python走通FINS/TCP:一个可用的最小例子
串口HostLink适合验证和简单上位机,真正做项目时,我更多用FINS/TCP。这里给出一个极简Python示例,用来读取CP1H或CJ/NJ系列的DM区数据。
import socket import struct PLC_IP = "192.168.1.10" PLC_PORT = 9600 MY_NODE = 0x01 # 上位机FINS节点号,需和PLC侧不冲突 PLC_NODE = 0x0A # PLC的FINS节点号,需查PLC配置 def send_fins_tcp(memory_code: int, start_addr: int, count: int): # 1. 建立TCP连接 s = socket.create_connection((PLC_IP, PLC_PORT), timeout=3) # 2. FINS/TCP协议头 + FINS报文 # FINS/TCP头: FINS(4字节) + 长度(4字节) + 命令(2字节) + 错误码(2字节) + 节点号(1字节) fins_tcp_header = b"FINS" + struct.pack(">I", 26) + b"\x00\x00\x00\x00" + bytes([MY_NODE]) # 4. FINS命令:读内存区 # 发送端信息忽略:ICF=0x80, RSV=0x00, GCT=0x02, DNA=0x00, DA1=PLC_NODE, DA2=0x00 # 源端信息:SNA=0x00, SA1=MY_NODE, SA2=0x00, SID=0x00 # 命令码:0101为读内存区 # 内存区代码:DM=0x82,起始地址(2字节),读取字数(2字节) fins = bytes([ 0x80, 0x00, 0x02, 0x00, PLC_NODE, 0x00, 0x00, MY_NODE, 0x00, 0x00, 0x01, 0x01, memory_code, (start_addr >> 8) & 0xFF, start_addr & 0xFF, (count >> 8) & 0xFF, count & 0xFF, ]) s.sendall(fins_tcp_header + fins) # 5. 读取响应 resp = s.recv(1024) s.close() # 6. 解析:响应里第19字节起是命令码,第21-22字节是响应码,后面是数据 res_code = struct.unpack(">H", resp[21:23])[0] if res_code != 0x0000: raise RuntimeError(f"PLC返回错误码: 0x{res_code:04X}") # 每个字2字节,高字节在前 words = [] for i in range(count): val = struct.unpack(">H", resp[23 + i * 2 : 25 + i * 2])[0] words.append(val) return words if __name__ == "__main__": data = send_fins_tcp(0x82, 100, 10) # 读DM区D100开始的10个字 print(data)这段代码有个容易迷的地方,FINS报文里的起始地址在“response解析时”要按帧实际结构来数。我写的时候故意留了个注释“第19字节起”的约定,实际不同固件版本可能因为FINS/TCP头长度不同而有偏移,所以最好先用抓包工具确认一次。读DM区用内存代码0x82,读CIO区用0x80,读W区用0x31,读HR区用0x32。这些代码值建议抄在小本子上。
这个例子没有处理FINS/TCP的握手协商,实际用有些型号的PLC会直接拒绝不协商的请求。如果要更严谨,需要先发送节点地址设定命令(命令码0x00,子命令0x00),从响应里拿到PLC分配给你这个连接的FINS节点号,再用这个节点号做后续通信。入门阶段可以先在PLC网口参数里关闭“FINS节点地址协商要求”,但正式项目不建议关。
3.4 地址换算和内存区代码:一张备忘对照
不同系列的欧姆龙PLC,内存区名称和FINS代码基本上通用,但还是有细微差别。我做了一张自己常用的对照表:
| 内存区 | 常用名称 | FINS内存代码 | 说明 |
|---|---|---|---|
| CIO区 | CIO | 0x80 | 最常见的IO和内部继电器区 |
| WR区 | W | 0x31 | 工作继电器区,掉电不保持 |
| HR区 | H | 0x32 | 保持继电器区,掉电保持 |
| DM区 | D | 0x82 | 数据存储器,按字访问 |
| EM区 | E | 0x98 | 扩展数据存储器,部分系列才有 |
| 定时器 | TIM | 0x89 | 读取定时器当前值或状态 |
读CIO区和DM区最常用,但地址换算要注意:CIO区通常按“通道”访问,比如CIO100就是0x0064。DM区按D后的编号直接换算十六进制。WR区也是,W0就是0x0000,W100就是0x0064。很多PLC程序里看到的“CIO 10.00”指的是通道10的第00位,如果你只读一个字那就是通道10的整个值。
关于地址换算,我的实际经验是:先在PLC编程软件里看到对应变量的绝对地址,再换算十六进制。别靠心算,现场一旦算错,排查时间成倍增加。写个脚本或者用计算器转一下,稳得多。
3.5 响应超时与并发轮询的经验值
上位机通信超时时间设置多少合适?我通常这样设:串口HostLink轮询周期至少100ms以上,超时500ms到1秒;FINS/TCP超时200到500ms;EtherNet/IP隐式IO的RPI周期从10ms到100ms看需求。不是说越快越好,太快会把老型号PLC的通信模块拖死,导致偶发超时。
轮询多个站时,我习惯把读取数据量合并成大帧。比如同一台PLC要读20个温度值,不要发20条单字读取命令,而是发一条连续读取20个字的FINS命令,一次往返全部拿回,效率能提高一个数量级。Modbus-RTU轮询变频器也是一样,尽量连续读寄存器块而不是逐寄存器读。
4. 常见问题速查:一张表记住八成故障
到现场排查通信问题,很多时候没空从头看协议文档。我把自己多年遇到的典型问题整理成一张速查表,基本覆盖了八成故障现象,按表排查比较快。
4.1 高频故障排查速查表
| 故障现象 | 可能原因 | 处理方式 |
|---|---|---|
| 串口发命令PLC完全无响应 | 串口参数不对,PLC未处于HostLink/Modbus模式 | 确认7E2、9600、单元号0,重新下载设置并重启 |
| 收到响应但FCS报错 | FCS计算错误或发送时多加了不可见字符 | 用串口调试助手查看发送的十六进制字节,逐字符核算FCS |
| 485通信时通时断 | A/B反了,缺终端电阻,波特率过高 | 检查接线、加120欧终端电阻、降波特率到9600 |
| FINS/TCP连不上 | 未做节点协商,连接数满,防火墙拦9600 | 先协商节点,关掉其他上位机,加防火墙白名单 |
| FINS/UDP收不到应答 | 应答端口不一致,防火墙拦截UDP 9600 | 抓包看应答端口,绑定对应端口监听 |
| 读数据全0或全F | 地址换算错误,起始地址填了10进制 | D100填0064,W100填0064,CIO100填0064 |
| 读个别地址数据乱跳 | IO周期和上位机读取周期不同步 | 调小RPI或增大读取间隔,保持数据一致快照 |
| Modbus读到的寄存器值对应关系错 | 地址偏移没有处理好 | 40001对应协议地址0,PLC组态里填0,不能填40001 |
| EtherNet/IP设备无法识别 | 没装EDS文件或型号版本不匹配 | 安装对应版本EDS文件,检查连接类型 |
| 通信超时频繁 | 轮询周期太短或PLC扫描周期太长 | 合并批量读命令,轮询周期放到100ms以上 |
4.2 Modbus的40001偏移陷阱
Modbus的保持寄存器地址经常被写成40001、40002这样的“PLC地址”,但协议报文里的寄存器寻址是从0开始的。也就是说设备手册上写“保持寄存器40001,对应参数X”,你发Modbus报文时地址其实要填0。在欧姆龙CP1H的Modbus-RTU简易主站指令里,地址参数很多资料直接要求填“寄存器编号减1”,也就是40001填0、40002填1。
这个偏移问题在接变频器时特别明显。有次我帮朋友调一台国产变频器,Modbus Poll里填40001读出来转速对不上,填0才对。因为变频器从站内部把40001对应到第一个保持寄存器,也就是协议地址0,而Modbus Poll这种上位机软件有时会自动帮你做地址转换,有时不会,必须自己搞清楚软件是否帮你减了1。
欧姆龙PLC做Modbus主站也一样。如果用功能码03读保持寄存器,目的起始地址要填协议地址;如果用触摸屏自带的Modbus驱动去读,触摸屏软件通常让你填40001,它会自动处理。结论就是:先确认通信对象是PLC还是第三方设备,再确认填的是协议地址还是PLC地址。这个确认动作花30秒,能省至少半天排查时间。
4.3 扫描周期、IO刷新与通信负载
还有一个容易被忽略的场景:PLC扫描周期对通信的影响。有个项目里NJ的EtherNet/IP标签数据链接总是延迟很大,点动按钮要隔几百毫秒才反应。查到最后发现PLC程序里有一个很长的循环,扫描周期被拖到80ms,而EtherNet/IP的RPI设的是10ms,两边数据刷新频率严重不匹配。把循环优化掉之后,扫描周期降到2ms,通信延迟立刻正常。
上位机读数据的频率也要考虑PLC的通信负载。老型号串口PLC在9600波特率下,一条HostLink命令带校验和回车大概是几十个字节,传输时间就得几十毫秒。如果上位机每10ms发一条命令,数据根本来不及回,通信就会堆积、超时。稳妥的做法是每50ms到100ms轮询一次,或者用批量读取代替零散读取。
4.4 调试工具的实用心得
调欧姆龙通信,我包里永远带着三样工具:串口调试助手、网络调试助手、Modbus Poll/Modbus Slave。
串口调试助手调HostLink和Modbus-RTU特别好用,注意看十六进制发送和ASCII发送的区别。HostLink是ASCII协议,直接用文本模式发送,但要确保FCS字符是ASCII字符不是十六进制字节。Modbus-RTU是二进制协议,必须用十六进制模式发送,一个字节一个字节拼完全帧。
网络调试助手用来抓FINS/TCP和FINS/UDP的原始报文,能看到PLC到底回没回、回的内容是什么、发到哪个端口了。很多“PLC没反应”的真相是“上位机没接对端口”,抓包一眼就看出来。
Modbus Poll是调从站设备的神器,支持Modbus-RTU和Modbus-TCP,可以直接读寄存器,验证地址和功能码。想确认欧姆龙PLC做Modbus从站是否正常,就用Modbus Poll去连PLC,比自己写测试程序快得多。
最后再分享一个小技巧:调FINS通信时,无论协议多复杂,先从最简单的“读PLC型号”命令开始验证。这个命令不带数据地址,只要地址信息对,PLC一定会回一个设备型号字符串。如果连这条都超时,说明物理层或FINS三号还有问题;如果这条通了,再继续读内存区。这种“先小步验证再扩大范围”的调试思路,比拿着完整命令一头扎进去要省时间得多。
我个人在实际项目里还有一个习惯:每种通信方式第一次调通后,把调好的接线定义、串口参数、地址映射、上层代码片段存成一个项目模板。下次接到同类任务,直接套模板改地址就行。欧姆龙的通信协议种类多,但万变不离其宗,物理层、链路层、应用层一层一层排查,基本没有解不开的死结。