C#实现三菱PLC通信

一、基于HslCommunication库的串口通信示例

csharp 复制代码
using HslCommunication;
using HslCommunication.Profinet.Melsec;
using System;
using System.Threading.Tasks;

public class MelsecPLC
{
    private MelsecMcNet _plc;

    public async Task ConnectAsync(string ipAddress, int port = 5000)
    {
        _plc = new MelsecMcNet(ipAddress, port);
        var result = await _plc.ConnectServerAsync();
        if (!result.IsSuccess)
        {
            throw new Exception($"连接失败: {result.Message}");
        }
    }

    // 读取D寄存器(示例读取D0-D9)
    public ushort[] ReadDRegisters(int startAddress, int count)
    {
        var result = _plc.Read("D" + startAddress, count);
        return result.IsSuccess ? result.Content : new ushort[0];
    }

    // 写入单个D寄存器
    public bool WriteDRegister(int address, ushort value)
    {
        var result = _plc.Write("D" + address, value);
        return result.IsSuccess;
    }

    // 批量写入D寄存器
    public bool WriteDBlock(int startAddress, ushort[] values)
    {
        return _plc.Write("D" + startAddress, values) is OperateResult<byte[]> { IsSuccess: true };
    }
}

// 使用示例
var plc = new MelsecPLC();
await plc.ConnectAsync("192.168.1.100");
ushort[] data = plc.ReadDRegisters(0, 10);
plc.WriteDRegister(100, 1234);

二、基于AxActUtlTypeLib的TCP/IP通信示例

csharp 复制代码
using System;
using System.Runtime.InteropServices;
using ActUtlTypeLib;

public class MelsecPLC
{
    private AxActUtlType _axActUtlType;

    public MelsecPLC()
    {
        _axActUtlType = new AxActUtlType();
        ((System.ComponentModel.ISupportInitialize)(_axActUtlType)).BeginInit();
        Controls.Add(_axActUtlType);
    }

    public int Connect(string ipAddress, int station = 0)
    {
        _axActUtlType.ActLogicalStationNumber = station;
        _axActUtlType.ActPassword = "";
        return _axActUtlType.Open();
    }

    public short[] ReadWords(string address, int count)
    {
        short[] buffer = new short[count];
        int result = _axActUtlType.ReadDeviceBlock2(address, count, out buffer[0]);
        return result == 0 ? buffer : new short[0];
    }

    public bool WriteWords(string address, short[] values)
    {
        return _axActUtlType.WriteDeviceBlock2(address, values.Length, ref values[0]) == 0;
    }
}

// 使用示例
var plc = new MelsecPLC();
int status = plc.Connect("192.168.1.100");
short[] data = plc.ReadWords("D0", 10);
plc.WriteWords("D100", new short[] { 100, 200 });

三、基于MC协议的TCP/IP通信示例

csharp 复制代码
using System;
using System.Net.Sockets;
using System.Text;

public class McProtocolPLC
{
    private TcpClient _client;
    private NetworkStream _stream;

    public bool Connect(string ip, int port = 5000)
    {
        _client = new TcpClient();
        _client.Connect(ip, port);
        _stream = _client.GetStream();
        return _client.Connected;
    }

    // 构建读取帧(示例读取D0-D9)
    private byte[] BuildReadFrame(string device, int startAddr, int count)
    {
        byte[] header = { 0x50, 0x00, 0x00, 0x03, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 };
        byte[] cmd = { 0x01, 0x04 }; // 批量读取指令
        byte[] addr = BitConverter.GetBytes(startAddr);
        byte[] len = { (byte)(count & 0xFF), (byte)(count >> 8) };
        byte[] devCode = GetDeviceCode(device);

        using (MemoryStream ms = new MemoryStream())
        {
            ms.Write(header, 0, header.Length);
            ms.Write(cmd, 0, cmd.Length);
            ms.Write(addr, 0, addr.Length);
            ms.Write(len, 0, len.Length);
            ms.Write(devCode, 0, devCode.Length);
            return ms.ToArray();
        }
    }

    private byte[] GetDeviceCode(string device)
    {
        return device switch
        {
            "D" => new byte[] { 0xA8 },
            "M" => new byte[] { 0x90 },
            "X" => new byte[] { 0x9C },
            "Y" => new byte[] { 0x9D },
            _ => throw new ArgumentException("无效设备类型")
        };
    }

    public ushort[] ReadData(string device, int startAddr, int count)
    {
        byte[] request = BuildReadFrame(device, startAddr, count);
        _stream.Write(request, 0, request.Length);

        byte[] response = new byte[1024];
        int bytesRead = _stream.Read(response, 0, response.Length);
        return ParseResponse(response, bytesRead);
    }

