基于FINS协议实现的C#欧姆龙PLC通信

简介: 基于FINS协议实现的C#欧姆龙PLC通信,包含串口/TCP双模式支持、FCS校验、内存区读写等核心功能

基于FINS协议实现的C#欧姆龙PLC通信,包含串口/TCP双模式支持、FCS校验、内存区读写等核心功能


一、核心代码结构

// 通信接口定义
public interface IFinsClient : IDisposable
{
   
    bool Connect();
    bool ReadMemory(string area, ushort address, ushort length, out byte[] data);
    bool WriteMemory(string area, ushort address, byte[] data);
    void Disconnect();
}

// 串口实现类
public class FinsSerialClient : IFinsClient
{
   
    private SerialPort _port;
    private const int FCS_OFFSET = 2; // FCS校验码起始位置

    public FinsSerialClient(string portName, int baudRate = 9600)
    {
   
        _port = new SerialPort(portName, baudRate, Parity.Even, 7, StopBits.Two);
        _port.Handshake = Handshake.None;
        _port.DataReceived += OnDataReceived;
    }

    public bool Connect()
    {
   
        try
        {
   
            _port.Open();
            SendCommand("STX@00FA0000000037ETX"); // 初始化握手命令
            return true;
        }
        catch (Exception ex)
        {
   
            Debug.WriteLine($"连接失败: {ex.Message}");
            return false;
        }
    }

    public bool ReadMemory(string area, ushort address, ushort length, out byte[] data)
    {
   
        string cmd = BuildReadCommand(area, address, length);
        SendCommand(cmd);
        var response = ReadResponse();
        return ParseReadResponse(response, out data);
    }

    private string BuildReadCommand(string area, ushort addr, ushort len)
    {
   
        var ms = new MemoryStream();
        ms.WriteByte(0x01); // 读命令
        ms.WriteByte((byte)GetAreaCode(area));
        WriteAddress(ms, addr);
        ms.WriteByte(0x00); // 高字节长度
        ms.WriteByte((byte)len);
        return Convert.ToBase64String(ms.ToArray());
    }

    private byte[] GetAreaCode(string area)
    {
   
        return area switch
        {
   
            "CIO" => 0x30, // CIO区代码
            "WR" => 0x33,  // WR区代码
            "HR" => 0x34,  // HR区代码
            "DM" => 0x35,  // DM区代码
            _ => throw new ArgumentException("无效的内存区域")
        };
    }

    private void WriteAddress(MemoryStream ms, ushort addr)
    {
   
        ms.WriteByte((byte)(addr >> 8));   // 高字节
        ms.WriteByte((byte)addr);          // 低字节
        ms.WriteByte((byte)(addr >> 8));   // 扩展高字节
        ms.WriteByte((byte)addr);          // 扩展低字节
    }

    // 其他方法实现...
}

// TCP实现类
public class FinsTcpClient : IFinsClient
{
   
    private TcpClient _client;
    private NetworkStream _stream;
    private readonly byte[] _header = {
    0x02, 0x46, 0x49, 0x4E, 0x53 }; // FINS头

    public bool Connect(string ip, int port = 9600)
    {
   
        _client = new TcpClient();
        _client.Connect(ip, port);
        _stream = _client.GetStream();
        return SendCommand("STX@00FA0000000037ETX");
    }
}

二、关键功能实现

1. FCS校验算法

private byte CalculateFCS(byte[] data)
{
   
    byte checksum = 0;
    foreach (var b in data.Skip(FCS_OFFSET)) // 跳过STX和长度字段
    {
   
        checksum ^= b;
    }
    return checksum;
}

// 带校验的帧构建
private byte[] BuildFrame(byte[] payload)
{
   
    using var ms = new MemoryStream();
    ms.WriteByte(0x02); // STX
    ms.WriteByte((byte)payload.Length); // 长度
    ms.Write(payload, 0, payload.Length);
    ms.WriteByte(CalculateFCS(payload));
    ms.WriteByte(0x03); // ETX
    return ms.ToArray();
}

