本文将使用一个gitHub开源的组件技术来读写西门子plc数据,使用的是基于以太网的TCP/IP实现,不需要额外的组件,读取操作只要放到后台线程就不会卡死线程,本组件支持超级方便的高性能读写操作

github地址:https://github.com/dathlin/HslCommunication 如果喜欢可以star或是fork,还可以打赏支持。

联系作者及加群方式(激活码在群里发放):http://www.hslcommunication.cn/Cooperation

在Visual Studio 中的NuGet管理器中可以下载安装,也可以直接在NuGet控制台输入下面的指令安装

Install-Package HslCommunication

如果需要教程:Nuget安装教程:http://www.cnblogs.com/dathlin/p/7705014.html

组件的完整信息和其他API介绍参照:http://www.cnblogs.com/dathlin/p/7703805.html   组件的授权协议,更新日志,都在该页面里面。

本文将展示如何配置网络参数及怎样使用代码来访问PLC数据,希望给有需要的人解决一些实际问题。主要对西门子PLC的M,Q,I,DB块的数据读写,亲测有效。

此处使用了网线直接的方式,如果PLC接进了局域网,就可以进行远程读写了^_^

此处使用到了2个命名空间:

using HslCommunication;
using HslCommunication.Profinet.Omron;

随便聊聊


当我们一个上位机需要读取100台西门子PLC设备(此处只是举个例子,凡是都是使用Modbus tcp的都是一样的)的时候,你采用服务器主动去请求100台设备的机制对性能来说是个极大的考验,如果开100个线程去轮询100台设备,那么性能损失将是非常大的,更不用说再增加设备,如果搭建Modbus tcp服务器,就可以完美的解决性能问题,因为连接的压力将会平均分摊给每一台PLC,服务器端只要新增一个时间戳就可以知道客户端有没有连接上。

我们在100台PLC里都增加发送Modbus tcp方法,将数据发送到服务器的ip和端口上去,服务器根据站号来区分设备。这样就可以搭建一个高性能总站。 本组件支持快速搭建一个高性能的Modbus tcp总站。

http://www.cnblogs.com/dathlin/p/7782315.html

关于两种模式


本组件所提供的所有客户端类,包括三菱,西门子,欧姆龙,modbus-tcp,以及SimplifyNet都是继承自双模式基类,双模式包含了短连接和长连接,下面就具体介绍下两个模式的区别

短连接:每次读写都是一个单独的请求,请求完毕也就关闭了,如果服务器的端口仅仅支持单连接,那么关闭后这个端口可以被其他连接复用,但是在频繁的网络请求下,容易发生异常,会有其他的请求不成功,尤其是多线程的情况下。

长连接:创建一个公用的连接通道,所有的读写请求都利用这个通道来完成,这样的话,读写性能更快速,即时多线程调用也不会影响,内部有同步机制。如果服务器的端口仅仅支持单连接,那么这个端口就被占用了,比如三菱的端口机制,西门子的Modbus tcp端口机制也是这样的。以下代码默认使用长连接,性能更高,还支持多线程同步。

在短连接的模式下,每次请求都是单独的访问,所以没有重连的困扰,在长连接的模式下,如果本次请求失败了,在下次请求的时候,会自动重新连接服务器,直到请求成功为止。另外,尽量所有的读写都对结果的成功进行判断。

关于日志记录


不管是三菱的数据访问类,还是西门子的,还是Modbus tcp访问类,都有一个LogNet属性用来记录日志,该属性是一个接口类,ILogNet,凡事继承该接口的都可以用来记录日志,该日志会在访问失败时,尤其是因为网络的原因导致访问失败时会进行日志记录(如果你为这个 LogNet 属性配置了真实的日志记录器的话):如果你想使用该记录日志的功能,请参照如下的博客进行实例化:

http://www.cnblogs.com/dathlin/p/7691693.html

举个例子:

omronFinsNet.LogNet = new HslCommunication.LogNet.LogNetSingle( "omron.log.txt" );

关于通讯的说明


使用FINS-TCP协议实现数据交互,如果在测试的过程中,发现写入失败的话,有可能是因为PLC侧进行了写保护操作。

访问测试项目


在上述的github源代码里有个测试项目,HslCommunicationDemo,里面包含了各种客户端的Demo项目,不需要编写任何的代码就可以测试数据的访问了。

下载地址为:HslCommunicationDemo.zip

演示项目


