拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

欧姆龙PLC上位机开发:FINS命令在HostLink协议下的应用与调试

欧姆龙PLC上位机开发:FINS命令在HostLink协议下的应用与调试

做欧姆龙PLC上位机开发的朋友,对HostLink协议应该不陌生。前几篇把HostLink的命令帧格式、FCS校验、传统读写命令(比如RD、WR这些)都聊了一遍,这篇集中讲FINS命令在HostLink链路上的进阶应用和调试方法。FINS之所以值得单独开一篇,是因为它在欧姆龙整个产品线里是统一的信息网络指令集,一套指令既能跑在HostLink串口上,也能跑在以太网FINS/TCP上,上位机代码写一次就能跨平台复用,不用为不同连接方式维护多套逻辑。

这篇适合正在做设备数据采集、视觉系统对接、上位机参数下发,或者被现场通讯问题卡住的工程师。我会从FINS帧的每个字节讲起,然后给几个能直接复制到串口助手里的完整报文实例,最后把调试方法和常见错误码整理成速查表。哪怕你之前没接触过FINS,跟着手敲一遍命令,也能把PLC里的数据读出来。

1. FINS命令的完整帧结构与字节逐项拆解

1.1 HostLink帧里如何承载FINS命令

先回顾一下HostLink的传统命令格式。比如读DM区,用的是两位大写字母的命令码加参数的组合:

@00RD0000000102*CR

其中@是帧起始符,00是单元号,RD是读DM区命令,后面跟参数,02是FCS校验,*CR是结束符。这种命令格式简单,但有个问题:RD只能操作固定几个区,想读CIO区、HR区、定时器当前值,就得换别的命令码。功能稍微复杂一点,比如同时读多个不同类型的区,或者做条件写入,传统命令就有点力不从心了。

FINS命令的长处在于,它不区分HostLink、Controller Link还是以太网,命令体完全一样。通过HostLink发送FINS命令时,报文格式变成这样:

@00FCS00 + FINS命令文本 + FCS + *CR

第一个00还是单元号,FCS是HostLink中专门承载FINS指令的命令标记,紧接着的00是目标节点号(在HostLink直连场景下固定填00,表示数据发给串口上直接连着的这台PLC),中间是FINS命令体(每字节转换成两位ASCII十六进制字符),末尾两位是FCS校验,*CR收尾。刚接触的人容易把开头的FCS和末尾的FCS校验搞混,这俩不是一回事:开头是三个字母FCS,末尾是两个十六进制字符的校验值。

1.2 FINS帧头逐字节说明及SA1详解

FINS命令体由10字节帧头加命令码加参数组成。帧头10字节是固定的,但很多人不知道怎么填,尤其是SA1,后台经常有人问“欧姆龙FINS里的SA1到底是什么意思”。这里把所有字节一次讲清楚:

字节名称含义常见取值
第1字节ICF信息控制字段0x80表示需要响应,bit6为0表示命令帧
第2字节RSV保留固定0x00
第3字节GCT网关计数0x02(允许网关转发两次)
第4字节DNA目标网络地址0x00表示本地网络
第5字节DA1目标节点号HostLink下填0x00,指向本机PLC
第6字节DA2目标单元号0x00表示CPU单元
第7字节SNA源网络地址0x00表示本机网络
第8字节SA1源节点号上位机节点号,可自定义,建议1~254
第9字节SA2源单元号0x00表示CPU单元
第10字节SID服务标识符0x00~0xFF,用来匹配请求和响应

SA1就是“发送这条FINS命令的设备的节点号”。打个比方,DNA和DA1是收件人的地址,SNA和SA1是寄件人的地址。PLC返回的响应帧里,SNA和SA1会被交换,上位机拿到响应后,靠SA1就能知道这条响应是对应自己哪一次请求的。在实际项目里,如果有多台上位机同时连一条HostLink链路,每台机器必须设置不同的SA1,否则PLC返回的响应会被张冠李戴。单机调试时填0x00或0x01都能跑通,但工程上建议固定一个唯一值,方便以后扩展。

还有一个容易混淆的概念:HostLink帧里的单元号(@后面的两位)和FINS帧里的目标节点号DA1。单元号是串口物理链路上的站号,取决于PLC串口设置里的“单元号”参数,常见是00;DA1是FINS网络层的目标节点,HostLink直连场景下填00就能命中PLC。两层职责不同,但很多老工程师在填参数时会把它们当成一回事,抓包时发现报文发出去没响应,先查这两个值。

1.3 内存区代码与地址计算

