Introduction to HMI (Part 2): Reading and Writing PLC Data Blocks with C#

Introduction to HMI (Part 2): Reading and Writing PLC Data Blocks with C#

Hello everyone, I am Edison.

As a programmer in the field of industrial automation, it seems a bit unreasonable not to understand PLCs and HMIs. Here, I will use two short articles to quickly introduce you to the field of HMI development. In the future, I will consider publishing a series of articles to explore industrial control HMIs together.Previous article: Setting up a PLC Simulation EnvironmentLet’s review

In the previous article, we created a virtual Siemens S7-1500 PLC using the PLCSIM Advanced software as shown below:

Introduction to HMI (Part 2): Reading and Writing PLC Data Blocks with C#

Then, we created an automation project in TIA Portal and configured it with our virtual PLC. After compilation, the data fields in the data block we created obtained their offsets, as shown in the figure below. 0, 2, 4, 260 are the so-called offsets, which will be used later.Introduction to HMI (Part 2): Reading and Writing PLC Data Blocks with C#

Creating a Windows Form Project

Here we will start by creating a Windows Form project in C#, and then use the S7NetPlus library to connect to the PLC and read and write data in the data block. This is a typical scenario for HMI data acquisition.We will create a Windows Form project targeting .NET Framework 4.8 and design a form application interface as shown in the figure below:

Introduction to HMI (Part 2): Reading and Writing PLC Data Blocks with C#

This form provides options to connect and disconnect from the PLC, as well as read and write data from the text boxes. Next, we will implement these functionalities.

Implementing PLC Connection and Disconnection

To implement the connection and operation of the S7 PLC, there are already many mature components available. Here, we will use the S7NetPlus component, which can be easily installed via NuGet.

Introduction to HMI (Part 2): Reading and Writing PLC Data Blocks with C#

Then, we will write the Click event for the Connect button as follows:

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();  }}

Implementing Reading from PLC Data Blocks

Since the data block we set in the TIA Portal project is DB01 and contains only 4 fields, we will write the Click event for the ReadData button as follows. It reads the specified type of data by specifying parameters and binds it to the Text of the text boxes.

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 indicates reading the length of the offset  var str01Data = Encoding.Default.GetString(s7Instance.ReadBytes(DataType.DataBlock, 1, 4 + 2, count)); // +2 indicates reading the character length of the offset  txtStr01.Text = str01Data;  // wstring  var str02Data = (string)s7Instance.Read(DataType.DataBlock, 1, 260, VarType.S7WString, 254);  txtStr02.Text = str02Data;}

(1) For bool and int types, we can quickly read them directly using the Read method, but we need to provide the PLC with the correct read/write position and data type, especially ensuring that the offsets are correct.

The parameters of the Read method are the data block type, data block, offset, read type, and read length.

(2) For string and wstring types, it is a bit more complicated:For string,we need to first obtain the length of the string value.Then get the specific byte values.Convert to UTF-8 format ASCII code,as shown in the code.

+1 indicates obtaining the length

+2 indicates obtaining the characters that skip the offset length

var count = (byte)s7Instance.Read(DataType.DataBlock, 1, 4 + 1, VarType.Byte, 1); // +1 indicates reading the length of the offset
var str01Data = Encoding.Default.GetString(s7Instance.ReadBytes(DataType.DataBlock, 1, 4 + 2, count)); // +2 indicates reading the characters that skip the offset

Note: The string type can only store ASCII codes, so please note that it cannot store Chinese characters!

For wstring, it is slightly simpler,but it is important to note that the obtained characters must be 254 because symbols occupy 4 bytes.

Implementing Writing to PLC Data Blocks

Writing is as easy as reading, using the Write method, but for string and wstring, it is still a bit complicated. Here, I have encapsulated a static class S7DataWriter that provides two methods to obtain the bytes to be written, as it cannot directly accept string types from C# programs.

public static class S7DataWriter{  /// <summary>  /// Get Siemens PLC string array -- String type  /// </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>  /// Get Siemens PLC string array -- WString type  /// </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;  }}

Then, we can write the Click event for the Write Data button:

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);}

Demonstration of Effects

Writing is as easy as reading, using the Write method, but for string and wstring, it is still a bit complicated. Here, I have encapsulated a static class S7DataWriter that provides two methods to obtain the bytes to be written, as it cannot directly accept string types from C# programs.(1) Reading data

Introduction to HMI (Part 2): Reading and Writing PLC Data Blocks with C#

(2) Writing data

Introduction to HMI (Part 2): Reading and Writing PLC Data Blocks with C#

Conclusion

This article developed a simple Windows Form application using C# to achieve connection, data reading, and writing for the S7 PLC. Although it is just a simple demo, it illustrates the basic idea of HMI, which is data acquisition and monitoring of PLCs. Of course, there are other protocols besides S7 to achieve this purpose, such as ModBus, OPC UA, etc. We will leave those for future topics. If you are interested, please stay tuned!

Source Code

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

Introduction to HMI (Part 2): Reading and Writing PLC Data Blocks with C#Year-end summary:Edison’s 2023 Year-end SummaryDigital Transformation: My Experience in Digital Transformation in Traditional EnterprisesC# Problem Solving: Directory of C# Algorithm Problems Series.NET Interview:.NET Development Interview Knowledge System.NET Conference: 2020 China .NET Developer Conference PDF MaterialsIntroduction to HMI (Part 2): Reading and Writing PLC Data Blocks with C#

Leave a Comment