C# 读写横河PLC 读写 Yokogawa PLC 读写数据,读取PLC信息 读取特殊的模块信息

本文将使用库技术来读写横河PLC数据,使用的是基于横河自身协议实现,不需要额外的组件,读取操作只要放到后台线程就不会卡死线程,本组件支持超级方便的高性能读写操作

 github地址:https://github.com/dathlin/HslCommunication 如果喜欢可以star或是fork,还可以打赏支持,打赏请认准源代码项目。

联系作者及加群方式:http://www.hslcommunication.cn/Cooperation 

 

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

1
Install-Package HslCommunication

   

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

 

组件的完整信息和API介绍参照: http://api.hslcommunication.cn  组件的使用限制,更新日志,都在该页面里面。

 

如果你需要在读取PLC数据之后,还要群发客户端来实现远程办公室同步监视,可以参考如下的项目(基于该组件扩展起来的,带有账户验证,版本控制,数据群发,公告管理等等功能)

https://github.com/dathlin/ClientServerProject

 

本文将展示如何配置网络参数及怎样使用代码来访问PLC数据,希望给有需要的人解决一些实际问题。主要对基恩士的数据进行读写操作,具体的参照下面的地址信息

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

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

1
2
using HslCommunication;
using HslCommunication.Profinet.Yokogawa;

  

随便聊聊


当我们一个上位机需要读取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

 

关于两种模式


在PLC端,包括三菱,西门子,欧姆龙,横河以及Modbus Tcp客户端的访问器上,都支持两种模式,短连接模式和长连接模式,现在就来解释下什么原理。

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

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

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

 

关于日志记录


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

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

 

访问测试项目


下面的一个项目是这个组件的访问测试项目,您可以进行初步的访问的测试,免去了您写测试程序的麻烦,三菱的界面和西门子的界面几乎是一致的。可以同时参考。该项目位于本篇文章开始处的Gitbub源代码里面的

下载地址为:HslCommunicationDemo.zip 

 

 

 

演示项目


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

https://github.com/dathlin/RemoteMonitor

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

 

 安卓演示项目:

 

 

 请加群下载,或是在华为,小米,应用宝等APP应用商店搜索HslCommunicaition 进行下载安装!

 

代码篇


具体的API文档地址:http://api.hslcommunication.cn/html/31845cf4-eb9e-f801-f6b8-c2759f9b9a5b.htm

下面也做一些说明

关于支持的地址:

 

 

 

对于所有的数据读写,我们分为两大类,读写Bool数据,读写字节数据。对应的方法分别是

1
2
3
4
OperateResult<bool[]> ReadBool( string address, ushort length )
OperateResult<bool> ReadBool( string address )
OperateResult Write( string address, bool[] value )
OperateResult Write( string address, bool value ) 

这类方法都是读写线圈的,针对的是X,Y,I,E,M,T,C,L线圈。

而其他的Read(string address, ushort length) 和写入,读取其他类型的都是寄存器的

 

 

 

好了。先从实例化开始

1
private YokogawaLinkTcp yokogawa = new YokogawaLinkTcp( "127.0.0.1", 12289 );

  

实例化之后就需要连接PLC了

1
2
3
4
5
6
7
8
9
10
OperateResult connect = yokogawa.ConnectServer( );
if (connect.IsSuccess)
{
    MessageBox.Show( "连接成功" );
}
else
{
    MessageBox.Show( "连接失败" );
}
                

  

连接的时候可能会失败,因为网络等等的原因,所以需要连接判断。连接成功之后,就可以进行读写数据了。我们先来看看如何读取一个X的点位信息

1
2
3
4
5
6
7
8
9
OperateResult<bool> read = yokogawa.ReadBool( "X0" );
if (read.IsSuccess)
{
    bool value = read.Content; // true 表示 通, false 表示 断
}
else
{
    Console.WriteLine( "Read failed: " + read.Message );
}

因为X的点位不能写入操作,所以下面写入Y信号。

1
2
3
4
5
6
7
8
9
OperateResult write = yokogawa.Write( "Y0", true );
if (write.IsSuccess)
{
    Console.WriteLine( "Write success! " );  // 写入成功
}
else
{
    Console.WriteLine( "Write failed: " + write.Message );
}

  

如果我要批量读取点位信息呢?

1
2
3
4
5
6
7
8
9
OperateResult<bool[]> readArray = yokogawa.ReadBool( "X0", 20 );
if (readArray.IsSuccess)
{
    bool[] value = readArray.Content; // 一个数组value[0] 就是X0, 按照索引依次往后对应
}
else
{
    Console.WriteLine( "Read failed: " + readArray.Message );
}

  

批量写入数组也是类似的。