FINS命令参数里最关键的是内存区代码和地址。以CP1H、CJ2M这些常用机型为例,主要的内存区代码如下:

内存区FINS代码(十六进制)说明
DM区0x80数据寄存器,字访问
CIO区0xB0外部输入输出继电器区
WR区0xB1内部工作位区
HR区0xB2保持继电器区
定时器当前值0xBE字访问
计数器当前值0xBF字访问
定时器完成标志0xBC位访问
计数器完成标志0xBD位访问

地址计算有一个关键规则:FINS命令里填的地址,对字区来说不是直接填“第几个字”,而是填“第几个字节地址”,即字地址乘以2。比如要访问DM100,先换算:100 × 2 = 200 = 0x00C8,命令里填00 C8。同理,CIO100换算后也是0x00C8。如果访问的是CIO区的某个位,地址等于字地址乘16加位号,比如CIO100.05,就是100 × 16 + 5 = 1605 = 0x0645。

这个换算规则是初学者最容易栽跟头的地方。我第一次用FINS读DM区时,直接把0x0100填进地址字段,结果PLC返回地址错误,后来翻手册才发现是字节地址和字地址的差异。要记住:所有字区统一按“字地址×2”换算,没有例外。

2. FINS命令进阶应用:内存读写实例

2.1 内存区读0101与写0102的帧格式

FINS最常用的两条命令是内存区读(0101)和内存区写(0102)。命令格式如下:

读命令:0101 + 内存区代码(2字节) + 起始地址(2字节) + 数据长度(2字节)

数据长度按字算。比如读DM100这一字,长度就是0001;读连续4个字,长度就是0004。

写命令:0102 + 内存区代码(2字节) + 起始地址(2字节) + 数据长度(2字节) + 写入数据(长度×2字节)

写入数据时,每个字低字节在前、高字节在后。比如往DM100写入0x1234,数据字段是34 12,不是12 34。这个顺序问题导致过不少数据错乱事故,写完先读回来验证一下最稳妥。

响应帧的格式是:命令码 + 完成码(2字节) + 读取/写入的数据。完成码0x0000表示正常;非0值表示出错,具体含义后面第四章会列速查表。

2.2 实例一:用串口助手读取DM100连续两个字

假设PLC是CP1H,串口单元号00,DM100和DM101里存放着设备运行参数。现在要读取这两个字,FINS命令体如下:

80 00 02 00 00 00 00 01 00 00 01 01 00 80 00 C8 00 02

逐个字节拆开看:前10字节是帧头,ICF=80(需要响应),GCT=02,DNA=00,DA1=00,DA2=00,SNA=00,SA1=01,SA2=00,SID=00。然后是命令码0101,内存区代码0080(DM区),起始地址00C8(DM100),数据长度0002。

把命令体转成ASCII十六进制字符串,并在HostLink帧里加目标节点号00,完整发送报文是:

@00FCS00800002000000000100000101008000C80002XX*

其中XX是FCS校验值,后面第三章会讲计算方法。用串口助手以十六进制发送时,实际发送的是这串ASCII字符对应的字节流:40 30 30 46 43 53 30 30 38 30 30 30 32 30 30 30 30 30 30 30 30 30 31 30 30 30 30 30 31 30 31 30 30 38 30 30 30 43 38 30 30 30 32 ...。注意这里“80”是两个字符“8”和“0”,对应ASCII值0x38和0x30,不要直接发一个字节0x80。

正常的响应帧类似:

80 00 02 00 00 00 00 00 01 00 01 01 00 00 34 12 56 78

这里完成码是0000,后面跟着4字节数据。如果DM100=0x1234、DM101=0x5678,返回顺序就是34 12 56 78。把低字节和高字节拼回来,就得到实际数值。

2.3 实例二:向上位机同步CIO区状态并写入参数

实际项目里更常见的是周期轮询,比如每100ms读一次CIO区20个输入点状态,同时根据工单信息往HR区写入配方参数。FINS命令可以轮询读取CIO区。CIO区的代码是0xB0,假如CIO0这个字的bit状态要上传,起始地址按字地址0×2=0,数据长度0001,命令体就是:

80 00 02 00 00 00 00 01 00 00 01 01 00 B0 00 00 00 01

写入HR区参数同理。比如往HR10写入两组数据0x0001和0x0002,HR区代码0xB2,HR10字地址×2=20=0x0014,命令为:

80 00 02 00 00 00 00 01 00 00 01 02 00 B2 00 14 00 02 01 00 02 00

