C# 与三菱 FX5U PLC 通过以太网基于 SLMP(Seamless Message Protocol,无缝消息协议)通讯,是工业自动化中实现上位机与 PLC 数据交互的常用方式。SLMP 是三菱专用以太网协议,支持读写 PLC 的软元件(寄存器、继电器等),以下是详细实现步骤:
一、前期准备
1. 硬件与软件环境
2. PLC 端设置(GX Works3)
二、SLMP 协议基础
SLMP 通讯通过报文帧实现数据交互,核心是构建符合格式的请求帧,PLC 响应后解析返回帧。
1. 帧结构(精简版,适用于 FX5U)
三、C# 实现步骤(基于 TCP/IP)
1. 建立 TCP 连接
通过TcpClient类与 PLC 的 5007 端口建立连接:
csharp
using System;using System.Net.Sockets;using System.Text;public class FX5U_SLMP{
private TcpClient client;
private NetworkStream stream;
private string plcIp; // PLC的IP地址
private int port = 5007; // SLMP默认端口
public FX5U_SLMP(string ip)
{
plcIp = ip;
}
// 连接PLC
public bool Connect()2. 构建 SLMP 请求帧(以读 D 寄存器为例)
需将请求参数转换为符合 SLMP 格式的字节数组:
csharp
/// <summary>/// 读取D寄存器/// </summary>/// <param name="address">寄存器地址(如100→D100)</param>/// <param name="count">读取数量</param>/// <returns>读取的值(整数数组)</returns>public int[] ReadD(int address, int count){
if (!client.Connected) return null;
// 构建请求帧
byte[] command = new byte[12];
// 指令长度(12字节)
command[0] = 0x00;
command[1] = 0x0C;
// 读指令代码(04 01)
command[2] = 0x04;
command[3] = 0x01;
// 软元件代码(D寄存器:00 02)
command[4] = 0x00;
command[5] = 0x02;
// 地址(4字节,高位在前)
byte[] addrBytes = BitConverter.GetBytes((uint)address);
Array.Reverse(addrBytes); // 转换为大端模式
Array.Copy(addrBytes, 0, command, 6, 4);
// 读取数量(2字节,高位在前)
byte[] countBytes = BitConverter.GetBytes((ushort)count);
Array.Reverse(countBytes);
Array.Copy(countBytes, 0, command, 10, 2);
// 发送请求
stream.Write(command, 0, command.Length);
// 接收响应(响应长度=8 + 2*count,8字节为头部)
byte[] response = new byte[8 + 2 * count];
int bytesRead = stream.Read(response, 0, response.Length);
// 解析响应(成功时第2-3字节为00 00)
if (response[2] != 0x00 || response[3] != 0x00)
{
Console.WriteLine("读取失败,错误码:" + response[2].ToString("X2") + response[3].ToString("X2"));
return null;
}
return result;}3. 写 D 寄存器实现
类似读操作,指令代码为04 02,并附加要写入的数据:
csharp
/// <summary>/// 写入D寄存器/// </summary>/// <param name="address">起始地址</param>/// <param name="values">要写入的值</param>/// <returns>是否成功</returns>public bool WriteD(int address, int[] values){
if (!client.Connected) return false;
int count = values.Length;
int frameLength = 12 + 2 * count; // 基础12字节 + 2字节/数据
byte[] command = new byte[frameLength];
// 指令长度
byte[] lenBytes = BitConverter.GetBytes((ushort)frameLength);
Array.Reverse(lenBytes);
Array.Copy(lenBytes, 0, command, 0, 2);
// 写指令代码(04 02)
command[2] = 0x04;
command[3] = 0x02;
// 软元件代码(D寄存器:00 02)
command[4] = 0x00;
command[5] = 0x02;
// 地址
byte[] addrBytes = BitConverter.GetBytes((uint)address);
Array.Reverse(addrBytes);
Array.Copy(addrBytes, 0, command, 6, 4);
// 写入数量
byte[] countBytes = BitConverter.GetBytes((ushort)count);
Array.Reverse(countBytes);
Array.Copy(countBytes, 0, command, 10, 2);
// 写入数据(每2字节一个值,大端模式)
for (int i = 0; i < count; i++)
{
byte[] data = BitConverter.GetBytes((ushort)values[i]);
Array.Reverse(data);
Array.Copy(data, 0, command, 12 + i * 2, 2);
}
// 发送请求
stream.Write(command, 0, command.Length);
// 接收响应(8字节)
byte[] response = new byte[8];
stream.Read(response, 0, 8);
// 验证响应(00 00表示成功)
return response[2] == 0x00 && response[3] == 0x00;}4. 断开连接
csharp
public void Disconnect(){
stream?.Close();
client?.Close();}四、调用示例
csharp
class Program{
static void Main(string[] args)
{
FX5U_SLMP plc = new FX5U_SLMP("192.168.3.100");
if (plc.Connect())
{
// 读D100的值
int[] readData = plc.ReadD(100, 1);
if (readData != null)
Console.WriteLine("D100的值:" + readData[0]);五、关键注意事项
六、工具推荐
通过以上步骤,可实现 C# 与 FX5U 的 SLMP 以太网通讯,适用于数据采集、远程控制等场景。

