在 C# 中实现对 PLC 软元件(如 D 寄存器、M 继电器、X/Y 输入输出等)的读写操作,核心是通过PLC 支持的通讯协议(如三菱的 SLMP、西门子的 S7 协议、Modbus 等)建立网络连接,并按协议格式构造读写指令。以下以三菱 FX5U(SLMP 协议) 和通用 Modbus 协议为例,详细说明实现方法。
一、基于三菱 SLMP 协议(以 FX5U 为例)
SLMP 是三菱专用协议,适用于 FX5U、Q 系列等 PLC,通过以太网 TCP/UDP 通讯。
1. 核心步骤
2. 代码实现(读写 D 寄存器、M 继电器)
csharp
using System;using System.Net.Sockets;using System.Linq;namespace PLCCommunication{
public class FX5U_SLMP
{
private TcpClient _tcpClient;
private NetworkStream _stream;
private string _plcIp;
private int _port = 5007; // SLMP默认端口
try
{
/// <summary>
/// 读取PLC软元件
/// </summary>
/// <param name="device">软元件类型</param>
/// <param name="startAddress">起始地址(如D100 → 100)</param>
/// <param name="count">读取数量</param>
/// <returns>读取结果(BOOL数组/M寄存器;ushort数组/D寄存器)</returns>
public object ReadDevice(DeviceCode device, ushort startAddress, ushort count)
{
if (!_tcpClient?.Connected ?? true) return null;
// 构造SLMP读命令帧
byte[] header = { 0x50, 0x00, 0x00, 0x00 }; // 报头
byte[] networkStation = { 0x00, 0xFF }; // 网络号、站号(默认广播)
byte[] reserve = { 0x00, 0x00 }; // 预留
byte[] command = { 0x04, 0x01 }; // 读命令码
ushort subCommand = (ushort)device; // 子命令码(软元件类型)
byte[] dataLength = BitConverter.GetBytes((ushort)4); // 数据长度(地址2字节+数量2字节)
if (BitConverter.IsLittleEndian) Array.Reverse(dataLength); // 转为大端模式
// 起始地址和数量(大端模式)
byte[] address = BitConverter.GetBytes(startAddress);
byte[] cnt = BitConverter.GetBytes(count);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(address);
Array.Reverse(cnt);
// 转换数据为字节数组(按软元件类型处理)
switch (device)
{
case DeviceCode.M: // M继电器(BOOL数组 → 字节数组)
bool[] mData = data as bool[];
if (mData == null) return false;
count = (ushort)mData.Length;
int mByteCount = (count + 7) / 8;
dataBytes = new byte[mByteCount];
for (int i = 0; i < count; i++)
{
case DeviceCode.D: // D寄存器(ushort数组 → 大端字节数组)
ushort[] dData = data as ushort[];
if (dData == null) return false;
count = (ushort)dData.Length;
dataBytes = new byte[count * 2];
for (int i = 0; i < count; i++)
// 构造SLMP写命令帧
byte[] header = { 0x50, 0x00, 0x00, 0x00 };
byte[] networkStation = { 0x00, 0xFF };
byte[] reserve = { 0x00, 0x00 };
byte[] command = { 0x14, 0x01 }; // 写命令码
ushort subCommand = (ushort)device;
ushort dataTotalLen = (ushort)(4 + dataBytes.Length); // 地址2 + 数量2 + 数据n
byte[] dataLength = BitConverter.GetBytes(dataTotalLen);
if (BitConverter.IsLittleEndian) Array.Reverse(dataLength);二、基于 Modbus 协议(通用 PLC)
Modbus 是通用工业协议(支持 RTU/TCP),适用于多数 PLC(如西门子 S7-1200/1500、施耐德 M340 等)。C# 中可使用NModbus库简化开发。
1. 前期准备
2. 代码实现(Modbus TCP 读写)
csharp
using System;using System.Net.Sockets;using Modbus.Device;namespace ModbusCommunication{
class ModbusClient
{
private TcpClient _tcpClient;
private IModbusMaster _master;
private string _plcIp;
private int _port = 502; // Modbus默认端口
/// <summary>
/// 读取保持寄存器(对应PLC的D寄存器)
/// </summary>
public ushort[] ReadHoldingRegisters(ushort startAddress, ushort count)
{
try
{
return _master.ReadHoldingRegisters(1, startAddress, count); // 1为从站地址
}
catch (Exception ex)
{
Console.WriteLine($"读取失败:{ex.Message}");
// 测试代码
class Program
{
static void Main(string[] args)
{
var modbus = new ModbusClient("192.168.1.10");
if (modbus.Connect())
{
// 读保持寄存器(D100对应地址100)
var data = modbus.ReadHoldingRegisters(100, 2);
// 写保持寄存器
modbus.WriteHoldingRegisters(100, new ushort[] { 123, 456 });
modbus.Disconnect();
}
}
}}三、关键注意事项
通过上述方法,C# 可灵活实现对不同 PLC 软元件的读写,适用于工业数据采集、远程监控等场景。实际开发中需根据 PLC 型号选择对应协议,并严格按照协议规范处理数据格式。