2. 异步通信处理

public async Task<byte[]> ReadAsync(int timeoutMs = 5000)
{
   
    var buffer = new byte[4096];
    var cts = new CancellationTokenSource(timeoutMs);

    try
    {
   
        int bytesRead = await _stream.ReadAsync(buffer, 0, buffer.Length, cts.Token);
        return buffer.Take(bytesRead).ToArray();
    }
    catch (OperationCanceledException)
    {
   
        throw new TimeoutException("读取超时");
    }
}

3. 响应解析器

public bool ParseReadResponse(byte[] response, out byte[] data)
{
   
    if (response.Length < 10) 
    {
   
        data = null;
        return false;
    }

    // 校验FCS
    var receivedFcs = response;
    var calcFcs = CalculateFCS(response.Skip(2).Take(response.Length - 3).ToArray());

    if (receivedFcs != calcFcs)
    {
   
        Debug.WriteLine("FCS校验失败");
        data = null;
        return false;
    }

    // 提取数据段
    data = response.Skip(6).Take(response.Length - 8).ToArray();
    return true;
}

三、完整使用示例

using (var plc = new FinsSerialClient("COM3"))
{
   
    if (plc.Connect())
    {
   
        // 读取D100开始的2个字
        if (plc.ReadMemory("DM", 100, 2, out byte[] data))
        {
   
            ushort value = (ushort)(data[0] << 8 | data[1]);
            Console.WriteLine($"D100值: {value}");
        }

        // 写入CIO 200地址
        plc.WriteMemory("CIO", 200, new byte[] {
    0x01, 0x00 });
    }
}

四、工业级优化方案

1. 连接池管理

public class FinsConnectionPool
{
   
    private readonly ConcurrentBag<IFinsClient> _clients = new();
    private readonly object _lock = new();

    public IFinsClient GetClient()
    {
   
        if (_clients.TryTake(out var client))
            return client;

        return CreateNewClient();
    }

    private IFinsClient CreateNewClient()
    {
   
        var client = new FinsSerialClient("COM3");
        client.Connect();
        return client;
    }

    public void ReturnClient(IFinsClient client)
    {
   
        _clients.Add(client);
    }
}

2. 批量操作优化

public class BatchCommand
{
   
    private readonly List<byte[]> _commands = new();

    public void AddRead(string area, ushort addr, ushort len)
    {
   
        _commands.Add(BuildReadCommand(area, addr, len));
    }

    public byte[] GetBatchData()
    {
   
        using var ms = new MemoryStream();
        foreach (var cmd in _commands)
        {
   
            ms.Write(cmd, 0, cmd.Length);
        }
        return ms.ToArray();
    }
}

3. 异常处理策略

public class FinsExceptionHandler
{
   
    private readonly Dictionary<byte, Action<byte[]>> _handlers = new();

    public void RegisterHandler(byte errorCode, Action<byte[]> handler)
    {
   
        _handlers[errorCode] = handler;
    }

    public void HandleError(byte[] errorFrame)
    {
   
        var code = errorFrame[2]; // 错误码位置
        if (_handlers.TryGetValue(code, out var action))
        {
   
            action(errorFrame);
        }
        else
        {
   
            Debug.WriteLine($"未知错误码: {code:X2}");
        }
    }
}

五、调试与测试工具

1. 串口监控器

public class SerialMonitor
{
   
    private SerialPort _port;

    public void StartCapture(string portName)
    {
   
        _port = new SerialPort(portName);
        _port.DataReceived += (s, e) =>
        {
   
            var data = new byte[_port.BytesToRead];
            _port.Read(data, 0, data.Length);
            File.WriteAllBytes($"capture_{DateTime.Now:yyyyMMddHHmmss}.bin", data);
        };
        _port.Open();
    }
}

2. 帧分析工具

public static class FrameAnalyzer
{
   
