C# 与三菱FX5U PLC通讯交互指南

简介: C# 与三菱FX5U PLC通讯交互指南

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#代码前,你需要完成以下准备工作:

  1. 硬件连接:确保你的PC和FX5U PLC处于同一局域网,使用网线直接连接或通过交换机连接。
  2. PLC设置:使用GX Works3软件设置PLC的IP地址、子网掩码等网络参数。对于MC协议或SLMP通信,通常需要在“模块参数”->“以太网端口”->“应用设置”中启用SLMP通信服务,并设置端口号(默认为8192或8195,可自定义)。设置完成后,务必下载参数到PLC并断电重启
  3. 开发环境:确保你的Visual Studio项目配置正确。

3. 通信方式详解

3.1 使用 MX Component (ActUtlTypeLib) 库

这种方式通过三菱提供的ActiveX控件进行通信,优点是官方支持且相对稳定。

实现步骤:

  1. 添加引用:在Visual Studio中,右键点击项目的“引用”->“添加COM引用”,找到并选择 ActUtlTypeLibActUtlType
  2. 初始化控件:通常在窗体设计器中拖入 AxActUtlType 控件,或在代码中动态创建。
  3. 设置站号:指定逻辑站号(Logical Station Number),这个站号应与在MX Component设置工具中配置的站号一致。
  4. 打开连接:调用 Open 方法。
  5. 读写数据:使用 ReadDeviceBlock2WriteDeviceBlock2 等方法进行批量读写,或使用 GetDeviceSetDevice 进行单个点读写。
  6. 关闭连接:操作完成后调用 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#实现关键步骤

  1. 建立TCP连接:使用 TcpClient 连接到PLC的IP和端口(默认可能是8192, 8195等)。
  2. 构造请求帧:根据MC协议格式,将指令、地址、软元件类型、点数等信息转换为字节数组。注意地址转换(如D7000 -> 0x1B58 -> 58 1B 00)和高低字节顺序
  3. 发送请求帧:通过 NetworkStream 发送字节数组。
  4. 接收响应帧:读取PLC返回的字节数组。
  5. 解析响应帧:检查结束代码判断成功与否,并从指定位置解析出数据。
  6. 处理异常:处理网络异常和协议错误。

代码示例:读取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协议,封装了底层细节。

实现步骤:

  1. 安装NuGet包:在Visual Studio的NuGet包管理器中搜索并安装 HslCommunication
  2. 创建PLC对象:实例化 MelsecMcNet 对象。
  3. 设置IP和端口:配置PLC的IP地址和端口号。
  4. 连接PLC:调用 Connect 方法(或类似方法,具体参考库的文档)。
  5. 读写数据:使用 ReadWrite 方法的重载。
  6. 断开连接:操作完成后调用 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. 通用注意事项

  1. PLC配置是关键:确保GX Works3中的以太网参数和SLMP服务设置正确,并且参数已下载至PLC并断电重启
  2. 强大的异常处理:PLC通信易受网络波动、PLC状态等影响,必须用 try-catch 包裹所有通信代码,并详细处理错误码和异常信息。
  3. 连接管理:合理管理TCP连接的生命周期。避免频繁开关连接。对于需要长期连接的场景,实现心跳机制断线重连逻辑。
  4. 数据解析与转换:注意MC协议中多字节数据的字节顺序(大小端)。例如,PLC返回的16位整数可能是低位在前高位在后,需要进行转换。
  5. 性能与阻塞:同步的读写操作可能会阻塞UI线程。对于需要高频读写的应用,考虑使用异步操作或将通信任务放在后台线程中。
  6. 防火墙与网络策略:确保PC和PLC之间的通信端口(如8192)在防火墙中是放行的
  7. 文档是最好的朋友:始终备好三菱的《MELSEC iQ-F FX5用户手册(编程篇)》和《MELSEC通信协议参考手册》,它们包含了软元件代码、错误代码和协议细节的权威信息。

5. 总结

C#与三菱FX5U PLC通信主要有三种方式:使用三菱官方的MX Component库适合快速开发且追求稳定性的场景;使用MC协议通过原生TCP/IPSocket通信灵活性最高,但开发工作量较大;使用HslCommunication等开源库则平衡了开发效率和灵活性。

对于大多数应用场景,如果你不介意使用第三方开源库,HslCommunication通常是一个不错的选择。如果你无法使用第三方库且需要精细控制通信过程,那么深入理解MC协议并实现原生Socket通信是必要的。无论选择哪种方式,充分理解协议细节、做好异常处理和完善的测试都是项目成功的关键。

相关文章
|
2月前
|
存储 网络协议 C#
C#实现与西门子S7-1200/1500 PLC通信
C#实现与西门子S7-1200/1500 PLC通信
|
12月前
|
物联网 C#
【C#】简单的蓝牙通讯功能实现
【C#】简单的蓝牙通讯功能实现
569 0
|
移动开发 监控 网络协议
基于Socket通讯(C#)和WebSocket协议(net)编写的两种聊天功能(文末附源码下载地址)
基于Socket通讯(C#)和WebSocket协议(net)编写的两种聊天功能(文末附源码下载地址)
|
关系型数据库 API C#
C#调用执行命令行窗口cmd,及需要交互执行的处理
C#执行外部程序用到的是Process进程类,打开一个进程,可以指定进程的启动信息StartInfo(启动的程序名、输入输出是否重定向、是否显示UI界面、一些必要参数等)...
3864 0
C#调用执行命令行窗口cmd,及需要交互执行的处理
|
监控 网络协议 C#
一款基于C#开发的通讯调试工具(支持Modbus RTU、MQTT调试)
一款基于C#开发的通讯调试工具(支持Modbus RTU、MQTT调试)
216 0
|
SQL 存储 数据库连接
C#编程与数据库交互的实现
【4月更文挑战第20天】C#与数据库交互是现代软件开发的关键,涉及数据库连接、数据操作和访问方式。使用ADO.NET建立连接,执行SQL实现读取、插入、更新和删除数据。可通过直接SQL或数据访问对象进行操作。注意性能优化,使用连接池,处理异常,确保安全,以提升应用性能和稳定性。
188 0
|
JavaScript C#
C#winForm程序与html JS交互调用
C#winForm程序与html JS交互调用
|
开发框架 .NET C#
无标题自用临时文档.C# | python交互
无标题自用临时文档.C# | python交互
197 0
|
JavaScript C#
【傻瓜级JS-DLL-WINCC-PLC交互】7.​C#直连PLC并读取PLC数据
【傻瓜级JS-DLL-WINCC-PLC交互】7.​C#直连PLC并读取PLC数据
618 0
|
SQL 数据库连接 数据库
C#常见控件与SQL Sever数据库交互
首先,我们采用DataSet作为临时的数据库,这样会比较好
214 0