大家好,我是Edison。

作为一个工业自动化领域的程序员,不懂点PLC和上位机,貌似有点说不过去。这里我用两篇小文带你快速进入上位机开发领域。后续,我会考虑再出一个系列文章一起玩工控上位机。

上一篇:搭建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 表示获取到跳过偏移长度的字符

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

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

实现PLC数据块的写入

和读取一样,通过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数据块数据的更多相关文章

  1. .net全栈开发-c#面向对象与工控自动化分拣上位机

    一.前言 开始做了两年web.期间也整了一段时间winform.后来做了两年工控上位机,也就是做工控这两年发现机器跟面向对象真是如此贴切,也是我从处理数据和流程的思维转变为面向对象思维的开始.这对我后 ...

  2. 我编写的EEPROM 上位机软件

    进入模式: 上位机发送 消息 上位机EEPROM 按下进入模式 消息的ID号是:0x08111111 数据是: 00 01 ff 00 00 00 00 00 上位机显示 运行状态 :为进入模式 当我 ...

  3. 家居环境监測系统设计(PC上位机版)(手机APP版待定)

    下面是我的毕业设计:家居环境监測系统设计(PC上位机临时版.手机app版待定).本系统採用STC12C5A60S2单片机.结合传感器.分别对空气湿度.空气温度.气压.海拔.进水温度.出水温度.光照强度 ...

  4. (转载)西门子PLC学习笔记十五-(数据块及数据访问方式)

    一.数据块 数据块是在S7 CPU的存储器中定义的,用户可以定义多了数据块,但是CPU对数据块数量及数据总量是有限制的. 数据块与临时数据不同,当逻辑块执行结束或数据块关闭,数据块中的数据是会保留住的 ...

  5. oracle --(一)数据块(data Block)

    基本关系:数据库---表空间---数据段---分区---数据块 数据块(data Block)一.数据块Block是Oracle存储数据信息的最小单位.这里说的是Oracle环境下的最小单位.Orac ...

  6. 分布式文件系统 之 数据块(Block)

    众所周知,HDFS中以数据块(block)为单位进行存储管理.本文简单介绍一下HDFS中数据块(block)的概念,以及众多分布式存储系统(不止是HDFS)使用block作为存储管理基本单位的意义. ...

  7. Oracle 数据块

    以emp表为例 SYS@ prod>select * from scott.emp; EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO --------- ...

  8. 上位机开发之三菱Q系列PLC通信实践

    经常关注我们公众号或者公开课的学员(如果还没有关注的话,左上角点击一波关注)应该知道,我们会经常使用西门子PLC,其实对于其他品牌的PLC,我们都会讲到,包括三菱.欧姆龙.基恩士.松下及国产台达.信捷 ...

  9. C++ MFC实现基于RFID读写器的上位机软件

    C++ MFC实现基于RFID读写器的上位机软件 该博客涉及的完整工程托管在https://github.com/Wsine/UpperMonitor,觉得好请给个Star (/▽\=) 运行和测试环 ...

  10. c#上位机与三菱PLC(FX3U)串口通讯

    项目中会经常用到上位机与PLC之间的串口通信,本文介绍一下C#如何编写上位机代码 与三菱FX3U进行通讯 1. 第一种方法是自己写代码实现,主要代码如下: //对PLC的Y7进行置1 byte[] Y ...

随机推荐

  1. 掌握 C++ 中 static 关键字的多种使用场景

    static是什么 在最开始C中引入了static关键字可以用于修饰变量和函数,后来由于C++引入了class的概念,现在static可以修饰的对象分为以下5种: 成员变量,成员函数,普通函数,局部变 ...

  2. 狂神说Java——Mybatis学习笔记

    前言:配合狂神老师的教学视频使用效果更佳: https://www.bilibili.com/video/BV1NE411Q7Nx/?spm_id_from=333.1007.top_right_ba ...

  3. 部署javaweb项目到阿里云ecs(centos7)

    阿里云文档 https://help.aliyun.com/document_detail/51376.html?spm=5176.12901015.0.i12901015.af8f525cCPi8Q ...

  4. 【鸿蒙千帆起】高德地图携手HarmonyOS NEXT,开启智能出行新篇章

    2024年1月18日下午,华为举办了鸿蒙生态千帆启航仪式,对外宣布HarmonyOS NEXT星河预览版现已开放申请,同时,首批200+鸿蒙原生应用加速开发,鸿蒙生态设备数量更是突破了8亿大关.这些进 ...

  5. LTV预估的一些思考

    什么是LTV 用户生命周期价值(Lifetime Value, LTV)是一个非常重要的指标,定义为单个用户在某种生命周期内(i.e. 从开始使用产品到停止使用期间) 为产品创造的总价值. 比如GMV ...

  6. NodeJS安装cnpm

    介绍: NPM(Node Package Manager):Node的包管理器. CNPM(Chinese CPM):中国的NPM(国内使用,网速较快). 配置步骤 用npm安装cnpm npm in ...

  7. 力扣13(java)-罗马数字转整数(简单)

    题目: 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值I 1V 5X 10L 50C 100D 500M 1000例如, 罗马数字 2 写做 II ,即为两个并列的 1 ...

  8. 为什么我要迁移 SpringBoot 到函数计算

    简介: 面对流量洪峰,我们再也不会手忙脚乱了,函数计算自动会帮我们扩容!很好的解决了我们的 API 场景和不定时执行各种不同任务的场景. 作者:榴莲   为什么要迁移? 我们的业务有很多对外提供服务的 ...

  9. 实时计算pv/uv Demo

    简介: 本文由阿里巴巴高级技术专家邓小勇(静行)分享,主要用 Demo 演示如何通过实时计算 Flink 实时计算pv/uv的场景. 本文由阿里巴巴高级技术专家邓小勇(静行)分享,主要用 Demo 演 ...

  10. 免费体验!阿里云智能LOGO帮你解决设计难题

    ​简介:超实用!零基础搞定一个高大上的智能logo设计 新年过后,往往是大家一年中士气最足的时候,散去了年末的疲惫和emo,重燃对新一年的热情和希望. 想创业的朋友们同样意气风发,趁着新年的劲头想大干 ...