    private ushort[] ParseResponse(byte[] data, int length)
    {
        if (BitConverter.ToUInt16(data, 7) != 0x0000) // 检查结束码
            throw new Exception("PLC返回错误");

        int dataLength = (BitConverter.ToUInt16(data, 8) << 8) | data[9];
        ushort[] result = new ushort[dataLength / 2];
        for (int i = 0; i < result.Length; i++)
        {
            result[i] = (ushort)(data[10 + i * 2] | (data[11 + i * 2] << 8));
        }
        return result;
    }
}

// 使用示例
var plc = new McProtocolPLC();
plc.Connect("192.168.1.100");
ushort[] data = plc.ReadData("D", 0, 10);

四、核心功能实现要点

  1. 地址转换规则

    • 位地址:Y737H→ ASCII码33 37
    • 字地址:D04000H→ ASCII码34 30 30 30
    csharp 复制代码
    public static string DecimalToWordAddress(int address)
    {
        return (address * 2 + 4096).ToString("X4");
    }
  2. 数据校验机制

    csharp 复制代码
    private byte CalculateChecksum(byte[] data)
    {
        byte sum = 0;
        foreach (byte b in data)
        {
            sum += b;
        }
        return (byte)(sum % 256);
    }
  3. 异常处理策略

    csharp 复制代码
    public async Task<OperateResult<byte[]>> SafeReadAsync(string address, int length)
    {
        try
        {
            return await ReadAsync(address, length);
        }
        catch (TimeoutException)
        {
            return OperateResult.Create<byte[]>(false, "通信超时");
        }
        catch (Exception ex)
        {
            return OperateResult.Create<byte[]>(false, ex.Message);
        }
    }

五、完整项目结构建议

csharp 复制代码
PLC_Communication/
├── MelsecPLC/              # 核心通信类
│   ├── MelsecPLC.cs       # 主类
│   └── AddressConverter.cs # 地址转换工具
├── TestApp/               # 测试程序
│   ├── MainForm.cs        # 主界面
│   └── PLCConfigForm.cs   # 参数配置界面
└── Resources/             # 配置文件
    └── plc_params.json    # PLC参数存储

六、调试与优化建议

  1. 串口调试工具

    使用PuttySecureCRT验证基础通信,设置参数:

    复制代码
    波特率:9600 | 数据位:7 | 停止位:1 | 校验:偶校验
  2. 性能监控

    csharp 复制代码
    public class PerformanceMetrics
    {
        public long MessagesSent { get; set; }
        public long MessagesReceived { get; set; }
        public double CPUUsage { get; set; }
        public double MemoryUsage { get; set; }
    }
  3. 日志记录

    csharp 复制代码
    public static class Logger
    {
        public static void Log(string message)
        {
            File.AppendAllText("plc_log.txt", 
                $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - {message}{Environment.NewLine}");
        }
    }

七、扩展功能实现

  1. 批量读写优化

    csharp 复制代码
    public ushort[] ReadWords(string startAddr, int count)
    {
        string cmd = $"{STX}30{StationNumber}0400{startAddr}{count:X2}{ETX}";
        var response = SendCommand(cmd);
        ushort[] result = new ushort[count];
        for(int i=0; i<count; i++)
        {
            result[i] = (ushort)(response[5+2*i] * 256 + response[6+2*i]);
        }
        return result;
    }
  2. 自动重连机制

    csharp 复制代码
    public async Task AutoReconnectAsync()
    {
        while (!_isDisposed)
        {
            if (!_serialPort.IsOpen)
            {
                try
                {
                    _serialPort.Open();
                    Debug.WriteLine("自动重连成功");
                }
                catch (Exception ex)
                {
                    Debug.WriteLine($"重连失败: {ex.Message}");
                    await Task.Delay(5000);
                }
            }
            await Task.Delay(1000);
        }
    }

参考代码 三菱通讯字节写入 www.youwenfan.com/contentcso/112220.html

八、推荐开发工具

工具名称 用途 下载地址
GX Works3 PLC程序编写与调试 三菱电机官网
HslCommunication 高级PLC通信库 GitHub
Serial Port Monitor 串口数据监控 NirSoft官网
相关推荐
专业开发者3 小时前
经 Nordic 实测:蓝牙长距离传输
网络·物联网
k***92163 小时前
【C++】继承和多态扩展学习
java·c++·学习
weixin_440730503 小时前
java结构语句学习
java·开发语言·学习
JIngJaneIL3 小时前
基于java+ vue医院管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot
Coder_Boy_3 小时前
Spring AI 源码大白话解析
java·人工智能·spring
仙俊红3 小时前
在 Java 中,`==` 和 `equals()` 的区别
java·开发语言·jvm
计算机学姐3 小时前
基于SpringBoot的高校论坛系统【2026最新】
java·vue.js·spring boot·后端·spring·java-ee·tomcat
予枫的编程笔记3 小时前
Redis 核心数据结构深度解密:从基础命令到源码架构
java·数据结构·数据库·redis·缓存·架构
zfj3213 小时前
top 命令中的 wa (IO wait) 指标,理论上几乎完全是由磁盘IO(包括swap)引起的,而不是网络IO
linux·网络·top·iowait