下面的三篇演示了具体如何去访问PLC的数据,我们在访问完成后,通常需要进行处理,以下的示例项目就演示了后台从PLC读取数据后,前台显示并推送给所有在线客户端的功能,客户端并进行图形化显示,具有一定的参考意义,项目地址为:

https://github.com/dathlin/RemoteMonitor

下面的图片示例中的左边程序就是服务器程序,它应该和PLC直接连接并接入局域网,然后把数据推送给客户端显示。注意:一个复杂高级的程序就应该把处理逻辑程序和界面程序分开,比如这里的服务器程序实现数据采集,推送,存储。让客户端程序去实现数据的整理,分析,显示,这样即使客户端程序因为BUG奔溃,服务器端仍然可以正常的工作。

演示项目使用的西门子访问,可以方便的改成欧姆龙的项目

地址支持


支持地址及示例如下:

  • DM区  D100
  • CIO区 C100
  • WR区 W100
  • HR区 H100
  • AR区 A100

特别感谢


  • 感谢 酒罢舞 对本组件的测试
  • 感谢 一贝水 对本组件的测试

实例化


 
private OmronFinsNet omronFinsNet = new OmronFinsNet( "192.168.0.100", 6000 );

在连接服务器前需要设置三个参数,PLC的单元号,PLC的网络节点,PC的网络节点,如下是举例,你需要根据实际情况来填写。

            omronFinsNet.SA1 = 0x20; // PC网络号,PC的IP地址的最后一个数
omronFinsNet.DA1 = 0x10; // PLC网络号,PLC的IP地址的最后一个数
omronFinsNet.DA2 = 0x00; // PLC单元号,通常为0

连接服务器,也可以放在窗口的Load方法中,一般建议使用长连接,速度更快,又是线程安全的(调用下面的方法就是使用了长连接,如果不连接直接读取数据,那就是短连接):


            try
{
OperateResult connect = omronFinsNet.ConnectServer( );
if (connect.IsSuccess)
{
MessageBox.Show( "连接成功!" );
}
else
{
MessageBox.Show( "连接失败!" );
}
}
catch (Exception ex)
{
MessageBox.Show( ex.Message );
}

断开连接,也就是关闭了长连接,如果再去请求数据,就变成了短连接


omronFinsNet.ConnectClose( );

下面就演示一些简单的数据操作,省去了对结果是否成功的验证,所有的读写结果都是OperateResult类型及派生类型,都有一个IsSuccess属性来判断成功与否

            // 读取操作,这里的D100可以替换成C100,A100,W100,H100效果时一样的
bool D100_7 = omronFinsNet.ReadBool( "D100.7" ).Content; // 读取D100.7是否通断,注意D100.0等同于D100
short short_D100 = omronFinsNet.ReadInt16( "D100" ).Content; // 读取D100组成的字
ushort ushort_D100 = omronFinsNet.ReadUInt16( "D100" ).Content; // 读取D100组成的无符号的值
int int_D100 = omronFinsNet.ReadInt32( "D100" ).Content; // 读取D100-D101组成的有符号的数据
uint uint_D100 = omronFinsNet.ReadUInt32( "D100" ).Content; // 读取D100-D101组成的无符号的值
float float_D100 = omronFinsNet.ReadFloat( "D100" ).Content; // 读取D100-D101组成的单精度值
long long_D100 = omronFinsNet.ReadInt64( "D100" ).Content; // 读取D100-D103组成的大数据值
ulong ulong_D100 = omronFinsNet.ReadUInt64( "D100" ).Content; // 读取D100-D103组成的无符号大数据
double double_D100 = omronFinsNet.ReadDouble( "D100" ).Content; // 读取D100-D103组成的双精度值
string str_D100 = omronFinsNet.ReadString( "D100", 5 ).Content;// 读取D100-D104组成的ASCII字符串数据 // 写入操作,这里的D100可以替换成C100,A100,W100,H100效果时一样的
omronFinsNet.Write( "D100", (byte)0x33 ); // 写单个字节
omronFinsNet.Write( "D100", (short)12345 ); // 写双字节有符号
omronFinsNet.Write( "D100", (ushort)45678 ); // 写双字节无符号
omronFinsNet.Write( "D100", (uint)3456789123 ); // 写双字无符号
omronFinsNet.Write( "D100", 123.456f ); // 写单精度
omronFinsNet.Write( "D100", 1234556434534545L ); // 写大整数有符号
omronFinsNet.Write( "D100", 523434234234343UL ); // 写大整数无符号
omronFinsNet.Write( "D100", 123.456d ); // 写双精度
omronFinsNet.Write( "D100", "K123456789" );// 写ASCII字符串

