欧姆龙通讯协议-Enthip/IP_ CIP报文(已测试)
Enthip/IP_ CIP报文格式
Ethernet Frame
└── IP Header
└── TCP Header
└── EtherNet/IP Encapsulation Header (24 bytes)
├─ Command (2 bytes)
├─ Length (2 bytes)
├─ Session Handle (4 bytes)
├─ Status (4 bytes)
├─ Sender Context (8 bytes)
└─ Options (4 bytes)
└── Encapsulation Data (Common Packet Format)
├─ Item Count (2 bytes)
├─ Address Item (Type/Length/Data)
├─ Data Item (Type/Length/CIP Message)
└── CIP Message (Message Router Request)
├─ Service (1 byte)
├─ Request Path Size (1 byte)
├─ Request Path (n bytes)
└─ Service Data (n bytes)
功能字分布在 3 层
-
EtherNet/IP Encapsulation(命令级)
-
CPF(承载方式级)
-
CIP(真正的“读 / 写 / 功能”)
Encapsulation Header(EtherNet/IP 功能字)
| 偏移 | 字节 | 字段 | 功能字说明 |
|---|---|---|---|
| 0x00 | 2 | Command | EtherNet/IP 功能字 |
| 0x02 | 2 | Length | 后续 CPF 长度 |
| 0x04 | 4 | Session Handle | 会话 ID |
| 0x08 | 4 | Status | 返回状态 |
| 0x0C | 8 | Sender Context | 标识 |
| 0x14 | 4 | Options | 固定 0 |
Command 功能字全集
| Command | Hex | 作用 |
|---|---|---|
| RegisterSession | 0x0065 | 建立会话 |
| UnRegisterSession | 0x0066 | 关闭会话 |
| SendRRData | 0x006F | 显式 CIP(读 / 写) |
| SendUnitData | 0x0070 | 隐式 IO |
| ListIdentity | 0x0063 | 设备发现 |
Address Item(是否连接)
| 字段 | 功能 |
|---|---|
| Type = 0x0000 | Null Address(无连接)用于显式消息 / CIP 无连接请求 |
| Type = 0x00A1 | TCP/IP Target Address(隐式消息 / I/O 消息) |
| Type = 0x8002 | UDP Target Address(特定厂商扩展) |
Data Item(承载 CIP)
| TypeID | 名称 | 含义 / 使用场景 |
|---|---|---|
| 0x00B2 | Unconnected Message | 最常用的显式 CIP 消息,未连接消息,适用于单次读写标签(Read Tag / Write Tag) |
| 0x00B1 | Connected Message | 已连接消息(通常用于实时 I/O),需要建立 CIP Connection |
| 0x00A1 | TCP/IP Target Address | 隐式消息(实时 I/O)目标地址,用于 I/O 连接 |
| 0x00A2 | UDP Target Address | 隐式消息(UDP)目标地址 |
| 0x8000+ | 厂商扩展 | 设备特定消息类型 |
CIP Message(真正的功能字核心)
Service (1)
Path Size (1)
Path (n)
Service Data (n)
Service(CIP 功能字全集)
Tag 访问(Logix PLC)
| 功能 | Service | 响应 |
|---|---|---|
| Read Tag/读取标签 | 0x4C | CC |
| Write Tag/写入标签 | 0x4D | CD |
| Read Fragmented | 0x52 | |
| Write Fragmented | 0x53 | |
| Multiple Service/多重复位 | 0x0A | 8A |
对象访问(标准 CIP)
| 功能 | Service |
|---|---|
| Get Attribute Single | 0x0E |
| Set Attribute Single | 0x10 |
Path 功能字(路径编码)
Tag 名
| 字节 | 含义 |
|---|---|
| 0x91 | ANSI Symbol |
| N | Tag 名长度 |
| ASCII | TAG |
Class / Instance
| 类型 | Code |
|---|---|
| Class | 0x20 |
| Instance | 0x24 |
| Attribute | 0x30 |
数据类型功能字
| 类型 | Code |
|---|---|
| BOOL | 0xC1 |
| BYTE | 0xC2 |
| INT | 0xC3 |
| DINT | 0xC4 |
| REAL | 0xCA |
| UINT | 0xC7 |
| UDint | 0xC8 |
| String | 0xD0 |
| Byte | 0xD1 |
| Word | 0XD2 |
| DWord | 0xD3 |
变量类型
| Type Name | Type Code | 描述 / 备注 |
|---|---|---|
| BOOL | 0xC1 | 单个位,1字节存储 |
| SINT (Short Int) | 0xC2 | 8位有符号整数 |
| INT (Integer) | 0xC3 | 16位有符号整数 |
| DINT (Double Int) | 0xC4 | 32位有符号整数 |
| LINT (Long Int) | 0xC5 | 64位有符号整数 |
| USINT | 0xC6 | 8位无符号整数 |
| UINT | 0xC7 | 16位无符号整数 |
| UDINT | 0xC8 | 32位无符号整数 |
| ULINT | 0xC9 | 64位无符号整数 |
| REAL | 0xCA | 32位浮点数 |
| LREAL | 0xCB | 64位浮点数 |
| STRING | 0xD0 | ASCII字符串,前2字节长度 |
| STRING2 | 0xD1 | ASCII字符串,前1字节长度 |
| STRINGN | 0xD2 | 可变长度字符串 |
| BYTE | 0xD1/D0? | 单字节数组,有时和 USINT 等价 |
| WORD | 0xD2 | 16位数据 |
| DWORD | 0xD3 | 32位数据 |
| LWORD | 0xD4 | 64位数据 |
| STRUCT | 0xA0 | 结构体类型 |
| ARRAY | 0x91 | 数组类型 |
常见场景对应类型
| PLC 标签类型 | CIP Data Type |
|---|---|
| BOOL | 0xC1 |
| SINT | 0xC2 |
| INT | 0xC3 |
| DINT | 0xC4 |
| REAL | 0xCA |
| LREAL | 0xCB |
| STRING | 0xD0 / 0xD1 |
| ARRAY[BOOL] | 0x91 + 0xC1 |
| ARRAY[DINT] | 0x91 + 0xC4 |
| STRUCT | 0xA0 + 子字段类型 |
变量类型与 Address Item Data 使用规则
| 场景 / 变量类型 | Address Item Data 内容 | 说明 |
|---|---|---|
| 单点 BOOL(简单 I/O、单变量) | 可以为空 0B 或占位 4B | PLC 允许逻辑寻址,报文简化,不需要指定路径 |
| 单 DINT / REAL / INT / WORD 等标量变量 | 通常 ≥ 4B | 需要指定目标对象路径(Connection Path)或 Logical Address,告诉客户端数据来源 |
| BOOL 数组 / WORD 数组 / DINT 数组 | ≥4B | 同样需要 Connection Path 或 Logical Address,通常还要加 Padding 保证 4B 对齐 |
| 结构体 / UDT(自定义数据类型) | ≥4B | 返回报文中必须包含 Address Item Data 指向结构体实例 |
| 多实例 / 多模块访问 | ≥4B | 必须明确目标模块或实例路径,否则客户端无法解析返回数据 |
| 隐式 I/O 读(Unconnected / I/O 模块) | 可空或占位 4B | 因为 PLC 端已经知道 I/O 地址,可省略明确路径 |
| 显式消息(Explicit Message)访问远程对象 | ≥4B | 必须包含完整 Connection Path,确保报文可以定位到对象 |
IP 与 Port 的规则
-
IP 只有
-
当你访问 本地 PLC、单模块对象或逻辑寻址的变量
-
EtherNet/IP 协议允许 Unconnected Message 或 Logical Addressing
-
PLC 端已经知道端口号 → 所以报文里只需要 IP 地址(4B)
-
Port 可以省略,报文更短
单 DINT 返回报文就是这种情况:只读 PLC 内部一个数据点(变量),只需要 IP 占位 4B
-
IP + Port
-
当你访问 远程模块或通过 Explicit Message 访问非本地对象
-
端口号必须明确,告诉客户端如何路由报文
-
EtherNet/IP 文档里提到:
-
Port ID 主要用于 CIP Explicit Message
-
对于 I/O 模块或连接到其他 PLC 的对象,如果报文需要发送到不同端口,必须包含 Port(2B)
-
-
什么时候需要 Connection Parameters / Extended Path
-
复杂对象,如多实例、多模块、多属性访问
-
Address Item Data = IP + Port + Path + Padding
-
保证总长度是 4B 的倍数
| 类型 | 本地 PLC / 逻辑寻址 | 远程模块 / Explicit Message |
|---|---|---|
| 单 BOOL | Address Item Data 可以空 | 需要完整 IP/Port/Path |
| BOOL 数组(本地) | 也可以空 | 需要完整 IP/Port/Path |
| DINT / REAL / 数组 | 可空或 4B 占位 | 需要 IP/Port/Path |
| 结构体 / UDT | 必须有 | 必须有 |
完整 EtherNet/IP 显式通信流程
1️⃣ RegisterSession → 建立会话(获取 Session Handle)
2️⃣ SendRRData (Read/Write)→ 显式 CIP 消息(读 / 写 / 多标签)
3️⃣ SendRRData Response → PLC 返回 CIP 响应
4️⃣ UnRegisterSession → 注销会话
测试环境
PLC:欧姆龙NX701-1600
该款PLC单次返回报文最大长度为542个字节
单次返回标签除去头部40byte+CIP头部6byte,剩余数据长度最长496byte
多服务标签中读取服务占用长度:8x+请求数据长度(为读取服务个数),写入服务占用长度:6x(x为写入服务个数)
诺返回数据超过542字节,PLC只会返回44字节,其中包含错误代码0x03(非法参数)

