C# OMRON PLC FINS TCP协议简单测试

       FINS(factory interface network service)通信协议是欧姆龙公司开发的用于工业自动化控制网络的指令/响应系统。运用 FINS指令可实现各种网络间的无缝通信,包括用于信息网络的 Etherne(以太网),用于控制网络的Controller Link和SYSMAC LINK。

      ORMON PLC的FINS协议看起来非常简单,但其中数据内容涉及高低位转换、16进制整数、字符串,有时需要自己写代码来进行通讯处理。

1、PLC的数据类型

数据类型

说明

布尔型

单个位

短整型

有符号 16 位值
位 0 是低位
位 14 是高位
位 15 是符号位

无符号 16 位值
位 0 是低位
位 15 是高位

长整型

有符号 32 位值
位 0 是低位
位 30 是高位
位 31 是符号位

双字型

无符号 32 位值
位 0 是低位
位 31 是高位

浮点型

32 位实数

BCD

两个字节封装的 BCD
值的范围是 0 至 9999。对于超出此范围的值,未定义行为。

LBCD

四个字节封装的 BCD
值的范围是 0 至 99999999。对于超出此范围的值,未定义行为。

字符串

空终止 ASCII 字符串。
支持多达 512 个字符的字符串长度,并支持择由高到低的字节排序、由低到高的字节排序、仅高位字节和仅低位字节。

短整型、长整型、双字等也可以是BCD码,需要根据PLC的程序设定进行解析。

1、FINS帧定义

FINS/UDP运用的是一种嵌套格式数据包,即Ethernet报头、IP报头、 UDP报头和FINS帧。一个UDP数据段(FINS 帧)超过1472字节将被分成若干个数据包来传送。分开的UDP数据将在UDP/IP协议层自动组合。通常不须要关注运用 层的数据分段,但是在一个多层 IP网络中1427字节的UDP包可能无法 发送。在这种系统中就须要运用 FINS/TCP方式。

ICF为信息控制域,用于标明指令和响应;

RSV为系统保留;

GCT为网关允许数目;

DNA为目的网络号;

DA1为目的节点号;

DA2为目的单元号;

SNA为源网络号;

SA1为源节点号;

SA2为源单元号;

SID为服务和响应的标识号,可任意配置,指令和响应对应相同;

MRC和SRC分别为 FINS指令的主指令和从指令;

参数/数据域,用于标明所操作的数据地址、范围等,在响应帧中前两个字节MRES和SRES构成响应码,用来诊断不正确信息

填充示例:

