C#使用S7NetPlus以及PLCSIM Advanced V3.0实现西门子PLC仿真通讯

PLCSIM Advanced 简介

PLCSIM Advanced是西门子推出的一款功能强大的仿真软件,目前最新发布的版本为4.0,但鉴于新版本可能存在未知的bug,故本文使用V3.0。

V3.0支持仿真1500PLC及ET 200SP,可实现Socket网络通讯功能,也可实现PLC之间、PLC与设备直接的ModbusTCP等通讯。

V3.0安装时需要先安装WinPcap_4_1_3,V4.0则不需要。

以下为两个版本的官网下载链接,下载时需要西门子账号,可以免费注册。

以下为V3.0下载链接:

PLCSIM Advanced V3.0

V3.0的两个升级包(可选安装)

以下为V4.0下载链接

PLCSIM Advanced V4.0


S7 Net Plus 简介

西门子PLC通讯库,支持200、200smart、300、400、1200、1500系列PLC。

GitHub项目地址

说明文档


配置PLCSIM Advanced

打开PLCSIM Advanced V3.0,如下图:

Online Access要选择右边的PLCSIM Virtual Eth.Adapter,左侧的PLCSIM不支持外部网络访问。

TCP/IP communication with 可选以太网或者是本地虚拟网卡。local即为本地虚拟网卡,是在安装PLCSIM Advanced时自动安装的网络适配器。打开控制面板-->网络和 Internet-->网络连接,Siemens PLCSIM Virtual Ethernet Adapter就是此虚拟网卡。使用虚拟网卡只能在本机进行通讯仿真,而使用以太网则可以在局域网内进行仿真通讯。

Start Virtual S7-1500 PLC为PLC设置,包括IP地址、子网掩码、默认网关及PLC型号。设置完成后点击Start按钮则会生成一个PLC实例。创建成功后就可以开始通讯仿真了。

Virtual SIMATIC Memory Ca为打开保存PLC历史记录的文件夹的按钮。

如下图所示,在Active PLC Instance(s)可以看到已成功创建的PLC。


下载测试DB块

在TIA Protal软件中,添加一个S7-1511的设备,然后在程序块中添加一个新的DB块,DB号设置为10。

打开设备的属性 --> 防护与安全 -->连接机制,勾选“允许来自远程对象的PUT/GET通讯访问”。

打开设备的属性 --> PROFINET 接口 [X1] -->以太网地址,按需设置PLC的IP地址。

打开DB10的属性,取消勾选“优化块的访问”,并在DB10中新建如下图所示的变量,编译完成后则可以得到每个变量的偏移量,即此变量在DB10上的地址。

设置完成后,下载到刚刚使用PLCSIM Advanced创建的仿真PLC中,需要注意网段要设置成与仿真PLC同一网段。


引用S7NetPlus

创建一个测试程序,此处创建的是一个控制台应用程序。

在NuGet下载S7NetPlus,如下图所示,版本可按需选择