1
2
3
4
5
6
7
8
9
OperateResult writeArray = yokogawa.Write( "Y0", new bool[] { true, false, true, false, false } );
if (writeArray.IsSuccess)
{
    Console.WriteLine( "Write success! " );  // 写入成功  Y0=true, Y1=false, Y2=true, Y3=false, Y4=false
}
else
{
    Console.WriteLine( "Write failed: " + writeArray.Message );
}

 

线圈的操作都是相似的,除了地址不一样,其他的操作都是类似的。我们再来看看寄存器的操作。

1
2
3
4
5
6
7
8
9
OperateResult<short> read = yokogawa.ReadInt16( "D0" );
if (read.IsSuccess)
{
    short value = read.Content; // value 就是D0的值
}
else
{
    Console.WriteLine( "Read failed: " + read.Message );
} 

  当然了,PLC在D0存储的不一定是整数值,有可能是个浮点数

1
2
3
4
5
6
7
8
9
OperateResult<float> readfloat = yokogawa.ReadFloat( "D0" );
if (readfloat.IsSuccess)
{
    float value = readfloat.Content; // value 就是D0的值
}
else
{
    Console.WriteLine( "Read failed: " + readfloat.Message );
}

 如果是写入,也是同理。

 

1
2
3
4
5
6
7
8
9
OperateResult write = yokogawa.Write( "D0", (short)123 );
if (write.IsSuccess)
{
    Console.WriteLine( "write success" ); // 写入成功
}
else
{
    Console.WriteLine( "write failed: " + write.Message );
}

  

写入浮点数也是同理,这里就不赘述了:

1
yokogawa.Write( "D0", 123f )

 

读取连续的short数组, float数组?

1
2
3
4
5
6
7
8
9
OperateResult<short[]> readArray = yokogawa.ReadInt16( "D0", 10 );
if (readArray.IsSuccess)
{
    short[] value = readArray.Content; // value[0] 就是D0的值, value[1] 就是D1的值,以此类推
}
else
{
    Console.WriteLine( "Read failed: " + readArray.Message );
}

float数组的读取也是类似的,也是加一个length。

1
yokogawa.ReadFloat( "D0", 10 );

  

批量的写入也是类似的。

1
2
3
4
5
6
7
8
9
OperateResult writeArray = yokogawa.Write( "D0", new short[] { 123, 456, 789, 1234 } );
if (writeArray.IsSuccess)
{
    Console.WriteLine( "write success" ); // 写入成功
}
else
{
    Console.WriteLine( "write failed: " + writeArray.Message );
}

  

我们来看一个高级点的操作,我们要读取不通的线圈的点位信息,怎么操作?

1
2
3
4
5
6
7
8
9
10
11
12
13
// 使用随机读取的方式读取不同地址的数据信息
OperateResult<bool[]> read = yokogawa.ReadRandomBool( new string[] { "X0", "Y100", "M200", "M1000" } );
if (read.IsSuccess)
{
    bool x_0 = read.Content[0];
    bool y_100 = read.Content[1];
    bool m_200 = read.Content[2];
    bool m_1000 = read.Content[3];
}
else
{
    Console.WriteLine( "Read failed, reason: " + read.Message );
}

  

写入也是类似的:

1
2
3
4
5
6
7
8
9
10
11
OperateResult write = yokogawa.WriteRandomBool( new string[] { "X0", "Y100", "M200", "M1000" },
    new bool[] { true, false, false, true } );
if (write.IsSuccess)
{
    Console.WriteLine( "write plc success!" );
}
else
{
    Console.WriteLine( "write failed:" + write.Message );
    return;
}

  

读取特殊模块的信息

1
2
3
4
5
6
7
8
9
10
11
// 读取PLC的特殊模块的地址数据
OperateResult<byte[]> read = yokogawa.ReadSpecialModule( 1, 2, 100, 2 );
if (read.IsSuccess)
{
    // 我们读取到了原始的数据内容
    byte[] content = read.Content;
}
else
{
    Console.WriteLine( "Read failed, reason: " + read.Message );
}  

写入也是类似

1
2
3
4
5
6
7
8
9
10
OperateResult<short> readInt16 = yokogawa.ReadInt16( "Special:unit=1;slot=2;100" );
if (readInt16.IsSuccess)
{
    Console.WriteLine( "Read D100: " + readInt16.Content );
}
else
{
    Console.WriteLine( "Read failed, reason: " + readInt16.Message );
    return;
}

  

当然了,本组件支持读PLC的基本信息,报警信息,更详细的参考API文档。

如果你没有相关的PLC信息,却又想进行相关测试的,可以使用HSL来构建虚拟PLC

 

 

具体参考类 YokogawaLinkServer

API说明地址为:http://api.hslcommunication.cn/html/ab5927f5-b6a1-d76a-7c06-10cbcca7ac37.htm

 

posted @   dathlin  阅读(3390)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示