尧图精选

欧姆龙PLC通信协议全解析:从Host Link到FINS/TCP实战指南

🕒 发布时间:2026/9/28 1:59:41 📁 来源:尧图网络
干工控这行尤其是常跟欧姆龙PLC打交道的人恐怕都听过一句吐槽“欧姆龙的软件挺好用但它的通信协议是真的抽象。”我之前也是这么认为的从第一次拿Host Link命令去读一个DM区数据到后来用FINS/TCP从上位机批量读写数据中间踩过的坑能装满两个工具箱。可等我真正把欧姆龙这套通信体系理顺之后才发现它其实一点不乱反而设计得相当有层次只是官方文档习惯把“能做什么”和“怎么用”分开写入门的人很容易被一串串术语绕晕。这篇东西就是我自己的一个复盘总结。不绕弯子直接讲清楚欧姆龙PLC通信协议里那些“一看就懂、一用就错”的点包括串口、以太网、FINS协议、485总线和第三方设备通信每一步我都会说为什么这么配、实际调试中会碰到什么问题。不管你是刚上手CP1系列、还在和CX-Programmer搏斗还是已经在用Sysmac Studio调NJ/NX、需要和变频器或温控表做数据交换这篇文章应该都能帮你少走点弯路。1. 先搞懂欧姆龙PLC通信协议有哪些层很多初学者第一次接触欧姆龙通信都是从一个很具体的需求开始的电脑怎么跟PLC交换数据或者触摸屏怎么读PLC里的D区然后就看到文档里出现Host Link、FINS、Modbus-RTU、EtherNet/IP、EtherCAT一堆名词瞬间就懵了。其实欧姆龙的通信体系从我自己的理解来看可以分成三“层”来记串口时代的协议、以太网时代的协议、以及新一代总线级的协议。这三层不是互相替代的关系而是根据硬件平台和应用场景并存的。搞懂这三层后面很多问题都能对号入座。1.1 串口通信Host Link、FINS串行和编程口欧姆龙早期PLCC系列、CPM系列包括后来的CP1系列最常用的串口通信就是Host Link协议。这个协议本质上是欧姆龙自己定义的一套ASCII字符命令通过RS-232C或RS-485口以上位机发命令、PLC回应答的方式工作。Host Link的特点非常“复古”一条指令就是一串可见字符比如以“”开头接着是两位十六进制的单元号然后是命令代码最后是校验码。它不需要安装驱动任何一个串口调试助手都能发这也是为什么很多老工程师到现在还在用Host Link做快速测试。但也正因为它是字符协议传输效率不算高一条命令只能操作一小段数据区域不适合大批量实时读写。除了Host Link欧姆龙还支持通过串口跑FINS协议这就是所谓的“FINS串行”。FINSFactory Interface Network Service是欧姆龙真正意义上的应用层通信协议它不关心底层是串口、以太网还是SYSMAC LINK它定义的是一套“内存区读写”的抽象命令。换句话说Host Link是“字符命令”FINS是“二进制帧命令”而欧姆龙更推荐的是FINS因为它能统一不同物理链路上的通信方式。还有个概念叫“编程口”。很多用户用USB转232线插到CP1H前面的外设口下载程序用的其实就是FINS协议只不过软件CX-Programmer自动帮你把协议封装好了。这也是为什么有时候你用一个第三方串口助手去“模仿”CX-P发命令却怎么也连不上——因为默认外设口的协议选择、波特率、数据格式跟通信口不一定一样。1.2 以太网通信FINS/TCP和FINS/UDP到了以太网时代欧姆龙把FINS协议打包进了TCP/IP和UDP/IP里就成了大家常说的FINS/TCP和FINS/UDP。这两种方式最大的优势是上位机可以直接通过网络读写PLC的I/O、DM区、CIO区不需要像串口那样独占物理链路而且可以同时和多台PLC通信。FINS/TCP和FINS/UDP的关系有点像打电话和发传真的区别。FINS/TCP要先建立一个TCP连接保证报文有序到达适合需要可靠传输的场景FINS/UDP则是无连接的数据报速度快一点但报文可能会丢需要在应用层自己做重试。欧姆龙的默认FINS端口是9600不管TCP还是UDP都是这个端口这也是排查连接问题时要记住的一个数字。在使用FINS/TCP时有一个非常容易忽略的点你不仅要设置PLC的IP地址还要设置PLC的“FINS节点号”。节点号是欧姆龙FINS编址体系里的一个参数范围是1到254它跟IP地址不是一回事。如果上位机发的报文里目标节点号跟PLC实际设置的节点号对不上就算网络是通的PLC也不会理你。这个坑我后面细说。1.3 新一代平台EtherCAT、EtherNet/IP和Sysmac Studio如果你用的是欧姆龙最新的NJ/NX系列会发现通信体系又不一样了。NJ/NX系列更依赖Sysmac Studio进行配置运动控制走EtherCAT设备层通信走EtherNet/IP同时也保留了对FINS命令的支持。EtherCAT是一种实时工业以太网总线适合伺服轴控制和高同步性场景EtherNet/IP则是基于CIP协议的标准工业以太网主要用于PLC与PLC、PLC与远程IO之间的数据交换。对刚接触Sysmac Studio的人来说最困惑的不是协议本身而是“配置方式从‘编程’变成了‘组态’”——你要先在软件里建好网络拓扑给每个从站分配节点地址然后再通过“变量映射”的方式关联数据。跟CP系列的“直接在D区里读写地址”完全是两套思路。不过对于大多数做上位机、触摸屏对接的开发者来说最核心的仍然是FINS协议。就算你用的是最新款NJ系列只要它支持FINS命令你的上位机程序逻辑和之前写的并没有本质区别。所以这篇文章后面会以FINS为主线展开。2. 实测电脑和PLC之间的串口通信怎么一步步调通串口通信看着简单实际上是最容易翻车的环节。尤其是现在笔记本电脑基本没有原生串口大家只能用USB转RS232或者USB转RS485线这中间光是驱动和线序就能卡住半天。我自己早期就干过一件蠢事拿着一根USB转TTL的线去连CP1W-CIF01的RS422口结果收发完全没反应最后才发现是电平标准根本不匹配。2.1 硬件连接先确认电平标准再谈协议欧姆龙CP1系列PLC的串口主要有两种物理形式一种是CPU单元自带的RS-232C口常见于CP1H、CP1L等型号另一种是通过通信板扩展出来的RS-422/485口比如CP1W-CIF11、CP1W-CIF12。这两种口的引脚定义不一样接线方法也完全不同。如果是RS-232C口和PC侧通讯通常需要“交叉线”PLC的发送接PC的接收PLC的接收接PC的发送地线必须共地。用USB转232线时原理也是一样只不过连接器往往已经内置了转换逻辑你只要把DB9公头跟PLC对插时注意对应引脚即可。这里我要反复强调一句地线一定要接、要接、要接。不共地的串口通信经常出现“偶尔能通一下但数据全是乱码”的诡异现象拿万用表量电压又觉得哪哪都对其实就是地电位差在作怪。如果是RS-485口两线制A、B就简单很多只要A接A、B接B即可。但485总线是半双工而且需要终端电阻匹配。长距离多站点连接时总线两端还需要加终端电阻通常是120欧姆否则波形反射会造成数据帧错误。接好线之后先用设备管理器确认USB转串口线识别出的COM口号用串口调试助手打开这个COM口时别急着发命令先把参数和PLC侧设置改成一致这是下一节的重点。2.2 CX-Programmer里的通信参数设置欧姆龙PLC的串口通信参数是在PLC设置里配置的。在CX-Programmer中双击左侧工程树里的“设置”打开“串口1”或“串口2”选项卡你会看到协议、波特率、数据位、停止位、校验位这几个选项。以常用设置为例协议选“Host Link”波特率根据设备和线缆质量设为9600或19200数据位8位停止位1位偶校验Even单元号设为0。这几个参数看似平平无奇但任何一个跟对端不一致通信就起不来。很多人在CX-P里下载设置时忘记把PLC切换到“编程模式”导致设置写入失败这也是老生常谈的坑。需要注意PLC设置修改后并不会立即生效通常要断电重启或者通过CX-P的“复位”操作让新参数加载。而且下载设置前最好先把PLC拨码开关调到编程模式等设置保存完再切回运行模式。否则在运行模式下写入通信设置轻则写入失败重则通信过程中PLC处在异常状态现场就被你搞停机了。2.3 用串口助手快速验证通信链路配置完成后可以先不急着写上位机程序用串口调试助手发一条Host Link命令测试下链路是否通。比如读DM0000的一个字命令格式大致是00RD00000001FCS。这里的“00”是起始符加单元号“RD”是读命令“0000”是起始地址“0001”是读取字数“FCS”是两位校验码。这个FCS校验码需要自己计算是把之后的每个字符的ASCII码做异或运算最后转成两位十六进制字符加在命令尾部。很多第一次接触的人都会在这里卡住。我的小技巧是手头常备一个小的计算器工具或者在电脑上写一个几行的FCS计算函数不要手动算太容易错。如果PLC正常响应串口助手的接收区会出现类似“00RD0000...”的回显格式。如果没反应先把PLC的通信指示灯和串口助手的发送计数对比一下发送计数在涨、但没有任何接收数据那基本可以判定是接线、波特率、校验位这三个问题之一。按这个顺序排查十有八九能找到原因。3. FINS协议拆解从报文结构到上位机实例如果说Host Link是“小打小闹”那FINS就是真正能干大事的协议。它能读写几乎所有内存区包括CIO、WR、DM、EM甚至定时器计数器的PV值和状态位而且报文结构非常规整用任意语言都能实现。我见过不少项目上位机用C#或者Python直接往PLC发FINS帧效果比用组态软件还灵活。3.1 FINS/TCP帧到底长什么样FINS/TCP的报文分两层首先是TCP报文头然后是FINS报文。TCP报文头是固定的10个字节前4个字节是ASCII字符“FINS”接着4个字节是报文长度这里的长度是从“命令”字段开始到整个报文体结束的字节数再接着2个字节是命令码和错误码的相关字段。后面才是真正的FINS正文。FINS正文则有固定的12字节头加上命令代码和参数。这12字节头里最重要的是目标网络号、目标节点号、目标单元号、源网络号、源节点号、源单元号以及服务ID。很多人第一次看官方手册时会被这一堆“NA、DA、SA”搞晕但其实只需要抓住一点你要告诉PLC“我是谁、我要发给谁”。举个例子假设PLC的IP地址是192.168.1.20FINS节点号设置为1上位机节点号设置为0那么读取D100开始的10个字完整的FINS请求帧大致会包含以下内容目标网络号00、目标节点01、目标单元00、源网络号00、源节点00、源单元00服务ID随意比如AA命令码0101内存区读取内存区代码82DM区起始字地址0064位地址00读取字数000A。把这串十六进制组出来再加上前面TCP头就是一条可以发送的FINS报文。3.2 用Python做最简单的FINS/UDP读取对于上位机快速验证我最推荐用FINS/UDP而不是TCP原因很简单UDP不需要建连和断连构造一个socket就能发调试时方便。下面这段Python代码就是我当时用来验证FINS读取D区的最小示例import socket plc_ip 192.168.1.20 plc_port 9600 # FINS 报文头目标节点1源节点0服务ID 0xAA fins_header bytes.fromhex(80 00 02 00 00 01 00 00 00 00 00 AA) # 命令: 0101 读内存区区域82(DM)字地址0064位地址00读取字数000A fins_cmd bytes.fromhex(01 01 82 00 64 00 00 00 0A) # FINS/UDP 数据报 FINS标签头(4字节) 长度(4字节) FINS报文 packet bFINS (len(fins_header fins_cmd)).to_bytes(4, big) fins_header fins_cmd sock socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.settimeout(1) sock.sendto(packet, (plc_ip, plc_port)) data, addr sock.recvfrom(1024) print(data.hex())这段代码的关键在于两点字节顺序都是大端也就是高位字节在前长度字段统计的是FINS报文的字节数而不是整个packet的长度。我之前就因为在长度字段上多加了4个字节导致PLC根本没法解析这条报文一直以为是节点号不对。收到响应后数据区的前一部分是命令码和结束码0表示正常若结束码非0PLC会告诉你具体是地址非法还是格式错误。需要注意的是读出来的数据每个字是2字节而且欧姆龙的高位字节在前所以如果你要拼成16位有符号整数得先把高字节左移8位再加上低字节。3.3 那些“看起来对不上”的地址映射FINS的地址映射是很多人的噩梦。先说D区FINS报文里的“字地址”是从0开始的而且它跟你在CX-Programmer里看到的梯形图地址DM0000是对应的。比如D100报文里要写十六进制0064只要你把十进制100转成十六进制就行这个还算友好。但CIO区就没这么直觉了。CIO区的地址在FINS里要用“区代码字地址位地址”来表示比如CIO0.00对应区代码是0x30字地址是0位地址是0。而W区内部工作区的区代码是0x31H区是0x32S区是0x33。用的时候拿不准就去翻官方“FINS命令参考”里的内存区代码表不要凭感觉猜。真正让人抓狂的是位地址。读取字数据时位地址填0没错但有些协议文档会告诉你如果你要读写某个位比如D100.01报文里的地址就不是单纯的字地址位地址而是要把字地址和位地址拼接后作为一个3字节字段发送。这点在写程序时非常容易漏我的习惯是封装一个“FinsAddress”类把内存区代码、字地址、位地址拆开管理绝不直接拼硬编码。3.4 FINS/TCP连接时最容易踩的“节点号”坑前面提到上位机通过FINS/TCP访问PLC时除了IP地址还必须确保FINS报文里的目标节点号与PLC的FINS节点号一致。在CX-Programmer里设置以太网或通信单元时会有一个“FINS节点号”选项一般默认是1或根据单元号自动分配。很多人在做上位机时只关心IP能不能ping通完全不看节点号结果TCP三次握手都能成功但PLC就是不回业务报文。我当时的解决方案是先打开CX-P的在线监控查看PLC分配到的实际节点号有条件的话直接在PLC设置里把节点号固定下来比如固定成1。上位机程序里也写死1测试通过后再改成可配置的。养成“工程项目里所有通信参数都是白纸黑字写在配置表上”的习惯能省掉很多后期排查时间。4. 用485和第三方设备通信变频器、仪表和温控表欧姆龙PLC不会只跟自家设备通信。现场变频器可能是台达的、汇川的温控表可能是欧姆龙自己的E5CC也可能是别的牌子。这些设备大多支持Modbus-RTU所以欧姆龙PLC与它们通信的实质就是把PLC当作Modbus主站去轮询各个从站设备。4.1 RS-485总线布线上的坑先说物理层。RS-485是差动信号A、B两根线之间的电压差决定逻辑状态理论上抗干扰能力很强但实际现场总会有变频器、电机这类大功率设备一旦布线不走线槽、屏蔽层不接地通信就会出现随机性丢帧。我在现场踩过最典型的坑是“屏蔽层两端都接地”。变频器启动瞬间地电位瞬间抬升屏蔽层反而成了干扰耦合通道通信直接罢工。后来按规范改成单端接地设备端屏蔽层悬空问题立刻消失。另外一个坑是A、B线接反虽然有些设备能自动识别但很多老设备不行接反的结果是“发命令没响应、示波器看波形又好像有数据”。所以接线后第一件事就是确认A/B定义千万不要默认红色就是A。4.2 欧姆龙PLC做Modbus-RTU主站欧姆龙CP系列PLC要做Modbus主站不同型号支持情况不一样。部分型号比如配备串行通信单元后支持“Modbus-RTU简易主站”功能也有的需要你用通信协议宏或者通过梯形图指令手动发送Modbus报文。如果是CP1H使用串口通信板并且软件版本支持的情况下可以用Modbus-RTU简易主站功能把串口设为“Modbus RTU master”后在DM区分配通信参数即可。这个通信参数区里通常要填的内容包括从站地址1到247、功能码比如03读保持寄存器、06写单个寄存器、10h写多个寄存器、起始寄存器地址、寄存器数量、数据存放区等。看起来和直接用自由协议差不多但好处是欧姆龙已经把CRC校验和报文封装做好了你只需在触发位给一个上升沿通信结果会自动写到状态区。这里我要强烈建议触发位给一个脉冲比如用符号的微分指令不要一直置ON。如果连续置ON有些固件版本会不停重复发送请求变频器或者仪表会被你的PLC轮询请求轰炸表现就是某个从站设备偶发无响应甚至报警。我见过有人把这个问题归结为“变频器抗干扰差”其实根本不是就是PLC侧触发方式不对。4.3 仪表通信欧姆龙温控表E5CC为例欧姆龙的E5CC等温控表通信无非两种模式CompoWay/F和Modbus-RTU。温控表默认可能是CompoWay/F协议需要先用表上的按键参数把通信协议切到Modbus-RTU再设置从站地址、波特率、校验位这些参数。跟温控表通信时寄存器地址不等于面板上显示的参数号比如你想修改设定值SV面板上显示的是“SP”但Modbus寄存器里它可能对应地址0001或0000具体要看仪表手册的“通信寄存器表”。这个坑我印象太深了当年把一个温度设定值写到了错误的寄存器里导致现场设备温度直接冲高还好及时发现没有出事故。现在我的规矩是任何Modbus寄存器地址都要以官方通信手册为准接线前先打印一页寄存器对照表贴在电柜门上。4.4 现场485通信不顺畅的排查金字塔如果485通信调不通别慌按顺序排查先看物理层用示波器或万用表确认A/B电压最好是空闲时A比B高2到5伏再确认从站设备地址、波特率、校验位和PLC配置完全一致然后看报文层把串口调试助手并联到总线上抓包看看PLC发出的帧长什么样子从站有没有应答帧最后才去怀疑上位机软件逻辑和CRC计算。我很少看到CRC算错导致完全无法通信的情况因为大多数库函数都会处理好。反而最常见的是波特率不一致导致的乱码比如PLC设为19200温控表却是9600你一抓包就会发现PLC发出的字节流“看起来是正常的但就是没有设备应答”。这种问题用串口助手一抓一个准比盲目改参数快得多。5. 那些年踩过的坑欧姆龙通信故障速查表每个项目做完回头总结一下踩过的坑比看十遍说明书都有用。我把这几年跟欧姆龙PLC通信相关的典型问题整理成了一张速查表不一定能覆盖所有情况但能覆盖我遇到过的大部分问题。排查时按图索骥效率会高很多。现象最可能原因解决方向串口通信完全无响应接线错误或地线未共地用万用表逐针确认定义接好地线串口偶尔通、数据乱码波特率或校验位不一致统一检查PLC设置和上位机参数上位机能连上但FINS无应答FINS节点号对不上确认PLC节点号并固定配置FINS命令返回结束码非0地址越界或内存区代码错误对照FINS命令手册检查报文485只在上电瞬间通一次屏蔽层接地方式错误改为单端接地并检查终端电阻Modbus主站反复发请求触发位一直ON用微分指令做单次触发温控表SV写不进去寄存器地址不对或仪表的通信协议不对查仪表手册确认协议和寄存器表多站点485轮询某个站点无响应站地址重复或总线太长挨个站点单独测试检查布线分支5.1 换软件平台后的新坑Sysmac Studio和NJ/NX系列如果你从CX-Programmer转到Sysmac Studio最大的变化不是指令而是通信配置的入口完全不同。在Sysmac Studio里PLC的IP地址、节点号、EtherNet/IP连接、EtherCAT从站分配全都在“配置和设置”里完成而不是在梯形图里操作。我初次用NJ系列做EtherCAT轴控时犯过一个低级错误在Sysmac Studio里更新了硬件配置但忘记编译下载结果轴参数和通信配置始终没生效现场伺服一个脉冲都不动。后来才明白Sysmac Studio的配置变更必须“离线编译——在线连接——下载——切换运行模式”四步走完才算数尤其是EtherCAT的拓扑下载前一定要先做总线扫描。另外NJ/NX系列的FINS命令虽然和CP系列差不多但内存区映射方式不同NJ里你看到的变量变量名如A、B、C是通过系统变量和I/O映射表映射到具体地址的不像CP系列直接在D区里看得到。上位机想读NJ里的一个变量要么把它映射到一个固定的地址区要么用符号数据通信比如Symbolic Addressing否则你的FINS报文根本不知道要读哪个位置。5.2 我的三个“保命习惯”建议你也养成第一个习惯是通信调试之前先把所有硬件的通信参数做成一张表贴在办公室或者保存在项目文件夹里。表里至少包含设备名称、接口类型、协议、IP/节点号、波特率、校验位、停止位、寄存器地址说明。别嫌麻烦现场调试时这张表比任何文档都好用。第二个习惯是上位机代码里把所有通信地址、参数做成配置文件不要写死在代码里。因为现场设备可能随时调整从站地址或者PLC节点号如果每改一次都要重新编译上位机你会在现场被折腾到怀疑人生。配置文件解析虽然多写几行代码但后期收益巨大。第三个习惯也是我最想强调的通信异常时先自己抓包再问别人。欧姆龙的CX-Programmer里有数据跟踪功能Sysmac Studio里有总线诊断串口端可以并联一个485转USB模块给电脑看报文。很多问题你自己抓一次包就能定位根本不需要打电话给技术支持。5.3 把通信问题当“时序问题”看最后分享一个我在项目里总结出来的视角PLC通信里的大部分疑难杂症其实都是时序问题不只是协议问题。比如你用Host Link读了D区数据但PLC程序里同一时间正在写D区读到的数据就会“忽对忽错”又比如你的上位机每50毫秒轮询一次PLC而PLC的扫描周期刚好是50毫秒就会时不时出现超时再比如Modbus主站触发位没有做微分处理导致请求帧连发从站缓冲队列直接爆掉。所以当通信“偶尔正常、偶尔不正常”的时候不要死磕协议格式先描一遍双方的时间轴PLC什么时候写数据上位机什么时候读数据通信指令占用了多久。很多时候你只要把轮询周期从100毫秒改成150毫秒或者把数据交换区独立出来问题就不治而愈了。欧姆龙的通信协议本身确实有些“刁钻”的地方但只要把物理层、报文层、时序逻辑这三层分开看每个问题都能一步步缩小范围最后定位到那一两个真正的原因。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →