C# 与三菱FX5U PLC通讯交互指南
目录
- 通信协议选择
- 准备工作
- 通信方式详解
- 通用注意事项
- 总结
1. 通信协议选择
三菱FX5U PLC支持多种通信协议,你需要根据项目需求、技术背景和硬件环境选择最合适的一种。以下是三种主流的通信方式对比:
特性 | MX Component库 (ActUtlType) | MC协议 (SLMP/3E帧) - 原生TCP/IP | HslCommunication开源库 | Modbus TCP桥接 |
---|---|---|---|---|
实现方式 | 使用三菱提供的ActiveX控件ActUtlTypeLib |
基于三菱私有协议MC协议,通过Socket发送特定格式指令 | 使用开源第三方库,封装了协议细节 | 将FX5U配置为Modbus TCP主站/从站 |
优点 | 官方支持,稳定性较高,编程相对简单 | 灵活性强,无需额外授权,性能较好 | 开源免费,API友好,支持多种PLC品牌 | 通用标准协议,兼容性好 |
缺点 | 可能需要购买授权,依赖特定组件 | 需手动组帧和解帧,处理错误码,开发复杂度稍高 | 社区支持,非官方 | 需在GX Works3中进行额外配置 |
适用场景 | 快速开发,对稳定性要求高的项目 | 需要深度控制通信过程或无法使用第三方库的项目 | 希望开源、免费,或项目需兼容多品牌PLC的场景 | 现有系统基于Modbus TCP |
2. 准备工作
在开始编写C#代码前,你需要完成以下准备工作:
- 硬件连接:确保你的PC和FX5U PLC处于同一局域网,使用网线直接连接或通过交换机连接。
- PLC设置:使用GX Works3软件设置PLC的IP地址、子网掩码等网络参数。对于MC协议或SLMP通信,通常需要在“模块参数”->“以太网端口”->“应用设置”中启用SLMP通信服务,并设置端口号(默认为8192或8195,可自定义)。设置完成后,务必下载参数到PLC并断电重启。
- 开发环境:确保你的Visual Studio项目配置正确。
3. 通信方式详解
3.1 使用 MX Component (ActUtlTypeLib) 库
这种方式通过三菱提供的ActiveX控件进行通信,优点是官方支持且相对稳定。
实现步骤:
- 添加引用:在Visual Studio中,右键点击项目的“引用”->“添加COM引用”,找到并选择
ActUtlTypeLib
或ActUtlType
。 - 初始化控件:通常在窗体设计器中拖入
AxActUtlType
控件,或在代码中动态创建。 - 设置站号:指定逻辑站号(Logical Station Number),这个站号应与在MX Component设置工具中配置的站号一致。
- 打开连接:调用
Open
方法。 - 读写数据:使用
ReadDeviceBlock2
和WriteDeviceBlock2
等方法进行批量读写,或使用GetDevice
和SetDevice
进行单个点读写。 - 关闭连接:操作完成后调用
Close
方法。
代码:连接与读取
using System;
using System.Windows.Forms;
// 根据需要添加对应的COM互操作程序集引用
// 例如 using AxActUtlTypeLib;
public class MitsubishiHelper
{
private AxActUtlType axActUtlType1; // 假设已在设计器中添加
public string OpenConnection(int stationNumber = 0, string password = "")
{
try
{
axActUtlType1.ActLogicalStationNumber = stationNumber;
axActUtlType1.ActPassword = password;
int returnCode = axActUtlType1.Open();
if (returnCode == 0)
{
return "PLC连接成功";
}
else
{
return $"PLC连接失败,错误代码: {returnCode}";
}
}
catch (Exception ex)
{
return $"PLC连接异常: {ex.Message}";
}
}
public string ReadDeviceBlock(string deviceName, int size)
{
try
{
short[] data = new short[size];
int returnCode = axActUtlType1.ReadDeviceBlock2(deviceName, size, out data[0]);
if (returnCode == 0)
{
// 成功读取,处理data数组
return $"读取成功,数据: {BitConverter.ToString(Array.ConvertAll(data, x => (byte)x))}";
}
else
{
return $"读取失败,错误代码: {returnCode}";
}
}
catch (Exception ex)
{
return $"读取异常: {ex.Message}";
}
}
public void CloseConnection()
{
axActUtlType1?.Close();
}
}
3.2 使用 MC 协议 (SLMP) 通过原生TCP/IP通信
MC协议(Melsec Communication Protocol)是三菱PLC的私有协议,FX5U支持基于以太网的3E帧二进制格式通信。这种方式灵活性高,但需要你自行组帧和解帧。
协议帧格式简介(以读取D寄存器为例)
- 读取命令帧示例(读取D7000开始的1个字):
50 00 00 FF FF 03 00 0C 00 10 00 01 04 00 00 58 1B 00 A8 01 00
500000
:副头部(请求)FFFF0300
:目标模块的网络号、PC号等,默认即可0C00
:请求数据长度(后面所有字节的长度)01000400
:指令(0401为批量读)、子指令(0000按字读)581B00
:起始地址(D7000的十六进制1B58,低位在前)A8
:软元件代码(D寄存器)0100
:读取的点数(1个)
- 成功响应帧示例:
D0 00 00 FF FF 03 00 04 00 00 00 0C 00
D00000
:副头部(响应)0400
:结束代码(0000表示正常)0C00
:读取到的数据值(000C,即十进制12)
C#实现关键步骤
- 建立TCP连接:使用
TcpClient
连接到PLC的IP和端口(默认可能是8192, 8195等)。 - 构造请求帧:根据MC协议格式,将指令、地址、软元件类型、点数等信息转换为字节数组。注意地址转换(如D7000 -> 0x1B58 -> 58 1B 00)和高低字节顺序。
- 发送请求帧:通过
NetworkStream
发送字节数组。 - 接收响应帧:读取PLC返回的字节数组。
- 解析响应帧:检查结束代码判断成功与否,并从指定位置解析出数据。
- 处理异常:处理网络异常和协议错误。
代码示例:读取D寄存器
using System;
using System.IO;
using System.Net.Sockets;
using System.Text;
public class McProtocolHelper
{
private TcpClient tcpClient;
private NetworkStream stream;
private string plcIp;
private int plcPort;
public McProtocolHelper(string ip, int port = 8192)
{
plcIp = ip;
plcPort = port;
}
public bool Connect()
{
try
{
tcpClient = new TcpClient(plcIp, plcPort);
stream = tcpClient.GetStream();
stream.ReadTimeout = 2000; // 设置读取超时
return true;
}
catch (Exception ex)
{
Console.WriteLine($"连接失败: {ex.Message}");
return false;
}
}
public byte[] BuildReadFrame(string deviceCode, int startAddress, int points)
{
// 将起始地址转换为3字节(低位在前)
byte[] addressBytes = BitConverter.GetBytes(startAddress);
// 软元件代码映射 例如: D -> 0xA8
byte deviceByte = GetDeviceCodeByte(deviceCode);
// 构建MC协议帧 (示例框架,具体字节顺序和长度需严格按照协议手册)
using (MemoryStream ms = new MemoryStream())
using (BinaryWriter writer = new BinaryWriter(ms))
{
// 副头部 (500000)
writer.Write(new byte[] {
0x50, 0x00, 0x00 });
// 网络号、PC号等 (默认FFFF0300)
writer.Write(new byte[] {
0xFF, 0xFF, 0x03, 0x00 });
// 请求数据长度 (后面决定,先占位)
writer.Write((short)0);
// 定时器 (默认1000)
writer.Write((short)0x1000);
// 指令: 批量读 (0401), 但写入顺序注意
writer.Write((short)0x0104);
// 子指令: 按字读 (0000)
writer.Write((short)0x0000);
// 起始地址
writer.Write(addressBytes[0]);
writer.Write(addressBytes[1]);
writer.Write(addressBytes[2]);
// 软元件代码
writer.Write(deviceByte);
// 点数
writer.Write((short)points);
// 计算请求数据长度并回填
long dataLength = ms.Length - 9; // 从指令开始到结束的长度
ms.Position = 3;
writer.Write((short)dataLength);
return ms.ToArray();
}
}
private byte GetDeviceCodeByte(string deviceCode)
{
// 简单映射,参考三菱协议手册完善
switch (deviceCode.ToUpper())
{
case "D": return 0xA8;
case "M": return 0x90;
// ... 其他软元件类型
default: throw new ArgumentException($"Unsupported device code: {deviceCode}");
}
}
public short[] ReadDeviceBlock(string deviceCode, int startAddress, int points)
{
if (!tcpClient?.Connected ?? true) Connect();
byte[] requestFrame = BuildReadFrame(deviceCode, startAddress, points);
stream.Write(requestFrame, 0, requestFrame.Length);
byte[] responseHeader = new byte[11]; // 先读取响应头
int bytesRead = stream.Read(responseHeader, 0, responseHeader.Length);
if (bytesRead < responseHeader.Length)
throw new Exception("响应头不完整");
// 检查结束代码 (位于响应头第9-10字节,低位在前)
int endCode = BitConverter.ToInt16(responseHeader, 9);
if (endCode != 0)
throw new Exception($"PLC返回错误: {endCode:X4}");
// 计算剩余要读取的数据长度并读取
int dataLen = points * 2; // 每个字2字节
byte[] dataBuffer = new byte[dataLen];
bytesRead = stream.Read(dataBuffer, 0, dataLen);
if (bytesRead < dataLen)
throw new Exception("响应数据不完整");
// 解析数据 (注意字节顺序)
short[] values = new short[points];
for (int i = 0; i < points; i++)
{
values[i] = BitConverter.ToInt16(dataBuffer, i * 2);
}
return values;
}
public void Disconnect()
{
stream?.Close();
tcpClient?.Close();
}
}
3.3 使用 HslCommunication 开源库
HslCommunication
是一个强大的开源工业通信库,支持多种品牌的PLC,包括三菱的MC协议,封装了底层细节。
实现步骤:
- 安装NuGet包:在Visual Studio的NuGet包管理器中搜索并安装
HslCommunication
。 - 创建PLC对象:实例化
MelsecMcNet
对象。 - 设置IP和端口:配置PLC的IP地址和端口号。
- 连接PLC:调用
Connect
方法(或类似方法,具体参考库的文档)。 - 读写数据:使用
Read
和Write
方法的重载。 - 断开连接:操作完成后调用
ConnectClose
方法。
代码示例:
using HslCommunication;
using HslCommunication.Profinet.Melsec;
// 创建MelsecMcNet对象,指定IP、端口
MelsecMcNet melsecNet = new MelsecMcNet("192.168.1.10", 8192);
// 设置连接超时时间
melsecNet.ConnectTimeOut = 2000;
// 连接PLC
OperateResult connectResult = melsecNet.Connect();
if (!connectResult.IsSuccess)
{
Console.WriteLine($"连接失败: {connectResult.Message}");
return;
}
// 读取D100开始的10个short值
OperateResult<short[]> readResult = melsecNet.ReadInt16("D100", 10);
if (readResult.IsSuccess)
{
short[] values = readResult.Content;
Console.WriteLine("读取成功: " + string.Join(", ", values));
}
else
{
Console.WriteLine($"读取失败: {readResult.Message}");
}
// 向D200写入一个short值
OperateResult writeResult = melsecNet.Write("D200", (short)1234);
if (writeResult.IsSuccess)
{
Console.WriteLine("写入成功");
}
else
{
Console.WriteLine($"写入失败: {writeResult.Message}");
}
// 断开连接
melsecNet.ConnectClose();
推荐项目 c# 与三菱FX5U PLC通讯交互 www.youwenfan.com/contentald/52014.html
4. 通用注意事项
- PLC配置是关键:确保GX Works3中的以太网参数和SLMP服务设置正确,并且参数已下载至PLC并断电重启。
- 强大的异常处理:PLC通信易受网络波动、PLC状态等影响,必须用
try-catch
包裹所有通信代码,并详细处理错误码和异常信息。 - 连接管理:合理管理TCP连接的生命周期。避免频繁开关连接。对于需要长期连接的场景,实现心跳机制或断线重连逻辑。
- 数据解析与转换:注意MC协议中多字节数据的字节顺序(大小端)。例如,PLC返回的16位整数可能是低位在前高位在后,需要进行转换。
- 性能与阻塞:同步的读写操作可能会阻塞UI线程。对于需要高频读写的应用,考虑使用异步操作或将通信任务放在后台线程中。
- 防火墙与网络策略:确保PC和PLC之间的通信端口(如8192)在防火墙中是放行的。
- 文档是最好的朋友:始终备好三菱的《MELSEC iQ-F FX5用户手册(编程篇)》和《MELSEC通信协议参考手册》,它们包含了软元件代码、错误代码和协议细节的权威信息。
5. 总结
C#与三菱FX5U PLC通信主要有三种方式:使用三菱官方的MX Component库适合快速开发且追求稳定性的场景;使用MC协议通过原生TCP/IPSocket通信灵活性最高,但开发工作量较大;使用HslCommunication等开源库则平衡了开发效率和灵活性。
对于大多数应用场景,如果你不介意使用第三方开源库,HslCommunication通常是一个不错的选择。如果你无法使用第三方库且需要精细控制通信过程,那么深入理解MC协议并实现原生Socket通信是必要的。无论选择哪种方式,充分理解协议细节、做好异常处理和完善的测试都是项目成功的关键。