基于C#实现欧姆龙PLC FINS_TCP通信
一、通信协议基础
1. FINS/TCP协议框架
// FINS帧结构示例(读取DM区)
byte[] frame = new byte[26]
{
0x46,0x49,0x4E,0x53, // FINS标识
0x00,0x00, // 数据长度(后续计算)
0x00,0x00, // 保留字段
0x00,0x01, // 目标网络号
0x00,0x01, // 目标节点号
0x00,0x00, // 目标单元号
0x00,0x00, // 源网络号
0x0A,0x00, // 源节点号(PC端)
0x00,0x00, // 源单元号
0x01,0x01, // 服务ID(01读/02写)
0x01,0x00, // 命令码(01读/02写)
0x02,0x00, // 数据区域(02=DM)
0x00,0x00,0x00,0x00, // 起始地址(高位在前)
0x00,0x0A, // 数据长度(10个字)
0x00 // 错误码
};
2. 关键参数配置
| 参数 | 默认值 | 说明 |
|---|---|---|
| IP地址 | 192.168.250.1 | PLC端IP需与PC同网段 |
| 端口号 | 9600 | FINS/TCP标准端口 |
| 服务ID | 0x01 | 01=读,02=写 |
| 数据区域代码 | 0x02 | 02=DM区,0x30=CIO区 |
二、开发环境搭建
1. 开发工具配置
// 使用.NET Framework 4.7.2及以上版本
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
2. PLC连接配置
// PLC参数类
public class OmronPLCConfig
{
public string IpAddress { get; set; } = "192.168.250.1";
public int Port { get; set; } = 9600;
public byte SourceNode { get; set; } = 0x0A; // PC节点号
public byte DestinationNode { get; set; } = 0x01; // PLC节点号
}
三、核心通信实现
1. TCP连接管理
public class OmronFinsClient
{
private TcpClient _client;
private NetworkStream _stream;
public bool Connect(OmronPLCConfig config)
{
try
{
_client = new TcpClient();
_client.Connect(config.IpAddress, config.Port);
_stream = _client.GetStream();
return true;
}
catch (Exception ex)
{
Console.WriteLine($"连接失败: {ex.Message}");
return false;
}
}
public void Disconnect()
{
_stream?.Close();
_client?.Close();
}
}
2. FINS帧构造
private byte[] BuildReadFrame(ushort startAddr, ushort length)
{
byte[] frame = new byte[26 + 2 * length];
// 固定头部
Array.Copy(new byte[] { 0x46,0x49,0x4E,0x53 }, 0, frame, 0, 4);
Array.Copy(BitConverter.GetBytes(2 + 2 + 2 + 2 + length * 2), 0, frame, 4, 4); // 数据长度
// 地址信息
Array.Copy(BitConverter.GetBytes(0x00000000), 0, frame, 8, 4); // 目标地址
Array.Copy(BitConverter.GetBytes(0x0A000000), 0, frame, 12, 4); // 源地址
// 命令参数
frame[16] = 0x01; // 服务ID
frame[17] = 0x01; // 命令码(读)
frame[18] = 0x02; // 数据区域(DM)
Array.Copy(BitConverter.GetBytes(startAddr), 0, frame, 19, 2);
Array.Copy(BitConverter.GetBytes(length), 0, frame, 21, 2);
// 计算数据长度
ushort dataLength = (ushort)(2 + 2 + 2 + length * 2);
Array.Copy(BitConverter.GetBytes(dataLength), 0, frame, 4, 2);
return frame;
}
3. 数据读写操作
public byte[] ReadData(ushort startAddr, ushort length)
{
try
{
byte[] request = BuildReadFrame(startAddr, length);
_stream.Write(request, 0, request.Length);
byte[] buffer = new byte[1024];
int bytesRead = _stream.Read(buffer, 0, buffer.Length);
return buffer.Take(bytesRead).ToArray();
}
catch (Exception ex)
{
Console.WriteLine($"读操作失败: {ex.Message}");
return null;
}
}
public bool WriteData(ushort startAddr, ushort[] values)
{
try
{
ushort length = (ushort)values.Length;
byte[] frame = new byte[26 + 2 * length];
// 构建写命令帧(代码结构类似读命令,需修改服务ID和命令码)
// ...省略头部构建...
// 写入数据
Array.Copy(BitConverter.GetBytes(startAddr), 0, frame, 19, 2);
Array.Copy(BitConverter.GetBytes(length), 0, frame, 21, 2);
Array.Copy(BitConverter.GetBytes(values), 0, frame, 23, 2 * length);
_stream.Write(frame, 0, frame.Length);
return true;
}
catch (Exception ex)
{
Console.WriteLine($"写操作失败: {ex.Message}");
return false;
}
}
四、通信测试与调试
1. 使用Wireshark验证
- 过滤FINS协议:
tcp.port == 9600 - 典型通信流程: 客户端发送FINS请求帧 PLC返回ACK确认帧 数据传输阶段 连接终止帧
2. 异常处理策略
// 重连机制
public bool Reconnect(OmronPLCConfig config, int retryCount = 3)
{
for(int i=0; i<retryCount; i++)
{
if(Connect(config)) return true;
Task.Delay(1000).Wait();
}
return false;
}
// 心跳检测
private async Task KeepAlive()
{
while(true)
{
await Task.Delay(30000);
SendKeepAlivePacket();
}
}
推荐代码 C#开发欧姆龙TCP通讯 www.youwenfan.com/contentcng/51558.html
五、高级功能实现
1. 批量数据读写优化
// 使用异步操作提升性能
public async Task<byte[]> AsyncRead(ushort startAddr, ushort length)
{
return await Task.Run(() => ReadData(startAddr, length));
}
// 分块传输大块数据
public void WriteLargeData(ushort startAddr, ushort[] values)
{
const int chunkSize = 128; // 每包128字
for(int i=0; i<values.Length; i+=chunkSize)
{
ushort end = (ushort)Math.Min(i+chunkSize, values.Length);
WriteData(startAddr + i, values.Skip(i).Take(chunkSize).ToArray());
}
}
2. 数据解析示例
public Dictionary<string, object> ParseResponse(byte[] response)
{
var result = new Dictionary<string, object>();
// 解析头部
ushort dataLength = (ushort)(response[4] << 8 | response[5]);
// 解析数据区
if(response[16] == 0x01) // 读响应
{
ushort addr = (ushort)(response[19] << 8 | response[20]);
ushort count = (ushort)(response[21] << 8 | response[22]);
ushort[] data = new ushort[count];
for(int i=0; i<count; i++)
{
data[i] = (ushort)(response[23 + 2*i] << 8 | response[24 + 2*i]);
}
result["data"] = data;
}
return result;
}
六、工程实践建议
-
网络配置规范
- PLC IP段:192.168.250.x(x为1-254)
- 子网掩码:255.255.255.0
- 禁用PLC防火墙
-
性能优化方案
- 使用连接池管理TCP连接
- 实现数据缓存机制
- 采用二进制协议替代ASCII
-
安全增强措施
// 添加HMAC-SHA256校验 private byte[] AddChecksum(byte[] data) { using(var hmac = new HMACSHA256(key)) { byte[] hash = hmac.ComputeHash(data); return data.Concat(hash).ToArray(); } }
七、调试工具推荐
- Omron FINS调试助手:官方提供的命令构造工具
- SocketTool:第三方TCP调试工具
- Wireshark:网络协议分析工具
- PLC模拟器:使用Sysmac Studio进行离线测试
该方案完整覆盖了C#与欧姆龙PLC的TCP通信开发全流程,开发者可根据实际需求调整数据解析逻辑和通信参数。建议结合Sysmac Studio进行PLC端配置,并通过日志系统记录通信异常。

浙公网安备 33010602011771号