第18、19字节是写入的数据长度0002,后面是两组数据:01 00和02 00(低字节在前)。写完成后最好用读命令读回来核对一遍,确认PLC侧数据没有被其他程序覆盖。

2.4 常用FINS命令码延伸

除了0101和0102,还有几条在调试中常用的命令:

命令码功能说明
0101内存区读最常用,适合轮询数据
0102内存区写参数下发、开关控制
2301运行模式设置切换RUN/PROGRAM模式
0401运行状态读取读取PLC当前模式、故障状态
0501单元状态读取用于诊断链路连接状态

2301这个命令在远程切换PLC模式时很实用。比如调试完程序后自动切换到运行模式,或者发生异常时远程置为编程模式,不需要去现场拨开关。不过用这条命令要格外谨慎,生产模式下切换到编程模式会让输出全部断电,设备可能停在半空中,最好在程序里做防呆。

3. 调试技巧:FCS校验、串口助手与抓包工具

3.1 FCS校验计算方法与常见误区

HostLink帧的FCS校验计算很简单:从@字符后面的第一个字符开始,到校验位之前的最后一个字符为止,所有ASCII码按字节异或,结果取两位十六进制大写字符。异或的意思是按位相加不进位,比如0x41异或0x42等于0x03。

以刚才读取DM100的报文为例,参与校验的字符串是:

00FCS00800002000000000100000101008000C80002

把这个字符串逐字符异或,得到一个0x00~0xFF的值,转成两位大写十六进制就是最终的校验码。手工算一遍大约需要两三分钟,但项目调试时要反复改参数、换地址,每次都手算太折磨。建议两种做法:一是用现成的在线异或校验工具,把字符串贴进去直接出结果;二是在自己写的上位机调试工具里加一个校验计算函数,几行代码的事,长期用下来效率高很多。

FCS校验的常见坑有三个:第一,@字符本身不参与校验,很多人从@开始异或,算出来的校验值永远不对;第二,*CR不参与校验,只作为帧结束判断;第三,计算的是ASCII字符的异或值,不是十六进制字节值。比如字符串里的“80”要当成0x38和0x30两个值参与运算,不要当成0x80参与运算。

3.2 用串口助手模拟上位机调通FINS命令

调试FINS命令,最直接的办法是先把上位机代码放一边,用串口助手手工发报文。这样能把问题收敛在“命令是否正确”这一层,避免PLC、代码、网络三层问题搅在一起。

具体步骤:

  1. 用USB转串口线连接电脑和PLC的串口,确认串口号。
  2. 串口参数要和PLC串口设置一致。欧姆龙PLC出厂默认一般是9600波特率、7位数据位、偶校验、2位停止位。这个配置和很多日系设备的默认值相同,但不同型号可能不一样,打开CX-Programmer或Sysmac Studio的PLC设定确认一下最保险。
  3. 串口助手里选择ASCII发送模式,把完整报文粘贴进去,勾选自动追加回车换行(对应*CR)。
  4. 点击发送,观察接收区是否返回响应帧。有响应但不正常,按FINS错误码排查;完全没响应,先查物理连接和单元号。

我第一次调通这个流程时,卡在串口参数上。PLC设定里是9600 7 E 2,但串口助手默认是9600 8 N 1,发了好几次都是石沉大海。后来把停止位改成2、校验改成偶校验,报文立马通了。所以遇到没响应,先别怀疑FINS命令格式,看一眼串口参数对不对。

3.3 用串口监听工具抓取真实报文

有时候上位机代码已经写好了,但通讯不稳定,这时可以借助串口监听工具抓取真实的收发数据。常用的有AccessPort、VSPD(虚拟串口)配合串口分线器等。AccessPort这类工具能在不改动现有程序的情况下监听串口数据流,看到上位机实际发出去了什么、PLC实际返回了什么。

抓包的目的有两个:一是验证上位机发出去的命令体是否和设计一致,很多时候代码里字符串拼接少了一个0,或者大小写转换出错,肉眼看不出来,抓包一看就露馅;二是分析响应时序,比如PLC响应延迟是否超时、返回帧是否被截断、帧与帧之间是否粘连。

分享一个实用技巧:在串口监听工具里开启时间戳,记录每帧数据的收发时间差。如果发现PLC响应时间不稳定,从几毫秒跳变到几百毫秒,多半是PLC程序扫描周期变长或者通讯缓冲区拥堵,而不是命令本身的问题。这时候去优化PLC程序里的通讯处理段,比反复改上位机代码有效得多。

3.4 现场调试设备选型的常见坑