新建一个名为PLCInstance的类,创建PLC单例。

    class PLCInstance{private PLCInstance(){plcObj = new Plc(CpuType.S71500, "192.168.10.230", 0, 1);}/// <summary>/// PLC单例/// </summary>public static PLCInstance Instance{get{return Nested.instance;}}/// <summary>/// 防止调用此类静态方法时,创建新的实例/// </summary>private class Nested{internal static readonly PLCInstance instance = null;static Nested(){instance = new PLCInstance();}}/// <summary>/// 私有PLC单例对象/// </summary>private static Plc plcObj;/// <summary>/// 连接至PLC并返回连接状态/// </summary>/// <returns></returns>private bool ConnectToPLC(){try{plcObj.Open();return plcObj.IsConnected ? true : false;}catch (Exception){return false;}}/// <summary>/// 关闭连接/// </summary>private void Disconnect(){plcObj.Close();}}

读写数据

S7NetPlus提供了多种读写的方式,可以读取字节自行解析或者按照指定格式写入字节,也可以指定地址进行读写,还可以使用变量、结构体或者类进行单个或者批量读写。

1、指定地址读写

这种方法可以在Read方法中以字符串形式传入需要读取的地址,返回的是Object类型的值,需要使用者自行做类型转换。Write方法则同理,以字符串的形式指定需要写入的地址,并在第二个参数传入需要写入的值,但是需要注意西门子PLC内的数据类型与C#的数据类型的对应。以下为读写DB10的0.0地址上的布尔量的值示例,此方式均支持读取与写入。

//读取
bool result = (bool)plc.Read("DB10.DBX0.0");//写入
plc.Write("DB10.DBX0.0",!result);

虽然这种方式比较简单且方便,但是它是作者不推荐的方式,文档中原文如下:

This method reads a single variable from the plc, by parsing the string and returning the correct result. While this is the easiest method to get started, is very inefficient because the driver sends a TCP request for every variable.

意思就是,这种方法会通过解析传入的地址字符串来获取需要读写的地址,对于使用者来说是非常简单的使用方式,但是S7NetPlus会为每个通过这种方式读写的变量生成一个新的TCP请求,因此在读写多个变量时,执行效率会比较低。

S7NetPlus使用的通讯本质上是西门子的S7通讯,通过发送七层通讯报文来建立与西门子PLC的TCP连接,后续也是根据S7通讯的通讯协议生成并发送报文来实现PLC的数据读写。所以当使用这种方式读写多个变量的时候,S7NetPlus内部为每个变量重复建立新的S7连接与发送读写报文的操作,而不是单个连接成功建立后在这个连接上进行批量的读写。

简单理解就是这种方式效率比较低,会占用更多的资源。

2、解析读写

这种方法需要指定DB的类型、DB号、起始地址、PLC数据类型及读取数量。虽然它需要传入的参数变多了,但是当需要读取多个地址连续且类型相同的变量时,仅需修改最后的读取数量,S7NetPlus就会自动读取这一连串的地址,并按照指定的变量类型解析出对应的值,文档中后面说到的多类型变量批量读取也是基于这种方法的。不过这种方式读取PLC内的字符串类型时,仍存在bug,所以当需要读写字符串的时候,推荐使用本文后面提及的字节读写的方式。

示例如下:

//读取
bool result = (bool)plc.Read(DataType.DataBlock, 10, 0, VarType.Bit, 1);//写入
plc.Write(DataType.DataBlock, 10, 0, true);

Read:

第一个参数是DB的数据类型,可以是DB、定时器、计数器、Merker(内存)、输入、输出。

第二个参数是DB号。

第三个参数是起始地址。

第四个参数是PLC内该变量的类型。

第五个参数是需要读取的个数。

Write:

第一个参数是DB的数据类型,可以是DB、定时器、计数器、Merker(内存)、输入、输出。

第二个参数是DB号。

第三个参数是起始地址。

第四个参数是需要写入的值。

3、字节读写

这种方法将会读取指定DB块上一段连续的地址上的字节,不做任何解析直接以字节数组的形式返回。

第一个参数是DB的数据类型,可以是DB、定时器、计数器、Merker(内存)、输入、输出。

第二个参数是DB号。

第三个参数是起始地址。

第四个参数是读取的字节数。

要使用这种方式读写数据,则需要非常熟悉PLC内各类型数据存储的格式,可以自行将读取上来的字节进行解析以获得所需数据。

虽然这种方式理论上能读写任意的数据,但是解析数据的过程会比较麻烦,所以若非万不得已,个人建议尽量少用。

此处仅提供PLC内String类型及WString类型的读取示例。

//String读取
byte[] data = plc.ReadBytes(DataType.DataBlock, 10, 2, 254);
string result = Encoding.Default.GetString(data);
//Wstring读取
byte[] data = plc.ReadBytes(DataType.DataBlock, 10, 4, 508);
string result = Encoding.BigEndianUnicode.GetString(data);

在S7-1500中,一个String类型的变量占用256个字节,但是第一个字节是总字符数,第二个字节是当前字符数,所以真正的字符数据是从第三个字节开始的,共254个字节。

同理,WString类型其实就是双字节的Sring,也就是说一个字符占用两个字节,所以一个WString类型的变量占用512个字节,第一、二个字节是总字符数,第三、四个字节是当前字符数,真正的字符数据是从第五个字节开始的,共508个字节。

按照以上示例的方法,读取上来的字符串后面会带很多个"\0"的字符,那是因为后面的空字节也读取上来了,正式使用时可以考虑使用.Replace("\0", "")来去除,或者解析第二个字节来获取字符长度进而转码。

当写入字符串时,则需要根据不同的数据类型来生成对应字符串的字节数组,然后将该数组写入到指定地址中即可。

需要注意的是,String类型的编码格式对应的是ASCII,而WString的则是C#中的BigEndianUnicode格式。在WString中,由于总长度与当前字符数是都是双字节数,所以在转换成字节数组的时候存在高低字节顺序问题。在这里就有一个大坑:这两个变量在C#中转换出来的字节数组跟PLC中存储的,高低字节是反过来的。这也就是为什么下面的WString的示例中需要对总字符数和当前字符数的两个字节数组进行反转。

此处提供一种生成String类型和WString的字节数组的方法,可供参考:

        /// <summary>/// 获取西门子PLC字符串数组--String/// </summary>/// <param name="str"></param>/// <returns></returns>private byte[] GetPLCStringByteArray(string str){byte[] value = Encoding.Default.GetBytes(str);byte[] head = new byte[2];head[0] = Convert.ToByte(254);head[1] = Convert.ToByte(str.Length);value = head.Concat(value).ToArray();return value;}/// <summary>/// 获取西门子PLC字符串数组--WString/// </summary>/// <param name="str"></param>/// <returns></returns>private byte[] GetPLCWStringByteArray(string str){byte[] value = Encoding.BigEndianUnicode.GetBytes(str);byte[] head = BitConverter.GetBytes((short)508);byte[] length = BitConverter.GetBytes((short)str.Length);Array.Reverse(head);Array.Reverse(length);head = head.Concat(length).ToArray();value = head.Concat(value).ToArray();return value;}

使用示例如下:

//写入String 
string str = "Example";
plc.Write(DataType.DataBlock, 10, 0, GetPLCStringByteArray(str));
//写入WString
string str = "示例";
plc.Write(DataType.DataBlock, 10, 0, GetPLCWStringByteArray(str));

4、旧版本的字节读取注意事项

旧版本的单次字节读取是有字节数限制的,每一次读取的最大字节数为200,如果需要读写更多的字节,则需要多次读写并进行拼接,以下提供两种方法,可供参考:

        /// <summary>/// 循环读取/// </summary>/// <param name="numBytes">要读取的字节数</param>/// <param name="db">DB号</param>/// <param name="startByteAdr">起始地址</param>/// <returns></returns>private byte[] CyclicReadMultipleBytes(int numBytes, int db, int startByteAdr = 0){byte[] resultBytes = new byte[0];int index = startByteAdr;while (numBytes > 0){var maxToRead = Math.Min(numBytes, 200);byte[] bytes = plc.ReadBytes(DataType.DataBlock, db, index, maxToRead);if (bytes == null)return null;resultBytes = resultBytes.Concat(bytes).ToArray();numBytes -= maxToRead;index += maxToRead;}return resultBytes;}/// <summary>/// 递归读取/// </summary>/// <param name="numBytes">要读取的字节数</param>/// <param name="db">DB号</param>/// <param name="startByteAdr">起始地址</param>/// <returns></returns>public static byte[] RecursiveReadMultipleBytes(int numBytes, int db, int startByteAdr = 0){byte[] result = new byte[0];if (numBytes > 200){byte[] temp = plc.ReadBytes(DataType.DataBlock, db, startByteAdr, 200);numBytes -= 200;result = temp.Concat(RecursiveReadMultipleBytes(numBytes, db, startByteAdr + 200)).ToArray();}else{byte[] temp = plc.ReadBytes(DataType.DataBlock, db, startByteAdr, numBytes);result = result.Concat(temp).ToArray();return result;}return result;}

在读取一两千个字节的情况下,这两种方法速度都差不多,递归会稍微快一点点。不过新版本没有单次读取限制,所以正常情况下是不需要这两个方法的。

5、其余读取方式

其它的读取方式可参考文档,本文不再赘述。


读取数据示例

PLCInstance:

using S7.Net;
using System;
using System.Text;namespace S7NetPlusExample
{class PLCInstance{private PLCInstance(){plcObj = new Plc(CpuType.S71500, "192.168.10.230", 0, 1);}/// <summary>/// PLC单例/// </summary>public static PLCInstance Instance{get{return Nested.instance;}}/// <summary>/// 防止调用此类静态方法时,创建新的实例/// </summary>private class Nested{internal static readonly PLCInstance instance = null;static Nested(){instance = new PLCInstance();}}/// <summary>/// 私有PLC单例对象/// </summary>private static Plc plcObj;/// <summary>/// 连接至PLC并返回连接状态/// </summary>/// <returns></returns>private bool ConnectToPLC(){try{plcObj.Open();return plcObj.IsConnected ? true : false;}catch (Exception){return false;}}/// <summary>/// 关闭连接/// </summary>private void Disconnect(){plcObj.Close();}/// <summary>/// 读取示例数据/// </summary>/// <returns></returns>public string GetPLCInfo(){if (ConnectToPLC()){StringBuilder sbr = new StringBuilder();//读取BOOL值bool boolResult = (bool)plcObj.Read(DataType.DataBlock, 10, 0, VarType.Bit, 1);//读取Int值int intResult = (short)plcObj.Read(DataType.DataBlock, 10, 2, VarType.Int, 1);//读取Real值float realResult = (float)plcObj.Read(DataType.DataBlock, 10, 4, VarType.Real, 1);//读取String值byte[] stringData = plcObj.ReadBytes(DataType.DataBlock, 10, 10, 254);string stringResult = Encoding.Default.GetString(stringData);//读取WStringbyte[] wstringData = plcObj.ReadBytes(DataType.DataBlock, 10, 268, 508);string wstringResult = Encoding.BigEndianUnicode.GetString(wstringData);Disconnect();sbr.AppendLine($"{boolResult}");sbr.AppendLine($"{intResult}");sbr.AppendLine($"{realResult}");sbr.AppendLine($"{stringResult}");sbr.AppendLine($"{wstringResult}");return sbr.ToString();                }else{return "连接PLC失败";}           }}
}

主程序:

using System;namespace S7NetPlusExample
{class Program{static void Main(string[] args){Console.WriteLine(PLCInstance.Instance.GetPLCInfo());Console.ReadKey();}}
}

运行结果:


结尾

本文简单介绍了S7 Net Plus和PLCSIM Advanced的使用,以上内容均由本人亲自实践得出的结果,但仍有可改进的的地方。S7NetPlus的文档也有非常详细的介绍,如有更复杂的读写需求,可以参考文档。

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

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

相关文章

西门子PLC与C#程序的S7.net通信

1、导入S7.net通信文件&#xff1a;打开工具->NuGet包管理器->管理解决方案得NuGet程序包&#xff0c;入下图搜索S7&#xff0c;安装S7netplus。 在程序中引用S7.Net文件 建立西门子PLC类 using System; using System.Collections.Generic; using System.Linq; using…

JAVA与西门子S7 PLC通信,方式一:S7connector

背景 在公司项目中&#xff0c;需要用到和PLC进行通讯&#xff0c;经过搜索后查询到使用JAVA与PLC通信两种方式&#xff0c;测试后达到正常读写的目的&#xff0c;于是记录下学习过程。 环境 SpringSpringMVCMybatisPlus / SpringBoot PLC: 西门子 S7-1500/S7-1200(1214C) …

汇川PLC和PLC之间ModebusTCP通讯

目录 一、AM402做主站和H3U通讯 1、Modebus主站中组态配置 2、读从站寄存器配置 3、写从站寄存器配置 4、程序中使用对从站读写操作的寄存器值 &#xff08;1&#xff09;I/O映射中地址关联 &#xff08;2&#xff09;创建自定义全局变量 &#xff08;3&#xff09;程序…

倍福TwinCAT3上位机与PLC通信测试(ADS通信) 包含C#和C++代码

倍福TwinCAT3上位机与PLC通信测试(ADS通信) 包含C#和C代码 倍福TwinCAT3上位机与PLC通信测试(ADS通信) 包含C#和C代码 本次测试需要环境&#xff1a; VS2013&#xff0c;TwinCAT3&#xff08;本人版本TC31-Full-Setup.3.1.4018.16&#xff09; 代码&#xff1a;C#代码&…

C#使用S7netPlus与PLC通讯(超简单)

前言 刚接到手一个项目&#xff0c;是开发一款程序&#xff0c;要和PLC有数据交互&#xff0c;如上图&#xff0c;设备发生故障后&#xff0c;PLC会发电报&#xff0c;我们收到电报后把故障显示出来&#xff0c;同时点击解除故障&#xff0c;也会给PLC发送相对应的电报。查了蛮…

C#与西门子PLC通信上位机程序

1.该程可以实现c#与西门子全系列plc(200smart&#xff0c;300&#xff0c;400&#xff0c;1200&#xff0c;1500)的以太网s7通讯&#xff0c;通讯传输快稳定。 2.该程序采用.dll动态链接库方式&#xff0c;是最近几年才出来的一种与西门子plc通讯的方式&#xff0c;本人经过几个…

C#中使用S7.net与西门子PLC通讯

最近因为工作的原因用到了西门子PLC&#xff0c;在使用过程中一直在思考上位机和PLC的通讯问题&#xff0c;后来上网查了一下&#xff0c;找到了一个专门针对S7开发的一个.net库–《S7netPlus》&#xff0c;PLC通讯方法比较多&#xff0c;所以也是在不断地学习中&#xff0c;以…

C#调用PCHMI与西门子PLC连接通讯

文章目录 一、PCHMI环境配置二、PCHMI连接S7&#xff08;PLC&#xff09;三、标签与按钮的使用总结 一、PCHMI环境配置 创建一个新项目 打开项目属性&#xff0c;更改输出路径为"bin\binexe"下 工具箱新建个选择卡&#xff0c;我们命名为PCHMI 鼠标右键【选择项】…

第三方调试助手的与S7-1200 PLC的通信

1、概述 西门子S7-1200 PLC支持多种协议通过以太网通讯方式&#xff0c;如OPC、TCP、S7、MODBUS-TCP等。TCP方式相比其它协议&#xff0c;具有更多的灵活性&#xff0c;更快的数据响应等优点&#xff0c; 需要PLC与电脑还有其他设备进行TCP通讯&#xff0c;使用TCP调试助手与…

TIA 博图 使用 S7通讯 Put Get 对两台PLC进行通讯

1.打开设备组态-属性-找到防护与安全&#xff1a; 把允许来自远程的PUT/GET 通讯访问✔&#xff0c;两台PLC都是这样&#xff0c;把组态下载进去。 2.设备与网络中&#xff0c;用端口1把两台设备连在一起&#xff1a; 两台设备需要在同一个网段里面 3.在PLC3新建一个DB块&#…

文心一言 VS 讯飞星火 VS chatgpt (23)-- 算法导论4.2 5题

五、V.Pan 发现一种方法&#xff0c;可以用 132 464 次乘法操作完成 68 x 68 的矩阵相乘&#xff0c;发现另一种方法&#xff0c;可以用 143 640 次乘法操作完成 70 x 70 的矩阵相乘&#xff0c;还发现一种方法&#xff0c;可以用155 424次乘法操作完成 72 x 72 的矩阵相乘。当…

【Python爬虫项目实战二】Chatgpt还原验证算法-解密某宝伪知网数据接口

目录 🐱背景🐱工具🐱分析流程🐔登陆分析🐔检索分析🐔模拟HTML代码请求🐔 解析HTML🐔 再次分析🐟分析js算法🐟 拿下furl🐟拿下sfname🐟拿下sfname🐔 构造请求🐔再次瓶颈🐔分析cookie🐟 成功演示🐱总结

[云炬python3玩转机器学习]6-2模拟梯度下降法

模拟梯度下降法 In [1]: import numpy as np import matplotlib.pyplot as plt import datetime;print (Run by CYJ,,datetime.datetime.now()) In [2]: plot_x np.linspace(-1., 6., 141) plot_xOut[2]: array([-1. , -0.95, -0.9 , -0.85, -0.8 , -0.75, -0.7 , -0.65…

OneFlow源码解析:静态图与运行时

作者&#xff5c;郑建华 更新&#xff5c;许啸宇、张文骁、成诚 OneFlow静态图的训练效率远高于动态图&#xff08;eager模式&#xff09;。本文试图通过一个简单例子&#xff0c;结合v0.8.0版本的代码&#xff0c;解读一下静态图和运行时的实现机制。 在开始之前&#xff0c;建…

infer源码阅读之yolo.cu

目录 yolo.cu注意事项一、2023/3/30更新前言1.宏定义2.Norm3.后处理3.1 affine_project3.2 decode3.2.1 decode_common3.2.2 decode_v8 3.3 nms3.4 invoker 4.预处理5.decode_mask6.AffineMatrix7.InferImpl7.1 adjust_memory7.2 preprocess7.3 load7.4 forwards 8.其它9.拓展之…

【爬虫实例】从B站和某论文网站分析python爬虫的一般编写思路———To someone

问题背景 好久没写爬虫了&#xff0c;前两天友人来问我python能不能爬论文&#xff0c;能不能告诉她爬虫的基本运行原理是什么&#xff0c;跑起来是什么样子。 我一看&#xff0c;论文爬取——爬虫最实用的场景之一&#xff0c;这不拿捏&#xff1f; 于是便尝试现场演示一番。…

【Metaverse系列一】元宇宙的奥秘

你有没有想过逃离闷热的会议室&#xff0c;瞬间移动到马尔代夫的沙滩上开会&#xff1f;开完会&#xff0c;纵身跳入大海和美人鱼捉迷藏。然后一个鲤鱼打挺直冲云霄&#xff0c;进入天宫一号开展科学研究&#xff0c;发现微重力环境下韭菜的长势喜人&#xff0c;而且在特定光照…

科大讯飞版ChatGPT测评:很好很强大

大家好&#xff0c;我是黄海广。 今天我体验到了科大讯飞版本的ChatGPT&#xff0c;这个产品凭借其强大的功能和出色的性能&#xff0c;超出了我对国产大模型的预期。 一、产品简介 这个模型全名叫讯飞星火认知大模型&#xff0c;官方是这么解释这个产品的&#xff1a; “科大讯…

七大语言模型PK,ChatGPT内容基线测评稳居第一

随着ChatGPT的爆火与流行&#xff0c;大型语言模型&#xff08;LLM&#xff09;与生成式人工智能&#xff08;AIGC&#xff09;不断跃入大众视野&#xff0c;随之也带来了许多内容风险隐患。 近日&#xff0c;知道创宇内容安全专家对互联网上流行的7款大型语言模型进行了全面和…

ChatGPT风靡全球,我们应该为未来感到担心吗?

近期&#xff0c;关于ChatGPT的话题再次引爆全网&#xff0c;不少用户加入到“玩疯了”的阵营中……有赞叹不已的、有表示惊奇的、有展示BUG的&#xff0c;但总体来说&#xff0c;ChatGPT的整体社交评价还是非常向好的。 微软CEO纳德拉就坦言&#xff0c;ChatGPT服务的风靡&…