下面说明复杂的数据操作,以及批量化的数据操作,例如读取D100-D105

            OperateResult<byte[]> read = omronFinsNet.Read( "D100", 5 );
{
if (read.IsSuccess)
{
// 此处需要根据实际的情况来自定义来处理复杂的数据
short D100 = omronFinsNet.ByteTransform.TransInt16( read.Content, 0 );
short D101 = omronFinsNet.ByteTransform.TransInt16( read.Content, 2 );
short D102 = omronFinsNet.ByteTransform.TransInt16( read.Content, 4 );
short D103 = omronFinsNet.ByteTransform.TransInt16( read.Content, 6 );
short D104 = omronFinsNet.ByteTransform.TransInt16( read.Content, 7 );
}
else
{
// 发生了异常
}
}

写入也是一样的,可以反着来操作。

如果想实现自定义的数据类型,需要继承一个接口

public class UserType : HslCommunication.IDataTransfer
{
#region IDataTransfer private HslCommunication.Core.IByteTransform ByteTransform = new HslCommunication.Core.ReverseWordTransform( ); public ushort ReadCount => 20; public void ParseSource( byte[] Content )
{
int count = ByteTransform.TransInt32( Content, 0 );
float temp = ByteTransform.TransSingle( Content, 4 );
short name1 = ByteTransform.TransInt16( Content, 8 );
string barcode = Encoding.ASCII.GetString( Content, 10, 10 );
} public byte[] ToSource( )
{
byte[] buffer = new byte[20];
ByteTransform.TransByte( count ).CopyTo( buffer, 0 );
ByteTransform.TransByte( temp ).CopyTo( buffer, 4 );
ByteTransform.TransByte( name1 ).CopyTo( buffer, 8 );
Encoding.ASCII.GetBytes( barcode ).CopyTo( buffer, 10 );
return buffer;
} #endregion #region Public Data public int count { get; set; } public float temp { get; set; } public short name1 { get; set; } public string barcode { get; set; } #endregion
}

  这样我们就是可以实现特殊数据的读写了

OperateResult<UserType> read = omronFinsNet.ReadCustomer<UserType>( "M100" );
if (read.IsSuccess)
{
UserType value = read.Content;
}
// write value
omronFinsNet.WriteCustomer( "M100", new UserType( ) );

究极数据的读取:

此处提供一个核心的报文读取机制,你可以自己传入自己的报文,然后接收服务器的报文,再自己解析操作,可以根据报文格式实现任意的操作,当然,前提是需要报文支持。假设我要实现读取D0,D1,那么最终的报文为

46494E530000001A000000020000000080000200210000C000000101820000000002

        private void userButton23_Click_1(object sender, EventArgs e)
{
byte[] buffer = HslCommunication.BasicFramework.SoftBasic.HexStringToBytes(
"46494E530000001A000000020000000080000200210000C000000101820000000002");
OperateResult<byte[]> operate = omronFinsNet.ReadFromServerCore(buffer);
if (operate.IsSuccess)
{
// 显示服务器返回的报文
TextBoxAppendStringLine(HslCommunication.BasicFramework.SoftBasic.ByteToHexString(operate.Content));
}
else
{
// 显示网络错误
MessageBox.Show(operate.ToMessageShowString());
}
}

更详细的信息,可以参照源代码里面的测试项目。

创作不易,感谢打赏