现场调试FINS通讯,硬件选型不当会浪费大量时间。最常见的坑是USB转串口线质量参差不齐。便宜的线用CH340芯片,虽然后面原理上能跑,但抗干扰能力差,在一些电柜环境里经常丢字节。有条件就上FT232芯片的转接线,稳定很多。

另一个坑是9针串口的接法。欧姆龙PLC的串口一般是9针公头,电脑这边往往需要USB转9针母头,线序里涉及2号脚RXD、3号脚TXD、5号脚GND。有些转接线只有2、3、5三根线,这在短距离直连时够用,但如果线材超过两三米或者靠近动力电缆,就需要用屏蔽双绞线并可靠接地,否则偶发通讯错误能排查到崩溃。

波特率方面,9600波特率是最稳妥的选择,距离可以拉得远一些;如果PLC支持并且线材靠谱,19200甚至38400也能用,但现场有变频器、伺服驱动器这些干扰源时,高速率更容易出错。工业现场求稳为主,速度不是第一位的。

4. 常见问题与错误码排查实录

4.1 FINS错误码速查表

FINS命令响应中的完成码字段反映了PLC对命令的处理结果。把实际项目中碰到频率最高的几个错误码整理成表,按这个查基本能定位问题:

完成码含义排查方向
0x0000正常完成无需处理
0x0101本地节点错误检查源节点号SA1,是否与其他设备冲突
0x0102目标节点错误检查DNA、DA1设置,HostLink下DA1填00
0x0103目标节点不存在确认PLC型号支持FINS,网络参数无误
0x0105目标节点已停止把PLC切到运行模式再试
0x1101内存区分类错误内存区代码填错,核对是否按16进制书写
0x1102访问地址指定错误地址越界或者地址计算错误,重点查字地址×2
0x1103读取数据长度错误数据长度超过上限或与访问区类型不匹配
0x1104写入数据长度错误写入数据字节数与长度字段不一致
0x2001命令不支持确认PLC型号是否支持该FINS命令码
0x2002内存区不存在该机型没有对应的内存区,查阅硬件手册

0x1102是出现频率最高的一个。多数情况下不是真的越界,而是地址换算出错。比如想把DM1000换算成0x07D0,结果手算成了0x03E8(那是1000十进制的十六进制),两者差了4倍。用上位机代码做地址转换时,一定要在注释里写明“地址=字地址×2”,防止三个月后自己回来看代码时一脸懵。

4.2 常见故障现象排查对照表

错误码只是故障的现象之一。下面这些故障场景更适合用现象来描述,排查方向也各不相同:

现象可能原因排查步骤
报文发出去完全没响应串口参数不对、单元号不对、接线错误先测自发自收,再核对PLC串口设置
有响应但返回内容乱码数据位/校验位设置不一致两端统一为7 E 2或8 N 1
偶发性无响应,一段时间后又恢复通讯线受干扰、波特率过高降波特率、换屏蔽线、检查接地
命令格式看起来对但一直报1101内存区代码高低字节写反确认0080写成8000没有
读取的数据和PLC实际值对不上字节序处理错误,未做低字节在前核对每个字的高低字节顺序
上位机多线程访问时数据错乱SID重复或响应匹配逻辑不严谨每次发送分配唯一SID,校验响应帧SID

关于“有响应但乱码”,我遇到过最诡异的一次,是电脑和PLC之间串口参数完全一致,但返回的数据每隔几个字符就多出一个0x00。查了半天发现是串口助手软件在ASCII发送模式下自动把回车换行追加错了,多发了两个00字符。这种软件层面的低级问题,抓包工具一秒钟就能暴露出来。

4.3 分层排查法:从物理层到应用层

现场通讯问题千奇百怪,但按分层思路排查是最快的。第一层物理层,用一根短线把PLC和电脑直接连起来,排除中间转接、电柜干扰、线缆过长等因素。串口调试助手里开自发自收测试,能收到自己发的数据说明转接线基本正常。第二层链路层,核对串口参数、单元号、FCS校验,这一步主要是排除帧格式错误。第三层应用层,看FINS命令体、内存区代码、地址换算,用错误码表对照。

这个分层思路借鉴了网络排错的套路,在工业通讯里同样适用。不要一上来就怀疑上位机代码,先确认物理层和链路层没问题,再逐层往上查。曾经有个项目,上位机显示通讯超时,我花了一个下午查FINS命令,最后发现是PLC串口线在水管下面泡了半个多月,接头已经腐蚀了,换根线瞬间解决。

