
1. 先把话说清楚欧姆龙通信到底有哪几套路子搞欧姆龙PLC通信最让人头疼的不是协议本身多复杂而是资料太散不同系列、不同软件、不同固件版本给出的方案还不一样。我自己最早就是从CP1H摸着石头过河的后来接触到NJ、NX这些机器才慢慢把整张地图拼完整。先给新手一个全景图。欧姆龙PLC上你能用到的通信方式基本就是下面这几种HostLink协议、FINS协议FINS/UDP和FINS/TCP、Modbus-RTU从站或者主站以及CX-P协议宏和无协议Non-procedure通信。Sysmac Studio时代NJ/NX还直接把EtherNet/IP、EtherCAT这些放到了台面上但底子里FINS依然在只是包装得更漂亮了。很多人在这一步就栽了跟头——不是不会写程序而是压根不知道自己该用哪个协议。比如CP1H只有串口你硬要去跟别人聊FINS/TCP那是聊不通的NJ/NX自带网口你却还在琢磨HostLink的FCS校验绕了一大圈弯路。所以我的建议是拿到项目先搞清楚两件事对端是什么设备PLC这边有什么物理接口。这两点定了协议选型就八九不离十了。串口时代CP1H、CP1L、CJ1M这些优先考虑HostLink为什么因为欧姆龙自家的上位机软件、触摸屏、组态软件全都原生支持HostLink你只要把参数和帧格式写对剩下的活它自己会干。Modbus-RTU在这类PLC上要用RS-422/485口做从站模式是跟第三方设备比如变频器、温控表、仪表通信时的通用语言。FINS则是在网口时代真正发挥威力CJ1W-EIP21、NJ/NX的EtherNet/IP端口上都能跑FINS/UDP和FINS/TCP尤其是FINS/TCP带确认机制在工业环境里可靠性比UDP高不少。我自己习惯用一张表归纳选型思路供参考通信场景推荐协议物理接口备注上位机/触摸屏连CP1H/CJ1MHostLinkRS-232C/422帧格式固定FCS校验要点比较多第三方仪表/变频器连欧姆龙PLCModbus-RTURS-422/485从站地址映射要查手册欧姆龙PLC之间网口通信FINS/UDP或FINS/TCP以太网无连接用UDP可靠性优先用TCP欧姆龙PLC与PC上位机通信FINS/TCP或HostLink以太网或串口FINS/TCP推荐带命令确认自定义协议对接无协议通信RS-232C/422一个字节一个字节收发这张表不是万能的但能帮你把思路理清楚。下面我逐一把里面最核心的几个协议讲透特别是那些手册里写得很含蓄、实际用起来特别容易掉坑的地方。2. 逐字节拆解HostLink帧结构里面藏着哪些坑HostLink协议说穿了就是欧姆龙串口时代的“通用语”。上位机发送一个以帧头开始的ASCII命令PLC收到后执行并返回响应。命令格式大致是设备号 命令码 正文 FCS *CR以读IR/SR继电器区数据为例命令码是“RR”后面跟四位十六进制起始地址和四位十六进制长度。一帧完整的读命令大概是这个鬼样子00RR00010002 FCS *CRFCS校验是我觉得最容易做错的地方。FCS的计算方法是从帧头“”之后到FCS之前的所有字符按ASCII码做异或结果转成两位十六进制ASCII大写字符。很多新手会犯一个错误把地址算成了16进制数位但忘了对应ASCII码。比如地址0001里的字符“0”“0”“0”“1”参与校验的是这4个字符的ASCII码0x30、0x30、0x30、0x31而不是数值0和1。响应帧一般长这样00RR 响应数据 FCS *CR正常响应里命令码会原样返回数据部分是一串十六进制ASCII。异常时PLC会返回以“F”开头的命令码后面跟着两位错误码比如“F4”表示FCS错误、“F5”表示格式错误、“F6”表示帧长度错误。把错误码记熟能省很多排查时间我后面常见问题部分再细说。继续说地址规则。IR/SR区也就是CIO区的HostLink地址是四位十六进制从0000到6143对应实际IO通道。DM区是独立的四个十六进制位。这里最容易弄混的是你在CX-P里看到的CIO区地址是十进制通道号比如CIO 100但HostLink帧里要用十六进制表示100就变成“0064”。漏了这个换算通信会一直返回地址超范围或者干脆没响应。再有一点HostLink命令一次能读的最大长度是有限制的别像我当年一样一条命令读400个字结果PLC返回一个错误码不跟你玩。单条命令读数据的上限跟PLC型号和内存区类型有关一般在几十到二百字左右超了就拆成多条发。拆条之后还要注意间隔时间别把PLC的串口缓冲区搞炸了。串口参数上HostLink默认波特率9600、8位数据、偶校验、1位停止位但是很多老设备并不一定是用默认值跑的所以实机调试前先用串口助手主动探一下参数省得后面抓瞎。实操上我建议新手不要上来就写整个上位机程序先用串口调试助手把手动发一帧的命令弄通。比如发“00RR00010001”算出FCS看PLC返回什么。这一个闭环过程走通了再往上写代码心里就有底了。因为HostLink是最容易用串口助手模拟联调的协议你要是连这一层都没走通直接上C#或Python写上位机遇到问题你会分不清是协议问题还是代码问题。3. FINS报文的门道从UDP到TCP一网打尽FINS协议是欧姆龙网口时代真正好玩的东西。它可以在UDP、TCP、甚至HostLink链路FINS over HostLink上传输很多NJ/NX工程师其实天天跟它打交道但未必意识到。FINS报文本身的格式很统一一帧FINS报文包括ICF、RSV、GCT、DNA、DA1、DA2、SNA、SA1、SA2、SID这些字节接着是命令码和参数。这堆缩写看着吓人其实拆开就明白前8个字节是寻址信息告诉报文从哪个网络节点来、到哪个网络节点去以及源和目的单元比如CPU单元还是通信单元。后面才是真正的命令。我最常用的FINS命令码有这么几个0101读出指定内存区数据Memory Area Read0102写入指定内存区数据Memory Area Write0103填充内存区Memory Area Fill2301读CPU单元状态Controller Status Read0401连接ConnectFINS/TCP建立连接时的第一条命令FINS/UDP比FINS/TCP简单因为UDP头里不需要建立连接直接发报文就行。但UDP实际用起来有一个很现实的问题丢包。工业现场电磁环境稍微差一点UDP报文可能就石沉大海了。FINS/UDP协议本身没有重传机制能不能重发、什么时候重发完全靠上位机自己看门狗实现。FINS/TCP则是先建立TCP连接端口号9600对就是那个标准的FINS/TCP端口然后第一条数据必须是“连接”命令格式为04 01 00 00 00 00对应命令码0401和空参数。PLC收到后回一条一样的命令TCP连接才算建立成功。之后才能发正常的读写信令。这里有个容易忽略的坑连接命令的SID服务标识符必须记录并递增每发一条读写命令SID加1PLC响应时会把SID原样带回。如果你发读写命令时SID始终是0虽然有的PLC也能正常响应但很多上位机库和PLC端会有超时管理长期用同一个SID会让PLC认为链路异常。FINS内存区代码也需要专门记一下内存区代码备注CIO区IR区0x30BCD/ 0x31二进制取决于你指定的是BCD还是二进制地址WR区写入区0x31很多CP系列不能直接访问HR区保持区0x32断电保持DM区0x82十六进制字地址EM区0x98需指定当前存储区号这里要特别注意DM区在FINS命令里的代码是0x82而不是0x32。当年我写第一个FINS读DM区程序照着网上某个博客抄了0x31结果死活读不出数据。后来对着官方命令格式查才发现DM区要带8位存储区指定。这种小细节手册里写得明明白白但就是没人翻。4. Sysmac Studio时代NJ/NX网口通信实操要点从NJ系列开始欧姆龙把编程环境换成了Sysmac Studio通信配置界面和CX-P完全不同。第一次接触NJ的人往往会懵一圈这软件里面没有“HostLink”这个选项了取而代之的是“EtherNet/IP”、“EtherCAT”、“FINS/TCP”这些现代词汇。其实FINS/TCP就在EtherNet/IP设置页面底层有个地方可以配置FINS/TCP服务是否启用、端口号是多少。默认情况下NJ系列的EtherNet/IP端口上FINS/TCP是启用的端口号就是9600。Sysmac Studio里的“网络配置”里你可以给PLC分配IP地址这个IP就是FINS/TCP通信的本地地址。如果你要跟另一个NJ通信对端设备设置里要填对端PLC的FINS节点号这个节点号默认等于IP地址最后一位。所以有时候你不能随便改PLC的IP最后一位改了要记得同步节点号设置否则FINS/TCP建连看上去能成功但命令会返回错误码0x1102目标节点不可到达这一下就能浪费你半小时。NJ和NX还有一个新东西叫变量映射。你可以通过Sysmac Studio把全局变量映射到具体地址比如%MW0000这样上位机用FINS命令访问地址区域就能读到变量值。很多上位机工程师喜欢直接用地址访问DM区但如果你面对的是个全符号编程的NJ程序DM区可能压根没被使用你读出来全是0而真正的数据都在被映射到地址的全局变量里。所以跟NJ打交道先问对方“变量映射表”在哪比自己去瞎撞高效得多。Sysmac Studio里还有一个特别容易触发的坑IP地址和节点号的联动。欧姆龙域名解析机制不太一样FINS协议里的DA1、SA1这些字节指的是“网络”、“节点”节点号在NJ里默认等于IP末位但你可以手动改。改完之后你查“端口设置”里的节点号显示的是对的但Sysmac Studio里如果没做“重传设置”或者重新下装配置实际运行的PLC固件里可能还是旧的。稳妥做法是改完IP之后把整个EtherNet/IP配置重新传一次再断电上电。动手写FINS/TCP客户端时有几个细节值得提。TCP连接建立后虽然不是严格必须但最好先发一条0401连接命令确认PLC正常响应再去发数据。很多第三方库比如HslCommunication、Kepware、Ignition里的欧姆龙驱动都封装好了自己用Socket写的话注意FINS/TCP报文里每个读写命令都带12字节的FINS帧头不是协议头然后才是ICF那一串。你可以在网上找协议文档但我建议还是直接参看官方《FINS命令参考手册》里的报文结构避免字节顺序搞错。5. Modbus-RTU这条路从站和主站都试一遍说到欧姆龙和第三方设备通信Modbus-RTU绝对是绕不开的口粮。CP1H/CJ1M的串口可以配置成Modbus-RTU从站NJ/NX的串口选件板也能做但在实际项目里欧姆龙PLC做Modbus主站去轮询仪表的情况远多于做从站。为什么因为欧姆龙本身是PLC你在产线里通常是让PLC去读取几十个温控表、电能表的数据而不是让上位机天天来问欧姆龙要数据。先讲从站模式。在CX-P的串口设置里把通信协议改成“Modbus-RTU”设置波特率、数据位、校验位然后给这个从站分配一个站号。这里有个容易忽略的地方欧姆龙不是把所有内存区都直接映射为Modbus地址的它提供一个“Modbus地址分配表”比如保持寄存器40001对应哪个CIO或DM区是跟PLC型号相关的。别想当然地以为40001一定对应DM0000很多时候它对应的是CIO区的一个约定偏移。实用做法是先按手册把映射表抄下来再通过串口助手发一条读命令验证。主站模式时原理就是要用CX-P的“协议宏”功能。协议宏听着高深本质就是让你像编剧本一样定义发送帧和接收帧的结构哪些字节固定、哪些字节从变量里取、收回来怎么解析。写之前一定先把对方的仪表通信协议手册拿到手里面会写清楚功能码、寄存器地址、寄存器数量、字节序。我见过太多人协议宏写好了但读回来的浮点数怎么也对不上——原因基本就是字节序没配对大端/小端搞反。Modbus-RTU的命令帧本身读保持寄存器是03功能码写单个寄存器是06写多个是10十六进制。帧格式从站地址 功能码 起始地址(2字节) 寄存器数量(2字节) CRC16(2字节)CRC16是Modbus特有的多项式0xA001低字节在前。你要是手写要注意有些库返回的CRC是反过来的跟Modbus标准比刚好高低字节互换联调时一验就能看出来。我排查CRC问题时常用的方法是串口助手里把一帧正常通信的报文全部抓下来包括CRC那两字节然后用Python或者C代码先复算一遍对比到底是谁的端序反了。还有一个经验Modbus-RTU在485总线上做轮询时两条命令之间的间隔时间不能太短。很多仪表手册要求主站至少等3.5个字符时间才能发下一条但如果你的轮询周期是50ms批量读10台设备整个周期就是500ms这还不算从站响应超时。实际项目里做数据刷新率预算时一定要把超时时间算进去不然界面上的数据跟蜗牛一样慢。6. 常见问题与排查技巧实录那些年我踩过的坑很多人学通信最大的阻力其实不是协议文档看不懂而是出了问题不知道从哪查。我把自己做过欧姆龙通信项目里遇到频率最高的几类问题列出来顺手整理一个速查表故障现象常见原因排查方向串口通信完全无响应波特率/校验位不一致先用串口助手抓包确认参数HostLink返回F4错误码FCS计算错误重新按ASCII逐字节异或注意起始字符HostLink返回F5错误码帧格式错误检查地址、命令码字符长度FINS/UDP丢包严重网络环境干扰或未做重发机制改用FINS/TCP或上位机加重发逻辑FINS/TCP建连成功但读写报错节点号、IP地址设置不一致核对PLC端节点号和IP末位Modbus从站读不到数据地址映射表没查对查对应手册的Modbus地址映射浮点数数值对不上字节序不对确认大端/小端、字序PLC错误灯频繁闪烁串口参数被反复错误连接上位机连接超时后不断重连加延时这里展开讲两个印象最深的坑。第一个是USB驱动和串口识别。用CP1H的USB口连上CX-P编程时通信很顺但很多人想直接用USB口跑HostLink结果发现怎么都不通然后怀疑协议写错了。实际上CP1H的USB口是编程口默认并不走HostLink它需要通过CX-P的“PLC系统”设置把USB口模式改成HostLink或者FINS而且改了之后要重新上电。我当年花了一下午抓帧、改FCS最后发现只是没改USB口工作模式。后来学乖了任何调试第一步永远是看“CPU单元上的通信口设置”和“实际用的物理口是不是同一个”。第二个是直连网线的IP设置。PC和NJ/NX直连时PC网卡IP和PLC IP必须在同一网段这个大家都会。但很多人忽略了一个问题NJ默认IP是192.168.250.1不同型号可能不一样但PC网卡如果是自动获取会得到一个169.254开头的APIPA地址跟PLC不在同一网段自然连不上。手动给PC网卡设一个静态IP比如192.168.250.2子网掩码255.255.255.0问题立刻消失。别问我为什么反复提到这个因为我真的见过工程师在新电脑上装好软件后折腾一下午都没发现网卡是自动获取的。还有一个排查FINS/TCP连接的小技巧用Wireshark抓包。抓包不是只看数据而是看TCP握手是否正常、端口是不是9600、应用层报文里ICF有没有回显。有时候PLC端防火墙、路由器NAT、交换机VLAN配置都会影响FINS/TCP抓包能帮你快速确认问题是出在网络层还是应用层。在工业现场临时拉着笔记本直连PLC抓包比在远程服务器上瞎猜强百倍。最后聊一个老生常谈的问题**通信不稳定到底是不是波特率不够**我见过很多人大幅提高波特率来解决刷新慢的问题结果丢帧、错字全来了。工业环境下的串口通信稳定比速度重要得多。9600波特率看起来土但它抗干扰能力和布线要求都相对低115200在短距离、双绞屏蔽线、规范接地的情况下才能稳定跑。如果一定要高波特率优先用RS-422全双工差分信号其次是RS-485别抱着RS-232不放。7. 最后的几句实在话说句实话搞欧姆龙PLC通信一年多以后我最深的体会是协议本身都不难难的是你永远不知道哪些“隐含假设”没被满足。HostLink的FCS、FINS的节点号、Modbus的映射表这些知识手册上都有但只有你真正在项目里踩过一次才会刻进脑子里。给还在学习路上的朋友几个建议第一不管你用什么协议先从串口助手或者Wireshark把原始报文看清楚搞清楚“发出去的是什么、收回来的是什么”再考虑写代码第二通信联调时把超时时间定得宽松一点宁愿多等100毫秒也不要在临界值上赌第三遇到问题先怀疑自己的参数配置再怀疑PLC固件最后才怀疑外部设备大部分坑都出在第一层。我到现在还时不时翻一下欧姆龙官方手册里的命令表因为不同系列、不同固件版本地址映射和响应码会有细微差异。通信这行没有“一劳永逸”的配置只有不停核对和验证的习惯。希望我这篇踩坑记录能帮你少走几步弯路哪怕只是省下一个下午的时间也算值了。