2、PLC连接、数据读取和解析示例

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;namespace PascalMing
{public class Tcp_FINS_PascalMingTest{TcpClient _tcpClient = new TcpClient();int _port;string _host;byte plcAddr = 0;byte pcAddr = 0;int headDm = 30;const int readDMStart = 5000;const int readDMCount = 60;EventWaitHandle ewh = new EventWaitHandle(false, EventResetMode.AutoReset);CancellationTokenSource cts = new CancellationTokenSource();//返回:46 49 4E 53 00 00 00 10 00 00 00 01 00 00 00 00 00 00 00 F0 00 00 00 9B //PC,PLC IP最后一位(4个字节一组)//不同网络配置返回值有区别,需要根据实际进行替换byte[] cmdConnect = { 0x46, 0x49, 0x4E, 0x53, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };//最后一位:PC端IP最后一位//读D5000,连续100个byte[] cmdReadD5000 = { 0x46, 0x49, 0x4E, 0x53, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x02, 0x00, 0x9B, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x01, 0x01, 0x82, (byte)(readDMStart / 0x100), (byte)(readDMStart % 0x100), 0x00, (byte)(readDMCount/0x100), (byte)(readDMCount%0x100) };public bool ConnectDevice(string ip, int port){_host = ip;_port = port;try{_tcpClient = new TcpClient();_tcpClient.Connect(_host, _port);//_tcpClient.ReceiveTimeout = 5_000;_tcpClient.Client.Send(cmdConnect);byte[] rx = new byte[100];for (int k = 0; k < 100; k++){if (_tcpClient.Available >= 24)break;Thread.Sleep(50);}int ret = _tcpClient.Client.Receive(rx);Console.WriteLine($"connect recv Len:{ret},{rx[0]},{rx[1]},{rx[2]},{rx[3]},{rx[7]}");if (ret == 24 && rx[0] == 0x46 && rx[1] == 0x49 && rx[2] == 0x4E && rx[3] == 0x53){pcAddr = rx[19];plcAddr = rx[23];cmdReadD5000[20] = plcAddr;cmdReadD5000[23] = pcAddr;Console.WriteLine("connect ok");Task.Run(() =>{myTaskExecute(cts.Token);});                return true;}Console.WriteLine("connect fail,check fail");return false;}catch (Exception ex){Console.WriteLine("connect fail,ex:"+ex.Message);return false;}}int count = 0;async Task myTaskExecute(CancellationToken token){Stopwatch sw = Stopwatch.StartNew();int timeOutMs = 30_000;List<byte[]> cmdIndex = new List<byte[]>();ushort txCount = 0;try{while (!token.IsCancellationRequested){int ret = -1;byte[] rx = new byte[4096];Console.WriteLine($"{DateTime.Now} send read");_tcpClient.Client.Send(cmdReadD5000);for(int k = 0; k < 200; k ++){if (_tcpClient.Available >= headDm+ readDMCount*2)break;await Task.Delay(20, token);}Console.WriteLine($"{DateTime.Now} send Available:{_tcpClient.Available}");if (_tcpClient.Available > 0){sw.Restart();ret = _tcpClient.Client.Receive(rx);try{Console.WriteLine($"{DateTime.Now} DataReceived len:{ret},data:{rx[7]},{rx[19]},{rx[23]}");if (ret >= 16 && rx[0] == 0x46 && rx[1] == 0x49 && rx[2] == 0x4E && rx[3] == 0x53){//数据解析根据PLC定义进行,包括数据值。此处使用比较简单的测试方案Console.WriteLine($"D{5000}:{GetInt16(rx,0)}");Console.WriteLine($"D{5001}:{GetInt16(rx,1)}");Console.WriteLine($"D{5010}:{GetInt32_2(rx, 10)}");Console.WriteLine($"D{5012}:{GetInt32_2(rx, 12)}");Console.WriteLine($"D{5014}:{GetInt16(rx, 14)}");Console.WriteLine($"D{5015}:{GetString(rx, 15,40)}");Console.WriteLine();                            }}catch (Exception ex){Console.WriteLine("DataReceived parse err:" + ex.Message);}}await Task.Delay(2000, token);}}catch (Exception ex){Console.WriteLine("DataReceived ex:" + ex.Message);}Console.WriteLine("DataReceived leave");}public int GetInt16(byte[]data,int offset){string sV = $"{data[headDm+ offset*2]:X2}{data[headDm+offset*2+1]:X2}";int iV = int.Parse(sV);return iV;}public int GetInt32(byte[] data, int offset){string sV = $"{data[headDm + offset*2]:X2}{data[headDm + offset*2 + 1]:X2}{data[headDm + offset*2 + 2]:X2}{data[headDm + offset*2 + 3]:X2}";int iV = int.Parse(sV);return iV;}public int GetInt32_2(byte[] data, int offset){string sV = $"{data[headDm + offset * 2+2]:X2}{data[headDm + offset * 2 + 3]:X2}{data[headDm + offset * 2 + 0]:X2}{data[headDm + offset * 2 + 1]:X2}";int iV = int.Parse(sV);return iV;}public string GetString(byte[] data, int offset,int len){int headDm = 30;StringBuilder sb = new StringBuilder();for(int k = 0; k < len; k ++){if (data[headDm + offset*2 + k] == 0)break;sb.Append($"{(char)data[headDm+offset*2+k]}");}return sb.ToString();}public void DisconnectDevice(){_tcpClient?.Close();}}
}

验证:

Tcp_FINS_PascalMingTest tcp_fins = new Tcp_FINS_PascalMingTest();
void Do_Tcp_FINS()
{tcp_FINS_Yinlun.ConnectDevice("192.168.0.1", 9600);
}

3、参考资料

FinsTCP协议报文详细分析 - 知乎
基于FINS协议的OMRON PLC与上位机以太网通信的实现_omron nx fins上位机配置-CSDN博客
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/453014.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL Server之DML触发器

一、如何创建一个触发器呢 触发器的定义语言如下&#xff1a; CREATE [ OR ALTER ] TRIGGER trigger_nameon {table_name | view_name}{for | After | Instead of }[ insert, update,delete ]assql_statement从这个定义语言我们可以知道如下信息&#xff1a; trigger_name&…

Kubernetes - 如何利用 K8S 拉取私有仓库镜像

问题描述 最近实战时&#xff0c;发现一个很奇怪的问题&#xff0c;在通过 k8s 创建 pod&#xff0c;拉取镜像时&#xff0c;总是显示如下信息&#xff1a; Error syncing pod, skipping: failed to "StartContainer" for "POD" with ImagePullBackOff: …

大数据 - Spark系列《四》- Spark分布式运行原理

Spark系列文章&#xff1a; 大数据 - Spark系列《一》- 从Hadoop到Spark&#xff1a;大数据计算引擎的演进-CSDN博客 大数据 - Spark系列《二》- 关于Spark在Idea中的一些常用配置-CSDN博客 大数据 - Spark系列《三》- 加载各种数据源创建RDD-CSDN博客 目录 &#x1f360;…

Java项目管理01-Maven基础

一、Maven的常用命令和生命周期 1.Maven的常用命令使用方式 complie&#xff1a;编译&#xff0c;将java文件编译为class字节码文件 clean&#xff1a;清理&#xff0c;删除字节码文件 test&#xff1a;测试&#xff0c;运行项目中的test类 package&#xff1a;打包&#x…

[SWPUCTF 2021 新生赛]easyupload1.0

发现是上传文件第一想到是文件木马 <?php eval ($_POST[123]);?>木马上传burp修改后缀发现flag里面这个是假的 我们猜想是在phpinfo我们上传<?php eval(phpinfo(););?>木马上传burp修改后缀里面 CtrlF 发现flag

Oracle 面试题 | 12.精选Oracle高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Packet Tracer - Configuring a Zone-Based Policy Firewall (ZPF)

Packet Tracer - 配置基于区域的策略防火墙&#xff08;ZPF&#xff09; 地址表 目标 在防火墙配置前验证设备之间的连通性。 在路由器R3上配置基于区域的策略&#xff08;ZPF&#xff09;防火墙。 使用ping、Telnet和网页浏览器验证ZPF防火墙功能。 背景/场景 基于区域的…

ROS2学习(一):Ubuntu 20.04 安装 ROS2(Galactic Geochelone)

文章目录 一、ROS2(Galactic Geochelone)介绍二、ROS2(Galactic Geochelone)安装1. 设置语言环境2. 配置ubuntu universe仓库3. 配置ros2 apt仓库4. 安装ros25. 安装情况测试 一、ROS2(Galactic Geochelone)介绍 官方文档 二、ROS2(Galactic Geochelone)安装 1. 设置语言环…

ACM训练题:曲线

这题只需要注意一个点&#xff0c;就是所有二次函数的二次系数都是大于0的&#xff0c;这说明这是个下凸函数&#xff0c;而且最小值旁边都是单调的&#xff0c;对于求区间凸函数极值问题&#xff0c;套三分模板即可。 AC代码&#xff1a; #include<bits/stdc.h> usin…

Ubuntu+GPU搭建Stable-Diffusion教程

【前序】已经安装anaconda 1.git拉取项目到本地 执行git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git 进入项目目录下 cd stable-diffusion-webui/ 2. 安装对应Python依赖包 首先安装pytorch和torchvision&#xff0c;若是GPU环境的用户需要安装与cu…

CSDN文章导出工具

源码地址&#xff1a; github:https://github.com/lishuangquan1987/CSDNExportergitee:https://gitee.com/lishuangquan1987/csdnexporter 介绍 最近有CSDN博客导出来的需求&#xff0c;翻看了很多开源工具&#xff0c;都不能用或者不好用&#xff0c;于是决定自己做一个。…

【Docker】入门到精通(常用命令解读)

一、准备工作 1.配置Docker的yum库 首先要安装一个yum工具 yum install -y yum-utils安装成功后&#xff0c;执行命令&#xff0c;配置Docker的yum源&#xff1a; yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo2.安装Docker 执…