C#与三菱PLC串口通信源码实现(基于MC协议)

简介: 基于System.IO.Ports.SerialPort实现三菱FX系列PLC的串口通信,支持D寄存器、M位元件读写操作,包含指令帧构建、校验和计算、响应解析等关键模块。

一、核心代码框架

基于System.IO.Ports.SerialPort实现三菱FX系列PLC的串口通信,支持D寄存器、M位元件读写操作,包含指令帧构建、校验和计算、响应解析等关键模块。

using System;
using System.IO.Ports;
using System.Text;
using System.Threading;

public class MitsubishiPLC
{
   
    private SerialPort _serialPort;
    private const byte STX = 0x02;
    private const byte ETX = 0x03;
    private const byte ENQ = 0x05;
    private const byte ACK = 0x06;
    private const byte NAK = 0x15;

    public MitsubishiPLC(string portName, int baudRate = 9600)
    {
   
        _serialPort = new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One);
        _serialPort.DataReceived += SerialPort_DataReceived;
    }

    // 打开串口
    public bool Connect()
    {
   
        try
        {
   
            if (!_serialPort.IsOpen)
            {
   
                _serialPort.Open();
                Thread.Sleep(100); // 等待初始化
                return true;
            }
            return false;
        }
        catch (Exception ex)
        {
   
            Log($"串口打开失败: {ex.Message}");
            return false;
        }
    }

    // 关闭串口
    public void Disconnect()
    {
   
        if (_serialPort.IsOpen) _serialPort.Close();
    }

    // 读取D寄存器(示例读取D0-D9)
    public ushort[] ReadDRegisters(string startAddr, int count)
    {
   
        byte[] cmd = BuildReadCommand('D', startAddr, count);
        byte[] response = SendCommand(cmd);
        return ParseResponse(response);
    }

    // 写入单个D寄存器
    public bool WriteDRegister(string address, ushort value)
    {
   
        byte[] cmd = BuildWriteCommand('D', address, new ushort[] {
    value });
        byte[] response = SendCommand(cmd);
        return CheckAck(response);
    }

    // 构建读取指令
    private byte[] BuildReadCommand(char device, string addr, int count)
    {
   
        string cmdStr = $"{ENQ}{0x30}{0x30}{device}{addr.PadLeft(4, '0')}{count:X2}03";
        byte[] data = Encoding.ASCII.GetBytes(cmdStr);
        byte checksum = CalculateChecksum(data);
        return data.Concat(new byte[] {
    checksum, ETX }).ToArray();
    }

    // 构建写入指令
    private byte[] BuildWriteCommand(char device, string addr, ushort[] values)
    {
   
        string valueHex = string.Join("", values.Select(v => v.ToString("X4")));
        string cmdStr = $"{ENQ}{0x30}{0x30}{device}{addr.PadLeft(4, '0')}{values.Length:X2}{valueHex}";
        byte[] data = Encoding.ASCII.GetBytes(cmdStr);
        byte checksum = CalculateChecksum(data);
        return data.Concat(new byte[] {
    checksum, ETX }).ToArray();
    }

    // 发送指令并接收响应
    private byte[] SendCommand(byte[] command)
    {
   
        try
        {
   
            _serialPort.DiscardInBuffer();
            _serialPort.Write(command, 0, command.Length);
            Thread.Sleep(100); // 等待响应

            if (_serialPort.BytesToRead > 0)
            {
   
                byte[] response = new byte[_serialPort.BytesToRead];
                _serialPort.Read(response, 0, response.Length);
                return response;
            }
            return null;
        }
        catch (TimeoutException)
        {
   
            Log("通信超时");
            return null;
        }
    }

    // 校验和计算
    private byte CalculateChecksum(byte[] data)
    {
   
        byte sum = 0;
        foreach (byte b in data)
        {
   
            sum += b;
        }
        return (byte)(0 - sum); // 补码校验
    }

    // 解析响应数据
    private ushort[] ParseResponse(byte[] response)
    {
   
        if (response[0] != STX || response[1] != 0x30) return null;
        int length = response[2] - 0x30;
        ushort[] data = new ushort[length / 2];
        for (int i = 0; i < length; i += 2)
        {
   
            data[i / 2] = (ushort)(response[3 + i] << 8 | response[4 + i]);
        }
        return data;
    }

    // 校验ACK响应
    private bool CheckAck(byte[] response)
    {
   
        return response != null && response[0] == ACK;
    }

    // 日志记录
    private void Log(string message)
    {
   
        File.AppendAllText("plc_log.txt", $"{DateTime.Now}: {message}\r\n");
    }

    // 数据接收事件
    private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
   
        // 处理实时数据流(如心跳检测)
    }
}

// 使用示例
var plc = new MitsubishiPLC("COM1");
if (plc.Connect())
{
   
    ushort[] data = plc.ReadDRegisters("0000", 10);
    plc.WriteDRegister("0010", 1234);
}

二、关键功能解析

  1. 指令帧结构

    • 起始符0x02 (STX)

    • 站号:PLC地址(ASCII码,如0x30表示站号0)

    • 指令码0x30表示写操作,0x31表示读操作

    • 数据地址:4位ASCII码(如D0000表示D寄存器起始地址)

    • 数据长度:2位十六进制(如0A表示读取10个字)

    • 校验和:所有字节累加取补码

    • 结束符0x03 (ETX)

  2. 通信参数配置

    _serialPort.BaudRate = 9600;    // 波特率
    _serialPort.DataBits = 8;       // 数据位
    _serialPort.StopBits = StopBits.One; // 停止位
    _serialPort.Parity = Parity.None; // 校验位
    
  3. 异常处理策略

    • 超时重试:发送指令后等待100ms,未收到响应则重试3次

    • 校验失败:丢弃错误帧并记录日志

    • 连接状态检测:定期发送ENQ指令检测PLC在线状态


