C#读写基恩⼠PLC使⽤TCPIP协议MC协议
本⽂将使⽤⼀个Github开源的组件库技术来读写基恩⼠PLC数据,使⽤的是基于以太⽹的TCP/IP实现,不需要额外的组件,读取操作只要放到后台线程就不会卡死线程,本组件⽀持超级⽅便的⾼性能读写操作
github地址:如果喜欢可以star或是fork,还可以打赏⽀持,打赏请认准源代码项⽬。
联系作者及加⽅式:
在Visual Studio 中的NuGet管理器中可以下载安装,也可以直接在NuGet控制台输⼊下⾯的指令安装:
Install-Package HslCommunication
如果需要教程:Nuget安装教程:
组件的完整信息和API介绍参照:组件的使⽤限制,更新⽇志,都在该页⾯⾥⾯。
如果你需要在读取PLC数据之后,还要发客户端来实现远程办公室同步监视,可以参考如下的项⽬(基于该组件扩展起来的,带有账户验证,版本控制,数据发,公告管理等等功能)
本⽂将展⽰如何配置⽹络参数及怎样使⽤代码来访问PLC数据,希望给有需要的⼈解决⼀些实际问题。主要对基恩⼠的数据进⾏读写操作,具体的参照下⾯的地址信息
此处使⽤了⽹线直接的⽅式,如果PLC接进了局域⽹,就可以进⾏远程读写了^_^
此处使⽤到了2个命名空间:
using HslCommunication.Profinet.Keyence;
using HslCommunication;
随便聊聊
当我们⼀个上位机需要读取100台西门⼦PLC设备(此处只是举个例⼦,凡是都是使⽤Modbus tcp的都是⼀样的)的时候,你采⽤服务器主动去请求100台设备的机制对性能来说是个极⼤的考验,如果开100个线程去轮询100台设备,那么性能损失将是⾮常⼤的,更不⽤说再增加设备,如果搭建Modbus tcp服务器,就可以完美的解决性能问题,因为连接的压⼒将会平均分摊给每⼀台PLC,服务器端只要新增⼀个时间戳就可以知道客户端有没有连接上。
我们在100台PLC⾥都增加发送Modbus tcp⽅法,将数据发送到服务器的ip和端⼝上去,服务器根据站
号来区分设备。这样就可以搭建⼀个⾼性能总站。本组件⽀持快速搭建⼀个⾼性能的Modbus tcp总站。
关于两种模式
在PLC端,包括三菱,西门⼦,欧姆龙以及Modbus Tcp客户端的访问器上,都⽀持两种模式,短连接模式和长连接模式,现在就来解释下什么原理。
短连接:每次读写都是⼀个单独的请求,请求完毕也就关闭了,如果服务器的端⼝仅仅⽀持单连接,那么关闭后这个端⼝可以被其他连接复⽤,但是在频繁的⽹络请求下,容易发⽣异常,会有其他的请求不成功,尤其是多线程的情况下。
长连接:创建⼀个公⽤的连接通道,所有的读写请求都利⽤这个通道来完成,这样的话,读写性能更快速,即时多线程调⽤也不会影响,内部有同步机制。如果服务器的端⼝仅仅⽀持单连接,那么这个端⼝就被占⽤了,⽐如三菱的端⼝机制,西门⼦的Modbus tcp端⼝机制也是这样的。以下代码默认使⽤长连接,性能更⾼,还⽀持多线程同步。
在短连接的模式下,每次请求都是单独的访问,所以没有重连的困扰,在长连接的模式下,如果本次请求失败了,在下次请求的时候,会⾃动重新连接服务器,直到请求成功为⽌。另外,尽量所有的读写都对结果的成功进⾏判断。
关于⽇志记录
不管是基恩⼠的,三菱的数据访问类,还是西门⼦的,还是Modbus tcp访问类,都有⼀个LogNet属性⽤来记录⽇志,该属性是⼀个接⼝类,ILogNet,凡事继承该接⼝的都可以⽤来记录⽇志,该⽇志会在访问失败时,尤其是因为⽹络的原因导致访问失败时会进⾏⽇志记录(如果你为这个 LogNet 属性配置了真实的⽇志记录器的话):如果你想使⽤该记录⽇志的功能,请参照如下的博客进⾏实例化:
访问测试项⽬
下⾯的⼀个项⽬是这个组件的访问测试项⽬,您可以进⾏初步的访问的测试,免去了您写测试程序的⿇烦,三菱的界⾯和西门⼦的界⾯⼏乎是⼀致的。可以同时参考。该项⽬位于本篇⽂章开始处的Gitbub源代码⾥⾯的
下载地址为:
地址的格式在在线⽂档⾥:
演⽰项⽬
下⾯的三篇演⽰了具体如何去访问PLC的数据,我们在访问完成后,通常需要进⾏处理,以下的⽰例项⽬就演⽰了后台从PLC读取数据后,前台显⽰并推送给所有在线客户端的功能,客户端并进⾏图形化显⽰,具有⼀定的参考意义,并且推送给⽹页前端,项⽬地址为:
下⾯的图⽚⽰例中的左边程序就是服务器程序,它应该和PLC直接连接并接⼊局域⽹,然后把数据推送给客户端显⽰。注意:⼀个复杂⾼级的程序就应该把处理逻辑程序和界⾯程序分开,⽐如这⾥的服务器程序实现数据采集,推送,存储。让客户端程序去实现数据的整理,分析,显⽰,这样即使客户端程序因为BUG奔溃,服务器端仍然可以正常的⼯
作。
基恩⼠PLC篇(本组件⽀持⼆进制和ASCII通讯,两者只是类名不同,具体的地址,⽅法都是⼀模⼀样的)
初始化访问PLC对象
注意:如果你采⽤了⼆进制读写,那么就实例化KeyenceMcNet类,如果采⽤ASCII来读写数据,请使⽤KeyenceMcAsciiNet类
如果想使⽤本组件的数据读取功能,必须先初始化数据访问对象,根据实际情况进⾏数据的填⼊。下⾯仅仅是测试中的数据:
private KeyenceMcNet keyence_net = new KeyenceMcNet( "192.168.8.13", 5000 );
打开连接,并可以判断是否连接上
keyence_net.ConnectServer( );
如果需要判断,那么按照如下的操作
OperateResult connect = keyence_net.ConnectServer( );
if (connect.IsSuccess)
{
MessageBox.Show( "连接成功!" );
}
else
{
MessageBox.Show( "连接失败!" );
}
说明:对象应该放在窗体类下⾯,此处仅仅针对读取⼀台设备的plc,也可以在访问的⽅法中实例化局部对象,初始化数据,然后读取,该对象⼏乎不损耗内存,内存垃圾由CLR进⾏⾃动回收。此处测试⽅便,窗体的多个按钮均连接同⼀台PLC 设备,所以本窗体实例化⼀个对象即可。
展⽰⼀些简单实⽤基础数据读写,这些数据的读写没有进⾏严格的是否成功判断(判断⽅法参照后⾯
的代码),⼀般⽹络良好的情况下都会成功,但不排除失败,以下代码仅作测试,所有没有严格判断是否成功:
short d100_short = keyence_net.ReadInt16( "D100" ).Content;
ushort d100_ushort = keyence_net.ReadUInt16( "D100" ).Content;
int d100_int = keyence_net.ReadInt32( "D100" ).Content;
uint d100_uint = keyence_net.ReadUInt32( "D100" ).Content;
long d100_long = keyence_net.ReadInt64( "D100" ).Content;
ulong d100_ulong = keyence_net.ReadUInt64( "D100" ).Content;
float d100_float = keyence_net.ReadFloat( "D100" ).Content;
double d100_double = keyence_net.ReadDouble( "D100" ).Content;
// need to specify the text length
string d100_string = keyence_net.ReadString( "D100", 10 ).Content;
keyence_net.Write( "D100", (short)5 );
keyence_net.Write( "D100", (ushort)5 );
keyence_net.Write( "D100", 5 );
keyence_net.Write( "D100", (uint)5 );
keyence_net.Write( "D100", (long)5 );
keyence_net.Write( "D100", (ulong)5 );
keyence_net.Write( "D100", 5f );
keyence_net.Write( "D100", 5d );
// length should Multiples of 2
keyence_net.Write( "D100", "12345678" );
如下⽅法演⽰读取了M200-M209这10个M的值,注意:读取长度必须为偶数,即时写了奇数,也会补
齐⾄偶数,读取和写⼊的最⼤长度为7168,否则报错。如需实际需求确实⼤于7168的,请分批次读取。
返回值解析:如果读取正常则共返回10个字节的数据,以下⽰例数据进⾏批量化的读取
private void test1()
{
OperateResult<bool[]> read = keyence_net.ReadBool( "M100", 10 );
if(read.IsSuccess)
{
bool m100 = read.Content[0];
// and so on
bool m109 = read.Content[9];
}
else
{
// failed
tcpip协议pdf}
}
写⼊Bool的操作
bool[] values = new bool[] { true, false, true, true, false, true, false, true, true, false };
OperateResult read = keyence_net.Write( "M100", values );
if (read.IsSuccess)
{
// success
}
else
{
// failed
}
⾼级的批量数据读取(针对连续的地址的时候效率⾮常的⾼):
private void test5( )
{
OperateResult<byte[]> read = keyence_net.Read( "D100", 10 );
if(read.IsSuccess)
{
int count = keyence_net.ByteTransform.TransInt32( read.Content, 0 );
float temp = keyence_net.ByteTransform.TransSingle( read.Content, 4 );
short name1 = keyence_net.ByteTransform.TransInt16( read.Content, 8 );
string barcode = Encoding.ASCII.GetString( read.Content, 10, 10 );
}
}
⿇烦之处需要⾃⼰写代码解析数据信息
更多详细的读写信息请关注本项⽬学习。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论