- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
大家好,我是Edison.
作为一个工业自动化领域的程序员,不懂点PLC和上位机,貌似有点说不过去。这里我用两篇小文带你快速进入上位机开发领域。后续,我会考虑再出一个系列文章一起玩工控上位机.
上一篇:搭建PLC模拟仿真环境 。
在上一篇中,我们通过PLCSIM Advanced软件创建了一个虚拟的西门子S7-1500 PLC如下所示:
然后,我们创建了一个博途的自动化项目,和我们的虚拟PLC进行了组态。在编译完成后,我们创建的数据块中的数据字段就得到了偏移量,如下图所示,0,2,4, 260就是所谓的偏移量,会在后面用到.
这里开始我们就开始使用C#创建一个Windows Form项目,然后通过S7NetPlus库来连接PLC,并读取和写入数据块中的数据,这是一个典型的上位机数据采集的场景。这里我们创建一个.NET Framework 4.8的Windows Form项目,并拖控件完成一个如下图所示的窗体应用界面:
这个窗体提供了连接和断开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(); } }
由于我们在博途项目中设置的数据块是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 表示获取到跳过偏移长度的字符 。
特别注意:string类型只能存储ascci码,需要注意,不能存储中文! 。
针对wstring,稍微简单点,但是需要注意的是获取的字符需要为254个,因为符号占用了4个字节.
和读取一样,通过Write方法即可轻松实现写入,但针对string和wstring仍然是复杂一些,这里我封装了一个S7DataWriter的静态类,提供了两个方法来获取要写入的bytes,因为它无法直接接收C#程序中的string类型.
public static class S7DataWriter { /// <summary> /// 获取西门子PLC字符串数组--String类型 /// </summary> 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; } /// <summary> /// 获取西门子PLC字符串数组--WString类型 /// </summary> 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 。
。
作者:周旭龙 。
出处:https://edisonchou.cnblogs.com 。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接.
最后此篇关于初识上位机(下):C#读写PLC数据块数据的文章就讲到这里了,如果你想了解更多关于初识上位机(下):C#读写PLC数据块数据的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试从 PLC (Beckhoff-cx5130) 获取当前时间。我试过“GETSYSTEMTIME”,但没有得到任何输出。我还尝试了“NT_GetTime”、“TIMESTRUCT”和“T_F
我很困惑plc的循环执行是否可以看作是一个被无限循环包围的程序。如果不是,它们之间有什么区别? 最佳答案 您的 while(1) 类比很好地解释了 PLC 的 循环执行 作品。 首先,您通常不需要进行
对于用 Structured Text 编写的 PLC 程序我需要一个以 ASCII 值开头的字符串 0x01 0x01 0x01 0x00 0x12 . 在 Java 中,我会这样做: String
我有一台 WAGO PFC200 750-8206,想知道是否可以用 C/C++ 编写控制逻辑代码。我知道WAGO用的是codesys runtime,codesys只支持IEC语言,但是WAGO声称
考虑以下梯形图程序,它检查连接是否启用 (A202.00),然后从 PLC 向 PC 发送消息。 文档(Omron CX-Programmer)严重缺乏对程序约定的解释。我不明白的是: 从一个节点向另
我想知道是否有任何方法可以使用自定义 C# 应用程序从 PLC 标签文件夹读取和写入值? 我已经尝试使用 Snap7,这是一个很好用的工具,实际上它已经工作了,但只是读取和写入数据 block ,而不
我正在关注使用 CIP 访问 Controller 数据的 Allen-Bradley 文档,特别是读取标签服务、写入标签服务以及有关读取/写入整个 UDT 的详细信息:https://literat
在 method 中定义 enum 时出现问题。 我正在尝试这样做: VAR enumA:(A,B,C); END_VAR 当我在 TwinCAT3 Shell (TcXaeShell) 中使
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 9
当指令序列仍在处理时,输入 X1 可以改变吗? 例如 LD X1 AND X2 OUT Y1 LD X1 // Can X1 loaded here differ from the previous
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 7年前关闭。 Improve thi
我在欧姆龙 PLC 中有一个以太网卡。有没有办法自动检查以太网卡是否正常工作?如果没有,是否有手动方法?例如,如果卡要在 PLC 上熄灭,它就会出错。但是如果卡只是失去了与服务器的信号,那么它不会出错
很难说出这里问的是什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或言辞激烈,无法以目前的形式合理回答。如需帮助澄清此问题以便可以重新打开,visit the help center . 8年前关闭
我有一个想要返回值的方法。该声明对我来说很清楚。但是如何在方法实现中分配要返回的值? 我只能考虑创建一个输出变量并使用它来将值传播给调用者。但这绝对不是我期望的返回值的工作方式: METHOD M_M
我有一个想要返回值的方法。该声明对我来说很清楚。但是如何在方法实现中分配要返回的值? 我只能考虑创建一个输出变量并使用它来将值传播给调用者。但这绝对不是我期望的返回值的工作方式: METHOD M_M
我想测量结构化文本 (ST) 程序的执行时间。与程序关联的任务以 10 毫秒的速度运行。 我如何测量执行时间? 最佳答案 您可以使用免费的 TwinCAT 库 Tc2_Utilities,它有一个功能
在单个梯级上,您可以拥有多少个输出。如果你有不止一个。它是 AND 逻辑,还是 OR 逻辑。串联,或并联。我正在尝试使用带有关闭输入指令的延迟指令计时器使六个灯闪烁。我将使用 Allen Bradle
我尝试在本地 PC 上激活我的配置,但失败了。我尝试过: 隔离我的电脑上的 1 或 2 个内核(在系统 > 实时下并重新启动电脑)并在这些内核上运行 PLC 任务。当我这样做时,我收到以下错误: 'T
定时器在 PLC 结构化文本 (ST) 中如何工作?我们如何声明它们? 我一直在研究PLC的标准(IEC 61131-3),他们没有谈到ST中的定时器。我知道绝大多数 PLC 程序员都是用梯形图逻辑来
我有一个有趣的问题(我希望如此)我正在尝试使用 IP、端口、机架和 SLot 使用套接字连接在西门子 S7 300 PLC 和我的 java 程序之间建立通信虽然我可以从套接字建立连接,从特定的数据库
我是一名优秀的程序员,十分优秀!