三、扩展功能实现

  1. 批量读写优化

    public ushort[] ReadDBlock(string startAddr, int count)
    {
         
        string cmd = $"{ENQ}00FF{startAddr.PadLeft(4, '0')}{count:X4}03";
        byte[] data = Encoding.ASCII.GetBytes(cmd);
        byte checksum = CalculateChecksum(data);
        _serialPort.Write(data.Concat(new byte[] {
          checksum, ETX }).ToArray());
    
        // 等待完整响应(最大3秒)
        byte[] response = ReadCompleteResponse();
        return ParseResponse(response);
    }
    
  2. M位元件操作

    public bool WriteM(string address, bool[] bits)
    {
         
        string hexStr = "";
        foreach (bool bit in bits)
        {
         
            hexStr += bit ? "1" : "0";
        }
        byte[] cmd = Encoding.ASCII.GetBytes($"{ENQ}00FFM{address.PadLeft(4, '0')}{hexStr.Length}00{hexStr}");
        byte checksum = CalculateChecksum(cmd);
        _serialPort.Write(cmd.Concat(new byte[] {
          checksum, ETX }).ToArray());
        return CheckAck(_serialPort.ReadExisting().ToByteArray());
    }
    

四、调试与优化建议

  1. 串口调试工具

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

       波特率: 9600 | 数据位:8 | 停止位:1 | 校验:
  2. 性能监控

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

    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}");
        }
    }
    

参考代码 C#与三菱PLC通讯源码 串口通讯 www.youwenfan.com/contentalh/57509.html

五、完整项目结构

PLC_Communication/
├── MitsubishiPLC/          # 核心通信类
│   ├── MitsubishiPLC.cs    # 主类
│   └── ProtocolParser.cs   # 报文解析工具
├── TestApp/                # 测试程序
│   ├── MainForm.cs         # 主界面
│   └── PLCConfigForm.cs    # 参数配置界面
└── Resources/              # 配置文件
    └── plc_params.json     # PLC参数存储

六、注意事项

  1. 通信参数一致性:确保PLC与上位机的波特率、数据位、停止位、校验位完全一致

  2. 数据缓冲区管理:批量读写时注意PLC的接收缓冲区大小限制(通常≤256字节)

  3. 实时性要求:关键控制指令建议采用中断接收方式

  4. 安全防护:工业环境中需增加光电隔离和防浪涌电路

相关文章
|
4月前
|
监控 测试技术 C#
基于C# WinForm实现的串口调试助手源码
基于C# WinForm实现的串口调试助手源码,包含串口配置、数据收发、HEX/ASCII转换、CRC校验等核心功能,支持实时流量统计和日志记录
|
11月前
|
网络协议 网络安全 API
C# 与三菱FX5U PLC通讯交互指南
C# 与三菱FX5U PLC通讯交互指南
3303 121
|
4月前
|
机器人 API 数据安全/隐私保护
钉钉企业内部机器人集成 OpenClaw 完整步骤
本文详解OpenClaw接入钉钉企业内部机器人的完整流程:从创建应用、开通机器人能力、配置Stream模式(免公网域名),到获取Client ID/Secret并配置网关。步骤清晰,含前置准备、实操要点与注意事项,助力开发人员快速落地高效协同。
|
3月前
|
网络安全 开发工具 git
Gogs: 打造属于你自己的轻量级 Git 服务
Gogs 是一个小而美的 Git 服务解决方案。无论你是想在个人服务器上搭建私有的代码仓库,还是为小团队提供一个轻量级的代码协作平台,Gogs 都是一个值得考虑的选择。
314 8
Gogs: 打造属于你自己的轻量级 Git 服务
|
2月前
|
存储 编解码 算法
MAX6675 K型热电偶温度采集程序(Keil环境)
MAX6675 K型热电偶温度采集程序(Keil环境)
|
3月前
|
存储 程序员 Linux
初级程序员必备的十大技能之 Git 版本控制(一)
教程来源 http://xcfsr.cn Git是程序员的“后悔药”与“时光机”:可随时回退错误修改、隔离并行开发、一键恢复稳定版本。作为分布式版本控制系统,它本地全量存储、离线可用、安全可靠,支撑全球90%以上团队高效协作。
|
3月前
|
NoSQL 安全 数据管理
远程维护redis服务器的数据,选用什么图形化工具
本文介绍三款支持SSH隧道的Redis图形化客户端:国产免费工具yunedit-redis(中文界面、强搜索、内存/慢查询分析);Another RDM(Electron开发、美观易用、免费);RDM新版(支持SSH但不免费)。适用于云环境安全管理Redis。
|
3月前
|
监控 网络安全 C语言
【2026最新】GX Works2安装使用保姆级教程(附安装包+图文步骤)
GX Works2是三菱电机官方PLC编程软件,专为FX/L/Q系列设计,替代GX Developer。支持梯形图、ST、SFC等多种语言,集成仿真调试、在线监控与结构化编程,功能更强、界面更优。(239字)
|
4月前
|
弹性计算 运维
新手必藏!阿里云服务器控制台首页打开教程,附直达链接
阿里云控制台首页是统一产品入口,悬停左上角“控制台首页”即可快速访问全量云服务;同时提供ECS、轻量应用服务器等核心产品的官方直达链接,提升运维效率。
681 3