C#编写CIP通讯源码,欧姆龙NX1P通讯DEMO

一、项目基础配置与环境说明

(一)配置文件核心作用

  1. App.config与CIP_TEST.exe.config
    这两个配置文件功能一致,仅存在于不同目录(源码目录与编译输出目录),核心作用是指定程序运行依赖的.NET框架版本为.NET Framework 4.8。通过节点明确运行时环境,确保程序在兼容的框架下启动,避免因版本不匹配导致的启动失败或功能异常。
  1. CIPTEST.csproj项目配置文件
    作为项目的核心编译配置文件,主要承担以下职责:
    - 定义项目基础属性:指定输出类型为Windows窗体可执行程序(WinExe),根命名空间与程序集名称均为“CIP
    TEST”,目标框架版本为.NET Framework 4.8;
    - 区分编译模式:Debug模式下生成完整调试符号、不优化代码,便于开发调试;Release模式下优化代码、仅保留必要调试文件,提升运行效率;
    - 管理引用与文件:引入Windows Forms开发必需的组件(如界面绘制、数据处理相关库),关联核心代码文件(如CipHelp.cs、Form1.cs)并明确文件依赖关系,确保编译流程正常执行。

(二)项目文件结构与分工

项目共包含15个文件,按功能可分为四类:

  • 配置类:App.config、CIP_TEST.csproj等,负责环境与编译配置;
  • 核心功能类:CipHelp.cs(CIP协议处理)、PublicHandle.cs(公共枚举定义),实现通讯核心逻辑;
  • 界面类:Form1.cs(界面逻辑)、Form1.Designer.cs(界面布局),提供用户交互入口;
  • 辅助类:Program.cs(程序入口)、Properties目录下文件(程序集信息、资源管理),保障程序启动与基础信息管理。

二、核心功能类:CipHelp.cs(CIP协议处理)

该类是整个通讯Demo的核心,封装了CIP协议从会话建立到数据解析的全流程,命名空间为EntherNetIPCIP_,所有逻辑均围绕“与欧姆龙NX1P2 PLC通讯”展开。

(一)基础成员与数据映射设计

  1. 事件定义
    定义三个事件实现跨类通信:
    - SessionEvent:会话注册成功后触发,传递会话句柄信息,用于通知界面更新会话状态;
    - TagValueExchangeEvent:标签值发生变化时触发,传递标签名称、类型、值等信息,用于界面日志展示;
    - TagValueEvent:预留事件,当前版本未实际使用,为后续功能扩展预留接口。
  1. 标签映射字典
    设计三个字典实现标签的双向映射与值缓存,解决多标签并发读写的标识问题:
    - TagFlagTagValue:以标签“随机标志”为键,缓存标签当前值,用于快速对比值是否变化;
    - TagFlag
    TagStr:以标签“随机标志”为键,映射对应的标签名称,用于解析响应时匹配标签;
    - TagStr_TagFlag:以标签名称为键,映射对应的“随机标志”,用于构造请求时标识标签。
  1. 协议常量定义
    定义固定的CIP协议报文与字段:
    - RegisterSession:会话注册请求报文(命令码0x65),字节数组固定,无需动态修改;
    - UnregisterSession:会话注销请求报文(命令码0x66),初始为固定结构,后续需填充会话句柄;
    - 其他固定字段:如服务标识(读取0x4C、写入0x4D)、请求路径(0x20 0x06 0x24 0x01)、超时时间(0x0A 0xF0)等,均遵循CIP协议与欧姆龙NX1P2的通讯规范。

(二)辅助方法:RandStr()

