基于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
七、典型应用场景
- 产线监控系统 实时读取PLC的DI/DO状态 周期写入控制指令 异常报警触发
- 设备远程维护 通过串口实现固件升级 执行诊断命令 日志下载
- 能源管理系统 采集PLC的能耗数据 生成用电报表 异常用电预警
八、注意事项
- 硬件兼容性 确认PLC支持的串口类型(RS232/485) 使用隔离模块防止电平冲突
- 通信稳定性 添加心跳包机制 实现断线自动重连 设置合理的超时时间
- 数据安全 对敏感指令加密 添加操作日志 限制非法访问

浙公网安备 33010602011771号