    public static string AnalyzeFrame(byte[] frame)
    {
   
        if (frame.Length < 5) return "无效帧";

        var type = frame[0] switch
        {
   
            0x01 => "读命令",
            0x02 => "写命令",
            _ => "未知类型"
        };

        var address = (frame[2] << 8) | frame[3];
        return $"类型: {type}, 地址: {address:X4}, 长度: {frame[4]}";
    }
}

六、部署建议

  1. 硬件配置

    • 工业PC:研华AIMB-501(支持宽温运行)

    • 通信模块:欧姆龙CP1E PLC + FINS兼容适配器

  2. 安全配置

    // 启用加密通信
    _port.EncryptMode = SerialPortEncryptMode.AES256;
    _port.SetEncryptionKey("YourSecureKey123");
    
  3. 性能调优

    • 设置ReadBufferSize = 65536

    • 启用DoubleBuffered = true

参考代码 C#写的欧姆龙PLC通信库与源码 www.youwenfan.com/contentalh/112013.html

七、扩展功能实现

1. 数据监控看板

public class RealTimeMonitor
{
   
    private Chart _chart;

    public void UpdateData(byte[] data)
    {
   
        var value = BitConverter.ToInt16(data, 0);
        _chart.Series[0].Points.AddY(value);
        if (_chart.Series[0].Points.Count > 1000)
        {
   
            _chart.Series[0].Points.RemoveAt(0);
        }
    }
}

2. 自动重连机制

public class AutoReconnect
{
   
    private readonly IFinsClient _client;
    private readonly int _retryInterval = 5000;

    public AutoReconnect(IFinsClient client)
    {
   
        _client = client;
        Task.Run(CheckConnection);
    }

