C#搭建西门子PLC模拟仿真环境读写PLCSIM数据块数据

360影视 动漫周边 2025-03-12 09:14 2

摘要:上位机,一般来说就是在数据采集和控制系统里处在比较高的层级,有着挺强的数据处理本事和控制功能的计算机设备。它靠着通信接口(像串口、网口啥的)跟下位机(比如说 PLC、单片机或者其他智能的设备)进行数据的交换还有指令的传达,达成对下位机的监控、配置、数据收集以及

什么是上位机

上位机,一般来说就是在数据采集和控制系统里处在比较高的层级,有着挺强的数据处理本事和控制功能的计算机设备。它靠着通信接口(像串口、网口啥的)跟下位机(比如说 PLC、单片机或者其他智能的设备)进行数据的交换还有指令的传达,达成对下位机的监控、配置、数据收集以及分析之类的功能。

简单理解,就是对PLC进行监控和数据采集分析。

建议按照WinPcap -> PLCSIM -> TIA Portal的顺序安装。

至于安装过程,可以自行搜索,或参考下列文章。所有软件仅供学习参考,本文不做详细解读:

一步到位,博图TIA下载、安装、仿真、授权 PLC论坛-全力打造可编程控制器专业技术论坛 -

http://bbs.plcjs.com/forum.php?mod=viewthread&tid=505862&fromuid=250402

配置虚拟网卡

安装完成PLCSIM Advanced后,会多一个虚拟网卡出来。

这里我们点开这个虚拟网卡,设置一下静态IP。

创建一个虚拟PLC

打开PLCSIM Advanced,按照下列步骤创建一个PLC实例。这里需要注意的实,PLC实例的IP地址需要和刚刚设置的虚拟网卡在同一个网段,这里是192.168.10.x。

创建完成后,由于PLC实例并未正式启动,因此亮黄灯。

创建博途自动化项目

接下来就是最为关键的步骤,打开博途TIA Portal,进行以下操作:

(1)创建一个项目

(2)添加PLC设备

(3)添加完成后得到项目视图

(4)为设备设置“允许来自远程对象的PUT/GET通信访问”

(5)为项目设置“块编译时支持仿真”

(6)为设备设置IP地址:下图中的IP应该是10.200哈

(7)为设备添加一个数据块,取名“DB01”

(8)添加一些字段,并点击编译按钮,编译完成后得到偏移量

(9)点击下载到设备的按钮,并选择虚拟网卡,然后搜索到我们的虚拟PLC设备,最后点击下载。

验证PLC实例状态

成功装载到设备后,我们的PLC实例的状态就会由黄灯 变为 绿灯,说明已经正常启动好了。

那么,接下来,我们就可以通过C#编写一个DEMO来读取和写入PLC的数据块中的数据了。

我们通过PLCSIM Advanced软件创建了一个虚拟的西门子S7-1500 PLC如下所示:

然后,我们创建了一个博途的自动化项目,和我们的虚拟PLC进行了组态。在编译完成后,我们创建的数据块中的数据字段就得到了偏移量,如下图所示,0,2,4, 260就是所谓的偏移量,会在后面用到。

创建Windows Form项目

这里开始我们就开始使用C#创建一个Windows Form项目,然后通过S7NetPlus库来连接PLC,并读取和写入数据块中的数据,这是一个典型的上位机数据采集的场景。

这里我们创建一个.NET Framework 4.8的Windows Form项目,并拖控件完成一个如下图所示的窗体应用界面:

这个窗体提供了连接和断开PLC,以及读取 和 写入 文本框中的数据,接下来我们就来实现这几个功能。

实现PLC的连接与断开

要实现S7 PLC的连接和操作,目前已经有很多较为成熟的组件了,我们这里使用S7NetPlus组件,直接通过NuGet安装最新版本即可。

然后编写Connect按钮的Click事件如下:

private static Plc s7Instance;public MainForm{ InitializeComponent;}private void btnConnect_Click(object sender, System.EventArgs e){ if (btnConnect.Text == "Connect") { if (s7Instance == null) s7Instance = new Plc(CpuType.S71500, txtPlcIPAddress.Text.Trim, 0, 1); s7Instance.Open; btnConnect.Text = "Disconnect"; } else { s7Instance.Close; btnConnect.Text = "Connect"; txtBool01.Clear; txtInt01.Clear; txtStr01.Clear; txtStr02.Clear; }}

实现PLC数据块的读取

由于我们在博途项目中设置的数据块是DB01,且只有4个字段,所以这里我们编写ReadData按钮的Click事件如下,它通过指定参数读取到指定类型的数据并绑定到文本框的Text中。

