初识上位机(下):C#读写PLC数据块数据

cfdcd5fd58c4e9e121e44ce208312be9.jpeg

大家好,我是Edison。

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

上一篇:搭建PLC模拟仿真环境

复习一下

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

c25b3b92bf98f94d00cbd150d5cd759e.png

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

bd01359eae09f297cf10710927e0fb02.png

创建Windows Form项目

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

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

044c8ff3a5e16fd0c46ee1e4f5f84228.png

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

实现PLC的连接与断开

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

9c99ff84e3d77cc6a54332624968d925.png

然后编写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
{
  /// <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)读取数据

fd76bca5036d4efa3e8d7d9d1fddff48.png

(2)写入数据

b65348d15130f86226bb702372aa72fc.png

小结

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

源码

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

7fb87397b5bac1d357c34e0ec4afe241.gif

年终总结:Edison的2023年终总结

数字化转型:我在传统企业做数字化转型

C#刷题:C#刷剑指Offer算法题系列文章目录

.NET面试:.NET开发面试知识体系

.NET大会:2020年中国.NET开发者大会PDF资料

2914d1f8f4f22ee4cbb745b44c5c6f23.png

### 回答1: 我可以提供一个参考示例: import pypyodbc import mysql.connector # connect to PLC plc_conn = pypyodbc.connect('DRIVER={PLC Driver};SERVER=<IP Address>;DATABASE=<Database Name>;UID=<User Name>;PWD=<Password>') # connect to MySQL mysql_conn = mysql.connector.connect(user='<MySQL User Name>', password='<MySQL Password>', host='<MySQL Host>', database='<MySQL Database>') # execute SQL query to read data from PLC sql_query = "SELECT * FROM <PLC Table Name>" cursor = plc_conn.cursor() cursor.execute(sql_query) # write the data to MySQL mysql_cursor = mysql_conn.cursor() for row in cursor.fetchall(): mysql_cursor.execute("INSERT INTO <MySQL Table Name> VALUES (%s, %s, %s)", row) # close the connections plc_conn.close() mysql_conn.commit() mysql_conn.close() ### 回答2: 使用Python可以轻松地连接PLC设备并读取数据,并将其写入MySQL数据库。以下是实现此任务的代码示例: 首先,您需要安装Python的PLC通信库,例如pyModbus或snap7。您可以使用以下命令使用pip安装它们: ``` pip install pyModbus pip install snap7 ``` 接下来,您需要安装Python的MySQL库,例如mysql-connector-python。您可以使用以下命令使用pip安装它: ``` pip install mysql-connector-python ``` 然后,您可以使用以下代码建立与PLC设备的连接,读取数据并将其写入MySQL数据库: ```python import mysql.connector from pymodbus.client.sync import ModbusTcpClient # 连接到PLC设备 plc_ip = '192.168.1.1' # 替换为实际的PLC IP地址 plc_port = 502 # 替换为实际的PLC端口号 plc = ModbusTcpClient(plc_ip, plc_port) # 连接到MySQL数据库 db_host = 'localhost' # 替换为实际的数据库主机地址 db_user = 'root' # 替换为实际的数据库用户名 db_password = 'password' # 替换为实际的数据库密码 db_name = 'test' # 替换为实际的数据库名称 db = mysql.connector.connect(host=db_host, user=db_user, password=db_password, database=db_name) cursor = db.cursor() # 读取PLC数据 slave_id = 1 # 设置PLC的从站ID register_address = 0 # 设置要读取的寄存器地址 register_count = 10 # 设置要读取的寄存器数量 response = plc.read_holding_registers(register_address, register_count, unit=slave_id) # 将数据写入MySQL数据库 if response.isError(): print("读取数据错误:{0}".format(response)) else: data = response.registers for i in range(register_count): value = data[i] sql = "INSERT INTO plc_data (value) VALUES ({0})".format(value) # 替换为实际的插入数据的SQL语句 cursor.execute(sql) db.commit() # 关闭连接 plc.close() db.close() ``` 请确保按照实际情况修改代码中的IP地址、端口号、数据库连接信息和SQL语句。此代码示例假定PLC设备使用Modbus通信协议,并且将数据写入名为"plc_data"的表中的"value"列。 注意:以上代码示例仅为参考,并且需要根据实际情况进行修改和调整。 ### 回答3: Python提供了多种与PLC通信的库,例如`pyModbusTCP`、`pyads`等。下面是一个示例代码,可用于连接PLC并读取数据,然后将数据写入MySQL数据库: ```python import pymysql from pyModbusTCP.client import ModbusClient # 连接PLC plc_ip = 'PLC的IP地址' plc_port = PLC的端口号 plc = ModbusClient(host=plc_ip, port=plc_port) if not plc.is_open(): if not plc.open(): print("无法连接到PLC") exit() # 读取PLC数据 # 此处假设要读取的数据在寄存器地址1000-1009之间,数据类型为32位无符号整数 start_address = 1000 quantity = 10 data = plc.read_holding_registers(start_address, quantity) if data: print("从PLC读取到的数据:", data) else: print("无法读取到数据") # 连接MySQL数据库 db_host = 'MySQL数据库的IP地址' db_user = 'MySQL用户名' db_password = 'MySQL密码' db_name = '数据库名称' db = pymysql.connect(host=db_host, user=db_user, password=db_password, db=db_name) # 将数据写入MySQL cursor = db.cursor() # 假设MySQL数据库中已经创建好了一个名为"plc_data"的表,表结构为(id INT AUTO_INCREMENT PRIMARY KEY, value INT) # 将读取到的PLC数据逐一插入到数据库中 for value in data: sql = "INSERT INTO plc_data (value) VALUES ({})".format(value) cursor.execute(sql) # 提交事务 db.commit() # 断开与MySQL的连接 db.close() ``` 以上代码演示了如何使用Python通过Modbus通信协议连接到PLC并读取数据,然后使用pymysql库连接到MySQL数据库,并将数据写入数据库中。请注意,需要根据实际情况修改连接PLC数据库的相关参数,并确保PLC和MySQL数据库的可访问性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值