建立会话

提取 SessionHandle(0x000E0171)用于后续 CIP 通信。
显式 CIP 消息
Bool读取

Bool写入

Bool数组读取
一次性读取全部数组

解析示例
-
Byte0 =
B2→ 0b10110010 -
Byte1 =
69→ 0b01101001 -
Byte2 =
C8→ 0b11001000 -
Byte3 =
00→ Padding,忽略
Index : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Value : 0 1 0 0 1 1 0 1 1 0 0 1 0 1 1 0 0 0 1 1
读取固定数量

Bool数组写入

BYTE读取

BYTR写入

INT读取

INT写入

INT数组读取
INT数组写入

一次性读取INT数组全部数据
直接读取数组标签可以返回数组所有数据

一次性写入INT数组全部数据

DINT读取

DINT写入

DINT数组读取

DINT数组写入

STRING读取

STRING写入

多标签读取

多标签写入

断开连接

写入返回错误代码
General Status(低字节)
| Hex | 含义 | 说明 |
|---|---|---|
| 00 | Success | 写入成功 |
| 01 | Connection Failure | I/O 连接失败(只在 I/O 连接有效) |
| 02 | Resource Unavailable | 资源不可用(Tag不存在或PLC忙) |
| 03 | Invalid Parameter | 参数非法(长度/类型错误) |
| 04 | Path Segment Error | 路径错误(找不到标签、Path 错误) |
| 05 | Unexpected Error | 未知错误(PLC内部) |
| 06 | Memory Error | PLC 内存错误 |
| 07 | Not Supported | 不支持的服务或类型 |
| 08 | Object State Conflict | 标签被锁定或状态冲突 |
| 09 | Hardware Fault | 硬件故障(模块/PLC) |
| 0A | Transport Failure | 网络传输失败 |
| 0B | Access Denied | 权限不足 |
| 0C | Invalid Tag Type | 类型不匹配(写入类型错误) |
| 0D | Tag Full | Tag 容量不足,写入失败 |
| FF | Unknown Error | 未知错误或未定义状态 |
Extended Status(高字节)
| Hex | 含义 |
|---|---|
| 0001 | Tag 不存在 |
| 0002 | Tag 是只读 |
| 0003 | Tag 类型不匹配 |
| 0004 | 写入超出数组范围 |
| 0005 | 数据长度错误 |
| 0006 | PLC 内部错误 |
举例
| 场景 | 返回字节 | 说明 |
|---|---|---|
| 写入成功 | 00 00 | General Status = 0x00,Extended Status Count = 0 |
| 写入失败 + 有 1 条扩展 | 0C 01 03 00 | General Status = 0x0C,ExtCount = 1,Ext Code = 0x0003 |
| 写入失败 + 无扩展 | 0C 00 | General Status = 0x0C,ExtCount = 0 |
| 子服务 | General Status | Extended Status Count | Extended Status Codes |
|---|---|---|---|
| TAG1 BOOL | 00 | 00 | 无 |
| TAG2 USINT | 0C | 01 | 0003 |
| TAG3 INT | 04 | 01 | 0001 |
| TAG4 DINT | 00 | 00 | 无 |
| TAG5 REAL | 05 | 01 | 0006 |
8A 00 00 05 // Multiple Service Response Header
00 00 // TAG1 Success
0C 01 03 00 // TAG2 Error
04 01 01 00 // TAG3 Error
00 00 // TAG4 Success
05 01 06 00 // TAG5 Error
附录
附录五