private void btnReadData_Click(object sender, System.EventArgs e){ if (s7Instance == null || !s7Instance.IsConnected) { MessageBox.Show("Your PLC is not connected now!", "Error", MessageBoxButtons.OK); return; } // bool var boolData = (bool)s7Instance.Read(DataType.DataBlock, 1, 0, VarType.Bit, 1); txtBool01.Text = boolData ? "1" : "0"; // int var intData = (short)s7Instance.Read(DataType.DataBlock, 1, 2, VarType.Int, 1); txtInt01.Text = intData.ToString; // string var count = (byte)s7Instance.Read(DataType.DataBlock, 1, 4 + 1, VarType.Byte, 1); // +1表示读取偏移值的长度 var str01Data = Encoding.Default.GetString(s7Instance.ReadBytes(DataType.DataBlock, 1, 4 + 2, count)); // +2表示读取偏移值(跳过)的字符 txtStr01.Text = str01Data; // wstring var str02Data = (string)s7Instance.Read(DataType.DataBlock, 1, 260, VarType.S7WString, 254); txtStr02.Text = str02Data;}

(1)针对bool和int类型,我们可以直接通过Read方法快速读取到,但需要告诉PLC准确的读写位置和数据类型,主要是偏移量一定要给正确。

Read方法的参数分别为数据块类型,数据块,偏移量,读取类型,读取长度

(2)针对string和wstring类型,就稍微麻烦一些了:

针对string,需要先获取string值的所占长度。再拿到具体byte值。转换为utf8格式的ascci码,具体代码中有体现。

+1 表示获取到长度

+2 表示获取到跳过偏移长度的字符

var count = (byte)s7Instance.Read(DataType.DataBlock, 1, 4 + 1, VarType.Byte, 1); // +1表示读取偏移值的长度var str01Data = Encoding.Default.GetString(s7Instance.ReadBytes(DataType.DataBlock, 1, 4 + 2, count)); // +2表示读取偏移值(跳过)的字符

特别注意:string类型只能存储ascci码,需要注意,不能存储中文

针对wstring,稍微简单点,但是需要注意的是获取的字符需要为254个,因为符号占用了4个字节。

实现PLC数据块的写入

和读取一样,通过Write方法即可轻松实现写入,但针对string和wstring仍然是复杂一些,这里我封装了一个S7DataWriter的静态类,提供了两个方法来获取要写入的bytes,因为它无法直接接收C#程序中的string类型。

public static class S7DataWriter{ /// /// 获取西门子PLC字符串数组--String类型 /// public static 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; } /// /// 获取西门子PLC字符串数组--WString类型 /// public static 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; }}

然后,我们就可以编写Write Data按钮的Click事件了:

private void btnWriteData_Click(object sender, System.EventArgs e){ if (s7Instance == null || !s7Instance.IsConnected) { MessageBox.Show("Your PLC is not connected now!", "Error", MessageBoxButtons.OK); return; } // bool var boolValue = txtBool01.Text.Trim == "1" ? true : false; s7Instance.Write(DataType.DataBlock, 1, 0, boolValue); // int var intValue = Convert.ToInt16(txtInt01.Text); s7Instance.Write(DataType.DataBlock, 1, 2, intValue); // string s7Instance.Write(DataType.DataBlock, 1, 4, S7DataWriter.GetPlcStringByteArray(txtStr01.Text.Trim)); // wstring s7Instance.Write(DataType.DataBlock, 1, 260, S7DataWriter.GetPlcWStringByteArray(txtStr02.Text.Trim)); MessageBox.Show("Write data successfully!", "Info", MessageBoxButtons.OK);}

效果演示

和读取一样,通过Write方法即可轻松实现写入,但针对string和wstring仍然是复杂一些,这里我封装了一个S7DataWriter的静态类,提供了两个方法来获取要写入的bytes,因为它无法直接接收C#程序中的string类型。

(1)读取数据

(2)写入数据

小结

本文通过使用C#开发了一个简单的WindowsForm窗体程序,实现了S7 PLC的连接、数据读取和写入。虽然只是一个简单的Demo,但是从中可以看见上位机的基本思想,就是对PLC的数据采集和监控。当然,实现这个目的,不止S7协议一条路,我们还可以通过ModBus、OPC UA等协议,这些就留到后面的专题吧,如果你感兴趣的话,就保持关注哦!

源码

GitHub:https://github.com/Coder-EdisonZhou/PLC-Connectors

来源:PLC技术玩

相关推荐