功能是生成8位随机字符串,字符集包含数字、大小写字母与特殊符号(@#*)。生成逻辑基于当前时间戳作为随机数种子,确保每次生成的字符串唯一。该随机字符串作为标签的“唯一标志”(TagFlag),用于在报文的“发送方描述”字段标识标签,后续解析响应时通过该标志匹配对应的标签名称,避免多标签并发读写时的混淆。

(三)报文构造逻辑

  1. 单标签读取报文:GetCipRSingle_Tag()
    核心作用是根据输入的标签名称,生成符合CIP协议的读取请求字节数组,流程分为四步:
    - 标签标志初始化:若标签未生成“随机标志”,调用RandStr()生成并建立标签名称与标志的双向映射;
    - 标签编码处理:将标签名称以UTF-8编码转为字节数组,若字节数为奇数,末尾补0x00(满足CIP协议对偶数长度的要求);
    - CIP核心报文构建:依次添加服务标识(0x4C,读取)、CIP长度(按字计算)、标签类型标识(0x91)、标签编码字节、读取长度(1个元素),形成CIP协议核心数据段;
    - 完整报文封装:组合帧头(命令码0x6F、会话句柄、发送方描述等)、特定命令数据(接口句柄、超时时间等)、CIP核心报文与槽号(欧姆龙PLC固定路径参数),最终生成可直接发送的TCP报文。
  1. 单标签写入报文:GetCipWSingle_Tag()
    功能是生成BOOL类型标签的写入请求报文,流程与读取报文类似,但存在两处关键差异:
    - 服务标识改为0x4D(表示“写入标签”);
    - 核心报文段增加“写入类型”(0xC1,标识BOOL类型)与“写入值”(0x01为置位、0x00为复位)字段,根据输入的布尔值动态填充写入值,确保写入逻辑正确。

(四)数据解析逻辑

  1. 响应分发:RevmsgHandle()
    接收PLC返回的字节数组后,根据报文首字节(命令码)分发处理逻辑:
    - 命令码0x65:对应会话注册响应,调用GetSessionHandle()解析会话句柄;
    - 命令码0x6F:对应标签数据响应,调用Get
    SingleTagVal()解析标签值;
    - 其他命令码:当前版本未处理,直接忽略,符合“聚焦欧姆龙NX1P2核心通讯”的设计意图。
  1. 会话句柄解析:Get_SessionHandle()
    解析会话注册响应报文,流程为:
    - 提取报文长度与状态码,验证状态码是否为“成功”(0x0000,参考PublicHandle.cs中的枚举);
    - 若成功,从报文中提取会话句柄并赋值给SessionHandle成员,同时填充UnregisterSession报文的会话句柄字段,触发SessionEvent事件通知界面更新;
    - 若失败,根据状态码枚举显示错误信息(如“无效会话句柄”“内存不足”),便于问题排查。
  1. 标签值解析:GetSingleTagVal()
    解析标签数据响应报文,确保数据有效性与正确性,流程为:
    - 报文有效性校验:验证“帧头长度+数据长度”是否与总长度匹配、会话句柄是否一致、会话状态是否正常,若不满足则丢弃报文;
    - 提取标签标志:从“发送方描述”字段提取8位字符,作为标签的“随机标志”,匹配对应的标签名称;
    - 数据类型解析:根据报文中的“数据类型标识”(如0x00C1为BOOL、0x00D1为Byte),解析对应类型的标签值,支持BOOL、Byte、int、long、real、string六种常用类型;
    - 值变化判断:对比缓存的标签值(TagFlag
    TagValue),若发生变化则更新缓存,并触发TagValueExchangeEvent事件通知界面。

三、界面交互类:Form1.cs(用户交互与流程控制)

该类基于Windows Forms开发,提供完整的可视化操作界面,所有逻辑均围绕“用户操作→通讯执行→结果展示”的流程展开,是用户与PLC通讯的直接入口。

(一)界面布局与功能分区

界面通过Form1.Designer.cs定义布局,分为四个核心功能区,各区域分工明确:

  1. 连接参数区:包含IP地址(默认192.168.250.1)、端口(默认44818)输入框,以及“连接”“断开”“注册会话”按钮,负责TCP连接与CIP会话管理;
  2. 标签操作区:包含标签名称输入框、标签值显示框,以及“读取当前标签”“添加当前标签”“自动读取所有标签”“置位/复位”按钮,实现单标签读写与批量轮询控制;
  3. 标签列表区:包含ListBox(显示已添加标签)与“仅显示选中项”按钮,支持标签管理与单独监控;
  4. 日志展示区:多行文本框,显示标签值变化日志、操作日志(如“标签添加成功”)与时间戳,便于用户追溯操作与通讯结果。

(二)核心界面逻辑

  1. 连接与会话管理
    - 连接(button1Click):创建TCP Socket,连接用户输入的IP与端口,连接成功后禁用“连接”按钮、启用“断开”与“注册会话”按钮,确保操作流程正确;
    - 断开(button2
    Click):关闭TCP连接,重置会话句柄(SessionHandle),恢复按钮状态,避免无效操作;
    - 注册会话(button3_Click):发送RegisterSession报文(从CipHelp类获取),等待SessionEvent事件触发后,在界面显示会话句柄,完成会话建立。
  1. 标签操作逻辑
    - 读取当前标签(button4Click):调用CipHelp类的GetCipRSingleTag()生成读取报文,通过TCP发送给PLC,等待响应后更新标签值显示框;
    - 添加当前标签(button5Click):将输入的标签名称添加到本地轮询字典(TagNameTag)与ListBox,避免重复添加,同时在日志区显示“添加成功”信息;
    - 自动读取所有标签(button6Click):通过AutoRead布尔值控制自动轮询的启动/停止,启动时定时器(间隔1ms)按队列顺序发送所有已添加标签的读取请求,实现批量监控;
    - 置位/复位(button9
    Click):根据按钮当前文本(“置位”/“复位”)切换布尔值,调用CipHelp类的GetCipWSingle_Tag()生成写入报文,发送后切换按钮文本,实现BOOL标签的状态控制。
  1. 数据展示与监控
    - 标签值变化处理(CipHelpTagValueExchangeEvent):接收CipHelp类触发的事件,根据selectswitch布尔值(控制“仅显示选中项”功能)决定日志显示范围——若开启则仅显示选中标签的变化,否则显示所有标签变化,同时添加时间戳确保日志时效性;
    - 标签列表选中(listBox1SelectedIndexChanged):记录当前选中的标签名称,用于“仅显示选中项”功能的过滤;
    - 日志长度控制(textBox6
    TextChanged):当日志文本长度超过1000字符时清空文本框,避免内存占用过高导致界面卡顿。

(三)多线程与异步处理

为避免界面卡顿,程序采用“后台线程+定时器”的多线程设计:

  1. 数据接收线程:程序启动时创建后台线程(IsBackground = true),循环监听TCP Socket的接收缓冲区,收到数据后立即调用CipHelp类的RevmsgHandle()解析,确保数据处理不阻塞界面;
  2. 自动轮询定时器:使用System.Timers.Timer(间隔1ms),当AutoRead为true时,按队列(TagQueue)顺序发送标签读取请求,队列空时重新填充所有已添加标签,实现有序轮询,避免并发冲突。

四、公共枚举类:PublicHandle.cs

该类仅定义一个枚举State_Code,包含CIP通讯中常见的状态码,如“成功”(0x0000)、“无效命令”(0x0001)、“内存不足”(0x0002)、“无效会话句柄”(0x0064)等。每个枚举值均附带中文注释,明确状态含义,主要用于CipHelp类解析响应时判断通讯状态,以及在界面显示错误信息,降低问题排查难度。

五、程序入口与启动流程:Program.cs

该类是应用程序的入口,仅包含Main方法:

  1. 启用Windows可视化样式(Application.EnableVisualStyles()),确保界面符合系统外观;
  2. 禁用兼容文本渲染(Application.SetCompatibleTextRenderingDefault(false)),避免文本显示异常;
  3. 启动主窗体(Application.Run(new Form1())),触发Form1的Load事件,开启数据接收线程与定时器,完成程序初始化。

六、关键通讯流程与程序意图

(一)完整通讯流程(以读取标签为例)

  1. 用户在界面配置PLC的IP与端口(默认192.168.250.1:44818);
  2. 点击“连接”按钮,建立TCP连接;
  3. 点击“注册会话”按钮,发送CIP会话注册请求;
  4. PLC返回会话响应,CipHelp类解析会话句柄并通知界面显示;
  5. 用户输入标签名称,点击“读取当前标签”;
  6. CipHelp类生成读取报文,通过TCP发送给PLC;
  7. PLC返回标签数据响应,CipHelp类解析值并触发事件;
  8. 界面接收事件,更新标签值显示框与日志,完成一次读取流程。

(二)程序设计意图

从代码细节可明确,该Demo的核心意图是“为欧姆龙NX1P2 PLC提供CIP通讯的基础参考”,具体体现在三方面:

  1. 功能聚焦:仅实现“会话管理+单标签读写+批量轮询”核心功能,不冗余扩展,确保逻辑清晰,便于开发者理解;
  2. 协议合规:所有报文构造与解析均遵循CIP协议规范,且适配欧姆龙NX1P2的固定参数(如槽号、请求路径),确保通讯兼容性;
  3. 易用性:提供直观的界面与操作说明(button8_Click显示操作步骤),降低使用门槛,同时保留扩展空间(如预留事件、可修改的轮询间隔),便于开发者根据实际需求调整。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