分层排查的另一个好处是,能帮你积累一套自己的“通讯自检清单”。每次去现场,先按清单快速过一遍,很多时候五分钟就能定位问题,不用每次都从头摸索。这份清单建议包括:线缆外观和连接、串口参数、单元号、FCS校验、目标节点号、内存区代码和地址、上位机超时设置。

4.4 源节点号与会话匹配的工程经验

前面提到SA1源节点号和SID服务标识符,这两个字段在单命令调试时看不出什么作用,但工程应用时直接影响通讯稳定性。多台上位机共享一条HostLink链路时,SA1必须各不相同,否则PLC无法区分请求来源;同一台上位机并发发送多条FINS命令时,SID要保证唯一,响应帧里的SID字段和请求帧一致,上位机才能把响应和请求正确配对。

具体实现上,建议每次发送命令前把SID加1,范围在0x00~0xFF之间循环。不要嫌256个值太少,正常轮询场景下同一时刻在途的请求数量远小于这个数。响应匹配时一定要校验两个字段:命令码是否回显一致、SID是否一致。有些上位机组件只校验命令码不校验SID,在低频通讯时没事,一旦高频并发,响应错乱的概率会显著上升。我在自己写的调试工具里强制校验SID,实测并发20条请求都没出现过配对错误。

5. 进阶扩展:把FINS命令变成工程能力

5.1 跨协议复用的价值

FINS命令一套指令通吃HostLink串口和以太网FINS/TCP,这个特性的工程价值很大。比如客户在现场用串口连PLC,开发阶段用HostLink调通了所有读写逻辑;后来客户升级网络架构,要求改用以太网,上位机代码里只需要把发送接收层从串口换成Socket,FINS命令体一行都不用改。协议栈与业务逻辑分离,就是FINS带来的架构红利。

同样,视觉系统对接、扫码枪数据上传这类常见需求,只要对方设备支持串口或以太网,都可以用同一套FINS命令完成数据交互。有一次我需要让视觉控制器把检测结果写到PLC的HR区,直接用HostLink发0102命令,一个下午就调通了。视觉程序里不需要额外引入复杂的通讯库,单纯拼报文、发串口、解析响应就够了。

5.2 与第三方通讯库的配合

如果你用C#、Java或Python写上位机,社区里已经有成熟的欧姆龙通讯库可以直接使用。比如HslCommunication这个库,对欧姆龙HostLink和FINS/TCP封装得比较完整,内部实现了帧格式拼装、FCS校验、响应解析、异步发送等逻辑。用这类库的好处是省去重复造轮子的时间,但强烈建议先手动跑通FINS裸命令再上库。原因很简单:库用出问题的时候,你如果看不懂底层报文,只能干瞪眼;亲手调通过一遍,就能区分是库的bug还是自己的参数错误。

使用通讯库时还要注意版本兼容问题。我遇到过HslCommunication旧版本在.NET Framework和.NET Core之间行为不一致的情况,串口参数偶发性丢字节,升级到新版后恢复正常。第三方库不是万能的,关键项目最好有直接抓包验证的兜底手段。

5.3 结合AI工具生成FINS通讯代码的取舍

这两年AI代码生成工具越来越强,很多朋友开始用它辅助生成PLC通讯代码。实测下来,AI对FINS常见读写命令的帧格式理解比较准确,生成0101、0102这类标准命令的代码基本能用,但涉及特殊机型、特殊内存区或者复杂错误处理时,经常出现代码格式对但逻辑有微妙错误的情况。

我的建议是:用AI生成代码之前,自己先具备手工构造FINS命令的能力。哪怕只调通过一次裸命令,你在审核AI生成代码时就能一眼看出地址换算、字节序、校验和这些关键点有没有问题。AI生成代码适合用来搭框架、写重复性高的轮询逻辑,不适合直接作为不了解协议时的“黑盒”。调试现场永远保留一份自己写的裸命令测试脚本作为对照基准,出了问题能快速定位是AI代码的问题还是PLC的问题。

我个人在实际项目里的体会是:FINS命令这套东西,难度不在协议本身,而在细节积累。地址换算、字节序、校验范围、SID匹配,每一个点单独拿出来都不难,但叠加在一起就是无数个坑。把这篇里的示例报文逐个手工调通一遍,再把错误码表打印出来贴在工位上,遇到问题按分层思路排查,绝大多数通讯故障都能在半小时内定位。最后分享一个小技巧:保留一份自己调试通过的“命令字典”,把常用功能对应的完整报文、校验码、响应示例都记下来,新项目直接复制修改,能省掉大量重复踩坑的时间。

返回列表