基于C#的PLC串口通信实现

一、基础通信配置

1. 串口参数设置

using System.IO.Ports;

public class PlcSerial
{
    private SerialPort _serialPort;

    public PlcSerial(string portName, int baudRate = 9600)
    {
        _serialPort = new SerialPort
        {
            PortName = portName,
            BaudRate = baudRate,
            Parity = Parity.None,    // 奇偶校验
            DataBits = 8,            // 数据位
            StopBits = StopBits.One, // 停止位
            Handshake = Handshake.None // 流控制
        };
    }

    public void Open() => _serialPort.Open();
    public void Close() => _serialPort.Close();
}

关键参数说明

  • 三菱PLC:需设置奇偶校验(如Even)和7位数据位
  • 西门子PLC:常用8数据位+1停止位

二、核心通信协议实现

1. Modbus RTU协议

public class ModbusRTU
{
    // 生成CRC校验
    private static ushort CalcCRC(byte[] data)
    {
        ushort crc = 0xFFFF;
        foreach (byte b in data)
        {
            crc ^= (ushort)b;
            for (int i = 0; i < 8; i++)
            {
                crc >>= 1;
                if ((crc & 0x0001) != 0)
                    crc ^= 0xA001;
            }
        }
        return crc;
    }

    // 构建Modbus请求帧
    public static byte[] CreateReadRequest(int slaveId, ushort startAddr, ushort count)
    {
        byte[] frame = new byte[8];
        frame[0] = (byte)slaveId;
        frame[1] = 0x03; // 读保持寄存器
        frame[2] = (byte)(startAddr >> 8);
        frame[3] = (byte)startAddr;
        frame[4] = (byte)(count >> 8);
        frame[5] = (byte)count;
        ushort crc = CalcCRC(frame);
        frame[6] = (byte)crc;
        frame[7] = (byte)(crc >> 8);
        return frame;
    }
}

2. 三菱HostLink协议

public class MitsubishiHostLink
{
    private const string STX = "\x02";
    private const string ETX = "\x03";

    // 构建读指令
    public static string BuildReadCommand(string address, int length)
    {
        string cmd = $"{STX}03{address}{length:X2}{ETX}";
        string fcs = CalcBCC(cmd);
        return $"{cmd}{fcs}";
    }

    // BCC校验算法
    private static string CalcBCC(string data)
    {
        byte bcc = 0;
        foreach (char c in data)
        {
            bcc ^= (byte)c;
        }
        return bcc.ToString("X2").PadLeft(2, '0');
    }
}

三、数据交互实现

1. 数据读取

public string ReadData(string command)
{
    try
    {
        _serialPort.Write(command);
        Thread.Sleep(100); // 等待响应
        
        if (_serialPort.BytesToRead > 0)
        {
            string response = _serialPort.ReadExisting();
            return ParseResponse(response);
        }
    }
    catch (TimeoutException ex)
    {
        Debug.WriteLine($"读取超时: {ex.Message}");
    }
    return null;
}

2. 数据写入

public bool WriteData(string address, object value)
{
    string command = BuildWriteCommand(address, value);
    _serialPort.Write(command);
    
    // 等待应答
    string ack = _serialPort.ReadLine();
    return ack.Contains("\x06"); // 06表示ACK
}

四、关键工程实践

1. 异常处理机制

public void SafeSend(string data)
{
    try
    {
        if (!_serialPort.IsOpen) Open();
        _serialPort.WriteLine(data);
    }
    catch (IOException ex)
    {
        Reconnect();
        throw new Exception("通信中断", ex);
    }
}

private void Reconnect()
{
    Close();
    Thread.Sleep(1000);
    Open();
}

2. 多线程数据采集

private void DataPolling()
{
    while (!_stopFlag)
    {
        string data = ReadData("ReadRegister");
        if (!string.IsNullOrEmpty(data))
        {
            UpdateUI(ParseData(data));
        }
        Thread.Sleep(500); // 采集间隔
    }
}

五、主流PLC适配方案

PLC品牌 通信协议 地址格式 典型指令示例
三菱 HostLink D1000→D1000+999 @00RD000000000100
西门子 PPI/MPI %Q0.0,%M100 05 03 0000 0002 00A0
欧姆龙 FINS over TCP W0.0, D100 46494E53 0000001A ...
施耐德 Modbus TCP 40001, 40002 [03][03][00][01][00][01]

六、调试工具开发

1. 串口调试助手

public class DebugAssistant : Form
{
    private TextBox _logBox;
    private SerialPort _debugPort;

    public DebugAssistant()
    {
        _debugPort = new SerialPort("COM2", 9600);
        _debugPort.DataReceived += (s,e) => 
            _logBox.AppendText(Encoding.ASCII.GetString(e.Buffer));
    }
}

2. 数据监控看板

public partial class Dashboard : Form
{
    private Timer _updateTimer = new Timer(1000);
    
    public Dashboard()
    {
        _updateTimer.Tick += () => 
            UpdatePlcStatus(GetRealTimeData());
    }
}

参考代码 C# 串口通讯 PLC 实例 www.youwenfan.com/contentcnn/92565.html

七、典型应用场景

  1. 产线监控系统 实时读取PLC的DI/DO状态 周期写入控制指令 异常报警触发
  2. 设备远程维护 通过串口实现固件升级 执行诊断命令 日志下载
  3. 能源管理系统 采集PLC的能耗数据 生成用电报表 异常用电预警

八、注意事项

  1. 硬件兼容性 确认PLC支持的串口类型(RS232/485) 使用隔离模块防止电平冲突
  2. 通信稳定性 添加心跳包机制 实现断线自动重连 设置合理的超时时间
  3. 数据安全 对敏感指令加密 添加操作日志 限制非法访问
posted @ 2025-12-11 10:11  yes_go  阅读(2)  评论(0)    收藏  举报