附录六
附录七


附录八

附录九
附录十

| 十进制 | 十六进制 | 英文原文 | 中文含义(校对) |
|---|---|---|---|
| 0 | 0x0000 | Success | 成功 |
| 1 | 0x0001 | Connection failure | 连接失败(连接不存在或已失效) |
| 2 | 0x0002 | Resource unavailable | 资源不可用(内存/连接数不足) |
| 3 | 0x0003 | Invalid parameter value | 参数值无效 |
| 4 | 0x0004 | Path segment error | 路径段错误(编码错误) |
| 5 | 0x0005 | Path destination unknown | 路径目标未知(Class/Instance 不存在) |
| 6 | 0x0006 | Partial transfer | 部分传输成功 |
| 7 | 0x0007 | Connection lost | 连接丢失(超时/PLC 重启) |
| 8 | 0x0008 | Service not supported | 服务不支持 |
| 9 | 0x0009 | Invalid attribute value | 属性值无效 |
| 10 | 0x000A | Attribute list error | 属性列表错误 |
| 11 | 0x000B | Already in requested mode/state | 已处于请求的模式/状态 |
| 12 | 0x000C | Object state conflict | 对象状态冲突 |
| 13 | 0x000D | Object already exists | 对象已存在 |
| 14 | 0x000E | Attribute not settable | 属性不可写 |
| 15 | 0x000F | Privilege violation | 权限不足 |
| 16 | 0x0010 | Device state conflict | 设备状态冲突 |
| 17 | 0x0011 | Reply data too large | 响应数据过大 |
| 18 | 0x0012 | Fragmentation of a primitive value | 基本类型不允许分段 |
| 19 | 0x0013 | Not enough data | 数据不足 |
| 20 | 0x0014 | Attribute not supported | 属性不支持 |
| 21 | 0x0015 | Too much data | 数据过多 |
| 22 | 0x0016 | Object does not exist | 对象不存在 |
| 23 | 0x0017 | Service fragmentation sequence error | 分段顺序错误 |
| 24 | 0x0018 | No stored attribute data | 无存储的属性数据 |
| 25 | 0x0019 | Store operation failure | 存储失败 |
| 26 | 0x001A | Routing failure: request packet too large | 路由失败:请求包过大 |
| 27 | 0x001B | Routing failure: response packet too large | 路由失败:响应包过大 |
| 28 | 0x001C | Missing attribute list entry data | 属性列表缺少数据 |
| 29 | 0x001D | Invalid attribute list entry | 属性列表项无效 |
| 30 | 0x001E | Embedded service error | 嵌套服务错误 |
| 31 | 0x001F | Vendor specific error | 厂商自定义错误 |
| 32 | 0x0020 | Invalid parameter | 参数无效(广义) |
| 十进制 | 十六进制 | 英文原文 | 中文含义(校对) |
|---|---|---|---|
| 33 | 0x0021 | Write-once value or medium already written | 写一次属性已写过 |
| 34 | 0x0022 | Invalid reply received | 收到无效响应 |
| 35 | 0x0023 | Buffer overflow | 缓冲区溢出 |
| 36 | 0x0024 | Message format error | 消息格式错误 |
| 37 | 0x0025 | Key failure in path | 路径 Key 错误 |
| 38 | 0x0026 | Path size invalid | 路径大小无效 |
| 39 | 0x0027 | Unexpected attribute in list | 属性列表中出现意外属性 |
| 40 | 0x0028 | Invalid member ID | 成员 ID 无效 |
| 41 | 0x0029 | Member not settable | 成员不可写 |
| 42 | 0x002A | Group 2 only server general failure | Group 2-only 设备通用错误 |
| 43 | 0x002B | Unknown Modbus error | 未知 Modbus 错误 |
| 44 | 0x002C | Attribute not supported | 属性不支持(重复定义) |
| 100 | 0x0064 | The transaction has timed out | 事务超时 |
| 101 | 0x0065 | Forward Open command failed | Forward Open 失败 |
| 102 | 0x0066 | Invalid length | 长度无效 |
| 103 | 0x0067 | Unsupported protocol version | 不支持的协议版本 |
| 104 | 0x0068 | Unknown error response | 未知错误响应 |
| 105 | 0x0069 | Bad address structure | 地址结构错误 |
| 106 | 0x006A | PLC config changed: tags uploading | PLC 配置已更改(标签正在上传) |
| 107 | 0x006B | Transaction timeout count exceeded | 超过事务超时计数 |
| 108 | 0x006C | Requested port semaphore timed out | 端口信号量超时 |
| 109 | 0x006D | Command response mismatch | 命令响应不匹配 |
| 110 | 0x006E | Attempting to send invalid read msg to PLC | 尝试向 PLC 发送无效读取消息 |
| 111 | 0x006F | No connection buffer memory available | 无可用连接缓冲区内存 |
| 796 | 0x031C | Miscellaneous connection error | 其他连接错误 |
附录十一

测试代码分享
作者很懒,什么也没留下



浙公网安备 33010602011771号