Prerequisites and Environment Setup
To establish communication between a .NET application and a Siemens S7-1200 PLC, the following environment is required:
Software:
- Visual Studio 2022 or later
- TIA Portal (with PLCSim Advanced or V16+)
- S7.Net NuGet package
Hardware:
- Siemens S7-1200 PLC (physical or simulated)
- Ethernet connection (RJ45 cable)
TIA Portal Configuraton
CPU Configuration and IP Assignment
- Create Device: Initialize a new PLC project and add the S7-1200 CPU module.
- Hardware Detection: If using physical hardware, utilize the "Online Access" feature to detect and configure the CPU automatically based on the connected device.
- IP Settings: Assign a static IP address within the same subnet as the development PC. Ensure the subnet mask and gateway are configured correctly.
- Version Compatibility: If connection attempts fail immediately, verify the firmware version. Mismatches between the projecct hardware version and the actual PLC firmware often cause connection drops. Resetting the PLC to factory settings may be necessary if version conflicts persist.
Data Block (DB) Configuration
For external access via C#, specific DB properties must be adjusted:
- Create a global data block (e.g.,
DB1). - Disable Optimized Block Access: In the DB properties, uncheck "Optimized block access". This is critical for accessing data via absolute addresses.
- Enable PUT/GET: Ensure "Permit access with PUT/GET communication" is enabled in the CPU protection settings.
- Download Changes: When modifying DB structures, download the changes to the PLC. If initialization errors occur, copy snapshot values to initial values before downloading.
Console Application Implementation
Create a new Console App project and install the S7.Net package. The following implementation demonstrates a continuous read loop.
using S7.Net;
using System;
using System.Threading;
namespace PlcCommunicationDemo
{
internal class Program
{
// Initialize PLC connection instance
private static Plc _plcClient = new Plc(CpuType.S71200, "192.168.1.50", 0, 1);
static void Main(string[] args)
{
try
{
_plcClient.Open();
Console.WriteLine("Connection established.");
while (_plcClient.IsConnected)
{
int dataBlockId = 1;
// Read integer at offset 2
var valueOffset2 = _plcClient.Read(DataType.DataBlock, dataBlockId, 2, VarType.Int, 1);
Console.WriteLine($"DB{dataBlockId}.DBW2 Value: {valueOffset2}");
// Read integer at offset 4
var valueOffset4 = _plcClient.Read(DataType.DataBlock, dataBlockId, 4, VarType.Int, 1);
Console.WriteLine($"DB{dataBlockId}.DBW4 Value: {valueOffset4}");
Thread.Sleep(2000);
Console.Clear();
}
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
finally
{
_plcClient.Close();
}
}
}
}
WinForms Interface Implementation
For interactive control, a Windows Forms application provides visual feedback and manual overrides.
Connection Toggle Logic
A button can manage the connection state, updating its appearance based on status.
private void btnToggleConnection_Click(object sender, EventArgs e)
{
if (_plcClient.IsConnected)
{
_plcClient.Close();
}
else
{
_plcClient.Open();
}
UpdateConnectionVisuals();
}
Status Monitoring Timer
Use a timer to poll the connection status periodically and update UI elements without blocking the main thread.
private void statusTimer_Tick(object sender, EventArgs e)
{
UpdateConnectionVisuals();
}
private void UpdateConnectionVisuals()
{
if (_plcClient.IsConnected)
{
btnToggleConnection.BackColor = Color.Lime;
btnToggleConnection.Text = "Connected";
}
else
{
btnToggleConnection.BackColor = Color.Silver;
btnToggleConnection.Text = "Disconnected";
}
}
Data Manipulation
Buttons can toggle boolean values within the PLC data block.
private void btnToggleBit_Click(object sender, EventArgs e)
{
// Read current boolean state
bool currentState = (bool)_plcClient.Read("DB1.DBX0.0");
// Write inverted state
_plcClient.Write("DB1.DBX0.0", !currentState);
// Update UI text box
txtStatusDisplay.Text = $"DB1.DBX0.0: {!currentState}";
// Visual feedback on button
btnToggleBit.BackColor = !currentState ? Color.Lime : Color.Gray;
}
Data Type Mapping and Common Pitfalls
Integer Precision
A critical distinction exists between C# and PLC data types:
- C#
int: 32-bit. - PLC
INT/WORD: 16-bit.
When writing to a PLC INT address, cast C# integers to short to prevent data corruption or zero-values.
// Correct casting for PLC INT (16-bit)
_plcClient.Write(DataType.DataBlock, 1, 2, (short)66);
// Reading back
var retrievedValue = _plcClient.Read(DataType.DataBlock, 1, 2, VarType.Int, 1);
Floating Point Numbers
PLC REAL types correspond to 32-bit floats, whereas C# double is 64-bit. Explicit casting is required.
// Correct casting for PLC REAL (32-bit)
_plcClient.Write(DataType.DataBlock, 1, 6, (float)62.5);
String Conversion
When displaying non-string data types in text boxes, explicitly call .ToString() to avoid casting exceptions.
txtStatusDisplay.Text = _plcClient.Read("DB1.DBX0.0").ToString();
Array Operations
Reading multiple consecutive values requires specifying the count and casting the result to the appropriate array type.
int dbIndex = 1;
short[] buffer = new short[10];
// Read 10 consecutive INT values starting at offset 2
buffer = (short[])_plcClient.Read(DataType.DataBlock, dbIndex, 2, VarType.Int, 10);
foreach (var item in buffer)
{
Console.WriteLine(item);
}