news 2026/2/28 20:11:58

C#与欧姆龙PLC NX102-9000测试FINS通信,使用TCP连接方式,保证通信数据重要...

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C#与欧姆龙PLC NX102-9000测试FINS通信,使用TCP连接方式,保证通信数据重要...

C#与欧姆龙PLC NX102-9000测试FINS通信,使用TCP连接方式,保证通信数据重要性,实时监测是否断线;实时读取D0至D1000寄存器数据,实时读取W0至W500的实时数据,将本机数据写入到D11000至D12000数据寄存器,保证数据交换正常;在工业环境中上位机软件需要与PLC交换数据,获取数据上传至MES系统中。 FINS通信速度较快,数据量大,非常好用。 希望能帮下开始使用欧姆龙PLC的工控朋友们

工业现场最刺激的莫过于看着自己写的代码成功撩上PLC。最近刚用C#调通欧姆龙NX系列的FINS协议,实测这货在千兆网络下能飙到每秒10万点数据吞吐,比某些慢吞吞的协议靠谱多了。直接上干货:

C#与欧姆龙PLC NX102-9000测试FINS通信,使用TCP连接方式,保证通信数据重要性,实时监测是否断线;实时读取D0至D1000寄存器数据,实时读取W0至W500的实时数据,将本机数据写入到D11000至D12000数据寄存器,保证数据交换正常;在工业环境中上位机软件需要与PLC交换数据,获取数据上传至MES系统中。 FINS通信速度较快,数据量大,非常好用。 希望能帮下开始使用欧姆龙PLC的工控朋友们

先整个TCP通信框架,核心就Socket那套东西:

public class OmronFinsClient { private Socket _clientSocket; private byte[] _receiveBuffer = new byte[4096]; private bool _isConnected; //心跳包间隔 private const int HeartbeatInterval = 3000; private System.Timers.Timer _heartbeatTimer; public bool Connect(string ip, int port) { try { _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _clientSocket.Connect(new IPEndPoint(IPAddress.Parse(ip), port)); StartHeartbeat(); return _isConnected = true; } catch{ /*记日志*/ return false; } } }

注意这个心跳计时器是保命用的,产线网络说崩就崩。定时发个空包探探路:

private void StartHeartbeat() { _heartbeatTimer = new System.Timers.Timer(HeartbeatInterval); _heartbeatTimer.Elapsed += (s, e) => { if(!SocketConnected) { _isConnected = false; //触发重连逻辑 } }; _heartbeatTimer.Start(); }

读D区数据要构造FINS命令帧,重点看地址转换:

public byte[] BuildReadCommand(int startAddress, int length) { //命令头 var header = new byte[] { 0x80, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }; //内存区标识:D区是0x82 byte[] addressBytes = BitConverter.GetBytes(startAddress).Reverse().ToArray(); //大端序 byte[] command = { 0x01, //读命令 0x82, //D区 addressBytes[0], addressBytes[1], //地址 0x00, //位地址 (byte)(length / 256), (byte)(length % 256) //读取长度 }; return header.Concat(command).ToArray(); }

这里Reverse()不是手滑,欧姆龙的地址排列是反人类的Big-endian(高位在前),必须把字节数组倒过来。比如D11000要转成0x00 0x02 0xAF 0xC8(别问我为什么,问就是日本人的脑回路)

处理响应数据时得注意粘包:

private void DataReceived(IAsyncResult ar) { int bytesRead = _clientSocket.EndReceive(ar); if(bytesRead > 0) { byte[] validData = new byte[bytesRead]; Buffer.BlockCopy(_receiveBuffer, 0, validData, 0, bytesRead); //解析数据头 if(validData.Length < 16) return; ushort dataLength = BitConverter.ToUInt16(new byte[]{validData[15], validData[14]}, 0); //提取有效数据 byte[] realData = validData.Skip(16).Take(dataLength).ToArray(); ProcessData(realData); //后续处理 } _clientSocket.BeginReceive(_receiveBuffer, 0, _receiveBuffer.Length, SocketFlags.None, DataReceived, null); }

写寄存器要注意数据打包:

public void WriteDRegisters(int startAddr, ushort[] values) { byte[] addrBytes = BitConverter.GetBytes(startAddr).Reverse().ToArray(); List<byte> payload = new List<byte>{ 0x02, //写命令 0x82, //D区 addrBytes[0], addrBytes[1], 0x00 //位地址 }; foreach(var val in values) { payload.AddRange(BitConverter.GetBytes(val).Reverse()); } SendCommand(payload.ToArray()); }

实际应用中有几个坑要注意:

  1. W区(CIO区)地址从0x00开始计算,和D区不同
  2. 连续读取超过960字会触发PLC保护机制
  3. 写入D11000这种高位地址需要确认PLC内存分配
  4. MES对接时建议用JSON中间件做数据缓冲

最后甩个实时监控的代码片段:

//创建双缓冲队列 ConcurrentQueue<PlcData> _dataQueue = new ConcurrentQueue<PlcData>(); void StartMonitoring() { Task.Run(() => { while(_isConnected) { var dData = ReadRange(0, 1000, MemoryType.D); var wData = ReadRange(0, 500, MemoryType.W); _dataQueue.Enqueue(new PlcData{ Timestamp = DateTime.Now, DRegisters = dData, WRegisters = wData }); Thread.Sleep(100); //根据PLC扫描周期调整 } }); }

记住,工控编程最重要的是稳如老狗。下次可以聊聊怎么用CRC校验防止数据被电磁干扰搞崩,那才是真·刺激战场。代码拿走不谢,出问题别找我(狗头)

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/27 8:47:50

[STM32L5] 【STM32L562 DK试用】基础外设体验

开发板自带了一块240*240分辨率的触摸屏&#xff1a;本次基于官方demo进行修改&#xff0c;从而在屏幕上显示相应的文字。首先进行系统和时钟的初始化&#xff1a;复制HAL_StatusTypeDef HAL_Init(void){ HAL_StatusTypeDef status HAL_OK; /* Set Interrupt Group Priorit…

作者头像 李华
网站建设 2026/2/27 9:36:10

[STM32L5] STM32L562E-DK开发板的BSP学习

该工程所在位置 STM32Cube_FW_L5_V1.5.0\Projects\STM32L562E-DK\Examples\BSP\MDK-ARM 打开工程&#xff0c;找到main.c的main函数&#xff0c;查看硬件初始化函数复制static void SystemHardwareInit(void){ /* Init LEDs */ if (LedInitialized ! SET) { if (BSP_L…

作者头像 李华
网站建设 2026/2/27 13:46:33

AI教材写作必备:掌握这些技巧,低查重教材轻松搞定

不少教材编写者常常感到沮丧&#xff0c;他们辛辛苦苦打磨出来的正文内容&#xff0c;却因为缺乏必要的配套资源而影响了教学效果。课后练习的题型设计需要层次分明&#xff0c;但往往缺少创新的想法&#xff1b;教学课件想要生动形象&#xff0c;却因技术限制而无法实现&#…

作者头像 李华
网站建设 2026/2/22 23:40:12

【OptisLang】设计优化

【OptisLang】设计优化 引言 正文 设计优化的三个重点 Author: JiJi \textrm{Author: JiJi} Author: JiJi Created Time: 2026.02.06 \textrm{Created Time: 2026.02.06} Created Time: 2026.02.06

作者头像 李华
网站建设 2026/2/23 3:54:24

【小程序毕设源码分享】基于springboot+小程序的在线答题微信小程序的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华