S7协议是西门子公司为其S7系列PLC(可编程逻辑控制器)通信而设计的一种专用协议。S7协议主要用于西门子PLC之间的通信,以及PLC与其他设备的通信。该协议支持多种通信方式,如MPI(多点接口)、PROFIBUS和Industrial Ethernet等。S7协议的报文结构相对复杂,可分为多个层次。
1. 简介
对比OSI参考模型的话,一层到四层(即物理层、数据链路层、网络层、传输层)与常规的TCP/IP通信相同,这里不在赘述。第五层(会话层)通过S7的TPKT实现,六层(表示层)通过COTP实现,S7Comm则于第七层(应用层)。
整个S7协议结构如下图(不含TCP/IP部分,下同)
TPKT头 | COTP头 | S7Comm头 | S7Comm参数 | 数据 |
---|
2.TPKT
TPKT头报文格式如下:
用途 | 版本 | 保留 | 长度 |
---|---|---|---|
长度 | 1byte | 1byte | 1byte |
描述 | 版本信息 | 保留(值为0x00) | TPKT、COTP、S7三层协议的总长度(单位字节) |
3.COTP
COTP分为两类,一类是COTP连接包,一类是COTP功能包。
- COTP连接包:COTP连接包主要用于建立、维护和断开COTP协议层的连接。这一过程包括连接请求(CR-Connect Request)、连接确认(CC-Connect Confirm)、断开请求(DR-Disconnect Request)和断开确认(DC-Disconnect Confirm)等步骤。通过这些连接包,COTP能够在通信双方之间建立一个稳定的、可靠的会话,保证数据的顺序传输和完整性。
- COTP功能包:COTP功能包用于在已建立的COTP连接上进行数据传输和控制信息交换。这包括数据传输(DT-Data Transfer)功能,通过它发送用户数据;以及一些控制功能,如流量控制、复位、错误报告等。功能包使得COTP能够在连接的基础上提供高效、可靠的数据交换服务。
简而言之,COTP连接包主要用于建立和管理连接,而COTP功能包则用于在这些连接上进行实际的数据传输和控制操作。
3.1 COTP连接包
用途 | 长度 | PDU类型 | 目的地参考 | 源地址参考 | 选项 | 参数 |
---|---|---|---|---|---|---|
长度 | 1byte | 1byte | 2byte | 2byte | 1byte | 不定 |
描述 | 除长度部分外COTP后续长度 | 指示PDU(Protocol Data Unit,协议数据单元)的类型 | 在建立连接时由接收方提供,用于标识目标或会话的唯一参考号。在连接建立后的通信中,这个字段用来确保数据包被送达到正确的会话。 | 在连接请求时由发起方提供,用于标识源或会话的唯一参考号。这同样用于确保通信双方在正确的会话中交换数据。 | 根据PDU类型不同,可能包含额外的控制信息 | 额外的参数或控制信息,这些信息的存在和格式依据PDU类型和选项字段而定。 |
其中PDU类型有以下选项:
- 0x1: ED Expedited Data,加急数据
- 0x2: EA Expedited Data Acknowledgement,加急数据确认
- 0x4: UD,用户数据
- 0x5: RJ Reject,拒绝
- 0x6: AK Data Acknowledgement,数据确认
- 0x7: ER TPDU Error,TPDU错误
- 0x8: DR Disconnect Request,断开请求
- 0xC: DC Disconnect Confirm,断开确认
- 0xD: CC Connect Confirm,连接确认
- 0xE: CR Connect Request,连接请求
- 0xF: DT Data,数据传输
3.1 COTP功能包
用途 | 长度 | PDU类型 | 选项 |
---|---|---|---|
长度 | 1byte | 1byte | 1byte |
描述 | 除长度部分外COTP后续长度 | 指示PDU(Protocol Data Unit,协议数据单元)的类型 | 根据PDU类型不同,可能包含额外的控制信息 |
4.S7Comm
报文结构如下
用途 | S7头 | 参数 | 数据 |
---|---|---|---|
长度 | 10或12byte | 不定 | 不定 |
描述 | 报文头 | 包含了执行特定操作所必需的控制信息 | 数据部分是可选的,具体取决于执行的操作类型。 |
4.1 S7头
报文结构如下:
用途 | 协议ID | 消息类型 | 冗余识别 | 议数据单元参考 | 参数长度 | 数据长度 | 错误类型 | 错误代码 |
---|---|---|---|---|---|---|---|---|
长度 | 1byte | 1byte | 2byte | 2byte | 2byte | 2byte | 1byte | 1byte |
描述 | 通常为0x32 | 指示消息类型 | 用于冗余管理,帮助识别和管理通信过程中可能出现的重复数据包,确保数据的一致性和准确性。通常为0x0000 | 这是一个标识符,用来将请求和相应的响应匹配起来。在复杂的通信过程中,这个字段确保了每个请求都能得到正确的响应。= | 参数字段的长度 | 数据部分的长度 | 可选,仅存在于Ack-Data消息中,如果传输过程中出现错误,这个字段将标识错误的类型 | 可选,仅存在于Ack-Data消息中,每个错误类型下可能有多个错误代码,指明了发生错误的具体原因 |
其中,PDU类型有以下值:
- 0x01- Job Request:主站发送的请求(例如读/写存储器,读/写块,启动/停止设备,通信设置)
- 0x02- Ack:从站发送的简单确认没有数据字段(从未见过它由S300 / S400设备发送)
- 0x03- Ack-Data:带有可选数据字段的确认,包含对作业请求的回复
- 0x07- Userdata:原始协议的扩展,参数字段包含请求/响应id,(用于编程/调试,SZL读取,安全功能,时间设置,循环读取..)
4.2 参数、数据
参数取决于消息类型,参数报文的第1个byte是功能码(此处仅介绍建立通讯、读取数据、写入数据三类报文格式)
4.2.1 建立通讯
在每个会话开始时会发送握手消息。它用于协商Ack队列的大小和最大PDU长度,双方都声明其支持的值以确保数据已成功传输。PDU和Ack队列长度字段都遵循大端的数据表示法。
发送请求的报文格式:
S7头消息类型 0x01- Job Request,是功能码为0xF0
用途 | 功能码 | 冗余数据 | Ack队列的大小(主叫) | Ack队列的大小(被叫) | 协商PDU长度 |
---|---|---|---|---|---|
长度 | 1byte | 1byte | 2byte | 2byte | 2byte |
描述 | 0xF0 | 0x00 |
响应请求的报文格式与发送请求的报文格式相同,但S7头消息类型0x03- Ack-Data。
4.2.2 读取数据
4.2.2.1请求报文
S7头消息类型 0x01- Job Request,是功能码为0x04。请求部分只有参数部分,没有数据部分。
用途 | 功能码 | 项目计数 | 项目1 | 项目2 | …… | 项目n |
---|---|---|---|---|---|---|
长度 | 1byte | 1byte | ||||
描述 | 0x04 |
每个项目的报文格式如下:
用途 | 变量规范 | 长度规范 | 地址规范 | 数据规范 | 数据长度 | DB编号 | 区域 | 地址 |
---|---|---|---|---|---|---|---|---|
长度 | 1byte | 1byte | 1byte | 1byte | 2byte | 2byte | 1byte | 3byte |
描述 | 通常为0x12 | 本项目剩余部分的长度 | IDS的地址规范的格式 | 数据传输的大小和变量类型 | 请求数据长度 | 如果访问的不是DB区域,此处为0x0000 | 数据的区域类型 | 要读取数据的地址 |
- 地址规范的常见值如下所示:
十六进制代码 | 标识 | 描述 |
---|---|---|
0x10 | S7ANY | S7-Any指针类似地址数据,例如DB1.DBX10.2 |
0x13 | PBC-R_ID | PBC的R_ID |
0x15 | ALARM_LOCKFREE | 报警锁定/释放数据集 |
0x16 | ALARM_IND | 报警指示数据集 |
0x19 | ALARM_ACK | 报警确认消息数据集 |
0x1a | ALARM_QUERYREQ | 报警查询请求数据集 |
0x1c | NOTIFY_IND | 通知指示数据集 |
0xa2 | DRIVEESANY | 见于Drive ES Starter,通过S7进行路由 |
0xb2 | 1200SYM | S7-1200的符号地址模式 |
0xb0 | DBREAD | DB块读取,仅在S7-400上见到 |
0x82 | NCK | Sinumerik NCK HMI访问 |
数据规范常见值如下:
值 | 类型 | 描述 | 长度单位 |
---|---|---|---|
0 | NULL | 空 | - |
3 | BIT | 位访问 | 位 |
4 | BYTE/WORD/DWORD | 字节/字/双字访问 | 位 |
5 | INTEGER | 整数访问 | 位 |
6 | DINTEGER | 双整数访问 | 字节 |
7 | REAL | 实数访问 | 字节 |
9 | OCTET STRING | 八位字节字符串 | 字节 |
数据区域常见值如下:
十六进制代码 | 描述 |
---|---|
0x03 | 200系列系统信息 |
0x05 | 200系列系统标志 |
0x06 | 200系列模拟量输入 |
0x07 | 200系列模拟量输出 |
0x80 | 直接访问外设 |
0x81 | 输入(I) |
0x82 | 输出(Q) |
0x83 | 内部标志(M) |
0x84 | 数据块(DB) |
0x85 | 实例数据块(DI) |
0x86 | 局部变量(L) |
0x87 | 未知(V) |
0x1c | S7计数器 |
0x1d | S7定时器(T) |
0x1e | 描述不明 |
0x1f | IEC计数器(200系列) |
0x20 | IEC定时器(200系列) |
4.2.2.2 响应报文
响应报文S7头消息类型0x03- Ack-Data。响应报文既有参数部分,又有数据部分。
参数部分:
用途 | 功能码 | 项目计数 |
---|---|---|
长度 | 1byte | 1byte |
描述 | 0x04 | 后续数据部分有几个 |
数据部分:
用途 | 返回码 | 数据规范 | 数据长度 | 返回数据 | 填充数据 |
---|---|---|---|---|---|
长度 | 1byte | 1byte | 2byte | 不定 | 不定 |
描述 | 表示返回信息类型 | 数据传输的大小和变量类型 | 后续数据长度 | 读取到的数据 | 如返回数据不到数据长度的长度,则填充一部分00至此 |
常见返回码类型:
十六进制代码 | 英文描述 | 中文描述 |
---|---|---|
0x00 | Reserved | 未定义,预留 |
0x01 | Hardware error | 硬件错误 |
0x03 | Accessing the object not allowed | 对象不允许访问 |
0x05 | Invalid address | 无效地址,所需的地址超出此PLC的极限 |
0x06 | Data type not supported | 数据类型不支持 |
0x07 | Data type inconsistent | 日期类型不一致 |
0x0a | Object does not exist | 对象不存在 |
0xff | Success | 成功 |
4.2.3写入数据
4.2.3.1 请求报文
S7头消息类型 0x01- Job Request,请求报文格式中参数部分和读取数据的相同,但功能码为0x05,且多了数据部分:
用途 | 返回码 | 数据规范 | 数据长度 | 写入数据 | 填充数据 |
---|---|---|---|---|---|
长度 | 1byte | 1byte | 2byte | 不定 | 不定 |
描述 | 通常为0x00 | 数据传输的大小和变量类型 | 后续数据长度 | 要写入的乳山市 | 如写入数据不到数据长度的长度,则填充一部分00至此 |
4.2.3.2 响应报文
参数部分请求报文,数据部分为:
用途 | 返回码 |
---|---|
长度 | 1byte |
描述 | 通常为0xff |