C# 读写欧姆龙(Omron)PLC ,C#使用Fins-tcp协议读写数据的更多相关文章

  1. C#读写三菱Fx PLC 使用Fx 串口协议 读写Fx3U设备

    本文将使用一个Github开源的组件库技术来读写三菱 FX PLC,使用的是基于串口的实现,不需要额外的组件,读取操作只要放到后台线程就不会卡死线程,本组件支持超级方便的高性能读写操作 github地 ...

  2. C# 读写倍福plc beckhoff , 使用ADS协议实现读取plc

    本文将使用库技术来读写倍福PLC数据,使用的是基于以太网的ADS实现,不需要额外的组件,读取操作只要放到后台线程就不会卡死线程,本组件支持超级方便的高性能读写操作 github地址:https://g ...

  3. Socket编程之聊天程序 - 模拟Fins/ModBus协议通信过程

    设备控制软件编程涉及到的基本通信方式主要有TCP/IP与串口,用到的数据通信协议有Fins与ModBus. 更高级别的通信如.net中的Remoting与WCF在进行C/S架构软件开发时会采用. 本篇 ...

  4. 关于OPC连接读写下位机PLC(转)

    原文转自:http://blog.csdn.net/u012252959/article/details/49736285?locationNum=11 开发OPC客户端程序时,首先应该生成OPC服务 ...

  5. C# 读写opc ua服务器,浏览所有节点,读写节点,读历史数据,调用方法,订阅,批量订阅操作

    OPC UA简介 OPC是应用于工业通信的,在windows环境的下一种通讯技术,原有的通信技术难以满足日益复杂的环境,在可扩展性,安全性,跨平台性方面的不足日益明显,所以OPC基金会在几年前提出了面 ...

  6. EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~终结~配置的优化和事务里读写的统一

    回到目录 本讲是通过DbCommand拦截器来实现读写分离的最后一讲,对之前几篇文章做了一个优化,无论是程序可读性还是实用性上都有一个提升,在配置信息这块,去除了字符串方式的拼接,取而代之的是sect ...

  7. IIC读写AT24C02代码2——串口命令控制多页读写

    通过串口输入 R .W 进行控制程序读写IIC设备.波特率9600bps,晶振115200HZ. main.c /*------------------------------------------ ...

  8. 维控PLC与电流变送器modbus通讯获取电流变送器数据

    2018-09-2319:28:01 今天本来要用单片机来做这个项目的,但是失败了.... 所以我又拿出了PLC来搞,也是相当之复杂,查了很多资料终于做出而来了. 今天还有事,赶紧临时备份总结一波

  9. Netty源码阅读之如何将TCP的读写操作和指定线程绑定

    原文链接:http://xueliang.org/article/detail/20200712234015993 前言 在Netty的线程模型中,对于一个TCP连接的读写操作,都是由一个单线程完成的 ...

随机推荐

  1. 【js】关于闭包、let、var的一个考题

    题目: html: body中有2个div 遍历,给每个div添加点击事件,输出值. js: var声明: 效果: 点击每个div后都打印2. 用户点击前,for循环就已经执行完了,是2,onclic ...

  2. lvs 进阶 第二章

    linux virtual server 一 . lvs lvs 对数据进行四层转发,根据目标地址和目标端口对请求数据进行转发. lvs 包含ipvsadm 和ipvs: ipvsadm :用户空间的 ...

  3. Python Redis 管道

    redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pi ...

  4. Bootstrap3基础 table-striped 表格实现隔行换色(浅灰色与白色交替)

      内容 参数   OS   Windows 10 x64   browser   Firefox 65.0.2   framework     Bootstrap 3.3.7   editor    ...

  5. Hi3519v101 SDK安装及升级

    安装SDK 1.解压tgz压缩包 将 Hi3519V101_SDK_Vx.x.x.x.tgz 压缩包放入共享文件夹中,并解压到Linux内部如 /sdk 目录下,因为在共享目录中编译容易出现各种错误. ...

  6. HTML5新技术FormData提交表单数据

    免去了你每次都要document.getElement的方式去获取input的表单值 传统方式 新技术表单数据提交 FormData使用注意 .无需调用setRequestHeader()方法 .要求 ...

  7. 解决 ln -s 软链接产生的Too many levels of symbolic links错误

    参考: ln -s 软链接产生Too many levels of symbolic links错误 解决 ln -s 软链接产生的Too many levels of symbolic links错 ...

  8. ubuntu中可以ping通IP地址但是ping不通域名的问题(www.baidu.com)

    治标不治本的办法:每次开机后执行sudo /etc/init.d/resolvconf restart就可以ping通. 治本方法见原博:https://blog.csdn.net/WFping518 ...

  9. Memcache_分布式缓存

    一. Memcache简介 1. 什么要用到Memcache以及该能解决什么问题 高并发访问数据库的痛楚:死锁! 磁盘IO之痛 多客户端共同缓存 NET+Memory>>IO 读写性能完美 ...

  10. 如何在nginx容器中使用ping、nslookup、ip、curl 等工具?

    Nginx镜像太精简了,启动一个容器进行测试时,常用的网络工具都没有,可以使用下面的命令进行安装.也可以直接起一个busybox容器进行测试. apt update #ping apt install ...