西门子、三菱、欧姆龙是我们自动化行业使用最多的三个PLC品牌。今天分享一下欧姆龙PLC的FinsTCP通信协议。

大家在学习FinsTCP通信协议时,建议先掌握ModbusTCP或三菱MC通信协议。

这样看来,ModbusTCP协议太简单了

三菱PLC的MC通信协议报文解析

Fins通信协议是欧姆龙PLC专用协议,主要用于控制欧姆龙系列PLC,它是一个公开的协议,可以通过欧姆龙官方下载到协议文档。

一、握手协议

FinsTCP通信协议,与ModbusTCP和MC协议有一个不同地方在于,当我们完成TCP连接后,不能直接进行读取或写入,需要有一个握手过程,以保证通信安全。

这点与西门子S7协议类似,S7协议会有两次握手验证,FinsTCP只需要一次即可。

握手命令如下所示:

发送报文格式:

图片

接收报文格式:

图片

我们使用TCP助手测试一下:本机IP地址是192.168.2.77,PLC的IP地址是192.168.2.164,因此发送报文为:

46 49 4E 53 00 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 4D

图片

返回报文为:

46 49 4E 53 00 00 00 10 00 00 00 01 00 00 00 00 00 00 00 4D 00 00 00 A4 

其中0x4D=77,对应ClientNode,PC的IP最后一位。

0xA4=164,对应ServerNode,PLC的IP最后一位。

二、Fins通用格式

我们学习通信,一般都会有个通用格式。

所谓通用格式,就是无论发送、接收的报文都会按照这个格式来,会将变化的部分封装成一个整体,一般叫做数据部分或者Parameter。

Fins通用报文格式如下:

图片

三、读取协议帧

FinsTCP通信协议读取数据的请求帧报文是在通用格式的基础上,将 Parameter部分替换为 Area+Address+Length。读取请求帧格式如下所示:

图片

响应帧报文是在通用格式的基础上,将 Parameter部分替换为 ErrorCode+Value。读取响应帧格式如下所示:

图片

图片

四、写入协议帧

FinsTCP通信协议写入数据的请求帧报文是在通用格式的基础上,将 Parameter部分替换为 Area+Address+Length+Value。写入请求帧格式如下所示:

图片

图片

响应帧报文是在通用格式的基础上,将 Parameter部分替换为 ErrorCode。写入响应帧报文如下所示:

图片

五、通信测试

我们以读取D0开始的5个寄存器为例,结合协议文档,来进行报文拼接。

发送报文如下:

Header:0x46 0x49 0x4E 0x53

Length:0x00 0x00 0x00 0x1A

Command:0x00 0x00 0x00 0x02

ErrorCode:0x00 0x00 0x00 0x00

ICF:0x80

RSV:0x00

GCT:0x02

DNA:0x00

DA1:0xA4

DA2:0x00

SNA:0x00

SA1:0x4D

SA2:0x00

SID:0x00

MRC:0x01

SRC:0x01

Area:0x82

Address:0x00 0x00 0x00

Length:0x00 0x05

我们通过网络调试助手发送这个报文,观察一下返回的报文:

图片

响应报文如下:

我们只需要关注最后的ErrorCode和Value即可。

ErrorCode:0x00 0x00

Value:0x00 0x0A 0x00 0x14 0x00 0x1E 0x00 0x28 0x00 0x32

其中0x00 0x0A 0x00 0x14 0x00 0x1E 0x00 0x28 0x00 0x32即表示D0-D4的值,进行数据解析处理后的值分别为10、20、30、40、50,与PLC数据一致。

图片

六、代码实现

我们也可以编写C#程序来实现整个过程。

这里测试为主,代码相对简单,实际应用时可进一步封装,代码如下:

static void Main(string[] args)
{
    // 连接
    Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    socket.Connect("192.168.2.164", 9600);
    //握手
    byte[] handsend = new byte[] { 0x46, 0x49, 0x4E, 0x53, 
        0x00, 0x00, 0x00, 0x0C, 
        0x00, 0x00, 0x00, 0x00, 
        0x00, 0x00, 0x00, 0x00, 
        0x00, 0x00, 0x00, 0x4D };

    socket.Send(handsend);
    byte[] handrcv = new byte[1024];
    int count = socket.Receive(handrcv);
    //简单验证握手正确
    if (count == 24 && handrcv[12] == 0x00 && handrcv[13] == 0x00 && handrcv[14] == 0x00 && handrcv[15] == 0x00)
    {
        //读取D0开始的5个字
        byte[] readsend = new byte[] { 0x46, 0x49, 0x4E, 0x53, 
        0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x02, 0x00, 
        0x00, 0x00, 0x00, 0x80, 0x00, 0x02, 0x00, 0xA4, 0x00, 
        0x00, 0x4D, 0x00, 0x00,0x01,0x01,0x82,0x00,0x00,
        0x00,0x00,0x05};
        socket.Send(readsend);
        byte[] readrcv = new byte[1024];
        int rcvCount = socket.Receive(readrcv);

        if (rcvCount == 40)
        {
            for (int i = 30; i < rcvCount; i += 2)
            {
                // 每2个字节作为一个数据
                byte[] dataBytes = new byte[2];
                dataBytes[0] = readrcv[i + 1];
                dataBytes[1] = readrcv[i];
                Console.WriteLine(BitConverter.ToInt16(dataBytes, 0));
            }
        }
    }
    Console.ReadLine();
}

输出结果如下:

图片

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