    private async Task CheckConnection()
    {
   
        while (true)
        {
   
            if (!_client.IsConnected)
            {
   
                Debug.WriteLine("尝试重连...");
                await Task.Delay(_retryInterval);
                _client.Connect();
            }
            await Task.Delay(1000);
        }
    }
}
相关文章
|
16天前
|
人工智能 Linux API
OpenClaw新手正确入门指南:云端/本地部署、先跑通高频动作+免费模型配置流程
很多人初次接触OpenClaw(Clawdbot)时,都会陷入同一个误区:疯狂收集技能、对接各种平台、搭建复杂流程,却始终没有让工具真正解决一个自己每天都会遇到的实际问题。新鲜感带来的进度幻觉,会让人误以为安装越多、配置越复杂就越厉害,可真正使用时却发现流程混乱、响应不稳定、无法稳定复现结果。OpenClaw的核心价值从来不是“能做多少事”,而是“能稳定做好一件事”。对于新手而言,正确的入门方式不是堆砌功能,而是选定一个高频动作,把上下文、执行步骤、输出格式、校验规则全部理顺,让工具形成可重复、可依赖的稳定工作流。在此基础上,再进行技能扩展、流程串联、多平台部署,才能真正发挥这款开源AI代理工
170 4
|
16天前
|
弹性计算 云计算 开发者
阿里云服务器秒杀活动怎么参与?2026年入口+攻略全解
阿里云2026服务器秒杀活动火热进行中!新用户实名认证后,每日10点/15点抢购高性价比云服务器。本文详解参与资格、抢购入口、秒杀技巧及99元/年等备选方案,助个人开发者与初创企业低成本、高效率上云。
189 3
|
16天前
|
运维 Linux API
OpenClaw免费多模型接入实战|阿里云/本地部署+统一推理服务配置+免费API方案+常见问题排查
2026年,OpenClaw(Clawdbot)作为主流AI智能体框架,其核心价值在于灵活对接各类大模型实现复杂任务执行。但在实际使用中,多模型接入面临接口分散、密钥管理繁琐、切换流程复杂、运维成本高的痛点。而统一推理服务的出现,通过聚合主流大模型接口、提供标准化调用方式,将多模型接入简化为“单密钥+改配置”的轻量操作,完美解决了这一难题。
436 1
|
16天前
|
人工智能 架构师 程序员
AI真的会抢走工作吗?Anthropic最新研究给出了第一份真实数据
Anthropic最新报告《AI对劳动力市场的影响》基于真实使用数据、职业任务与统计分析,揭示AI尚未导致失业,但正加速重塑白领岗位:程序员75%任务可被覆盖,而厨师、维修工等物理型职业几乎不受影响;AI当前主攻“增强”而非“替代”,但初级岗位招聘已下降14%。
|
16天前
|
人工智能 JavaScript API
【最新】2026年阿里云无影云电脑部署OpenClaw保姆级图文流程
2026年,OpenClaw(Clawdbot)作为可执行任务、跨平台运行的开源AI智能体,已经形成云端与本地双轨部署体系。阿里云无影云电脑凭借图形化桌面、云端持久运行、安全隔离、权限可控等特点,成为OpenClaw长期稳定运行的首选环境;同时本地Windows11、macOS、Linux部署依然满足轻量化、隐私优先的使用场景。本文以无影云电脑为核心,完整覆盖2026年最新部署流程、环境配置、阿里云百炼Coding Plan免费大模型对接、常用命令与高频问题排查,全程可直接复制执行,无需额外依赖。
534 1
|
16天前
|
人工智能 Linux API
OpenClaw 全平台部署与配置手册:阿里云轻量应用服务器+本地三系统+免费模型对接教程
OpenClaw(Clawdbot,业内常称龙虾)作为2026年主流开源AI代理工具,支持云端长期稳定运行与本地灵活部署两种模式。云端部署可实现7×24小时不间断工作、不占用本地设备、功耗更低、安全性更可控;本地部署则适合隐私敏感、离线使用、轻量化测试场景。本文基于2026年最新环境,完整提供阿里云轻量应用服务器一键部署、本地Windows11/MacOS/Linux手动部署、阿里云百炼Coding Plan免费大模型API配置、通讯工具集成方法以及全场景常见问题解决方案,全程无冗余步骤,可直接按流程执行。
380 0
|
16天前
|
存储 安全 Linux
OpenClaw 阿里云/本地部署与核心Skill精选指南|实用技能组合及免费模型配置方案
OpenClaw作为轻量化可扩展的AI智能体框架,凭借灵活的技能扩展机制与稳定的执行能力,成为日常办公、信息处理、自动化任务执行的优选方案。面对数量丰富的技能组件,无需盲目安装,选用经过广泛验证的高频实用技能,即可覆盖绝大多数日常使用场景,同时保持系统简洁稳定。本文结合实际使用需求,整理适配日常场景的核心技能组合,说明各项技能的作用与价值,并完整提供阿里云环境部署、MacOS、Linux、Windows11本地部署流程,以及阿里云百炼Coding Plan免费大模型API配置方式,同时梳理使用过程中的常见问题,形成一套可直接落地的OpenClaw使用方案。
171 0
|
3月前
|
机器学习/深度学习 边缘计算 安全
C#实现OPC客户端
C#实现OPC客户端,结合OPC DA与OPC UA两种协议
|
16天前
|
人工智能 JSON 监控
【从零手写 ClaudeCode:learn-claude-code 项目实战笔记】(10)Team Protocols (团队协议)
本章详解AI团队协议设计:通过request-id、状态机(pending→approved/rejected)和内存追踪器,实现关机握手与计划审批两大结构化交互。告别s09的随意消息,构建可追溯、可审批、线程安全的协作范式。
143 7
|
16天前
|
文字识别 监控 数据可视化
把重复作业交给机器后,才明白1949ai聊的协同自动化工具到底省了多少无用功
本文介绍一位教务老师如何用开源自动化工具,将每日1.5小时重复工作(下载作业、分文件夹、录分数、发通知)全自动完成。全程无需编程,通过拖拽节点实现页面监控、文件处理、OCR识别与消息推送,兼顾隐私安全与低配电脑适配,展现协同自动化“所见即所得”的实用价值。(239字)

热门文章

最新文章