不好意思,我不是互联网人,不会谈论“颠覆传统行业”。
目录
一、概述
本文件汇总接触到的设备和协议。
目前接触的设备情况:
设备 | 连接方式 | 标准协议 | 私有协议 |
西门子PLC S7系列 | RS485 以太网 | Modbus RTU Modebus TCP | S7 |
温湿度传感器 | RS485 | Modbus RTU | |
电表 | RS485 | Modbus RTU | |
燃气表(体积修正仪) | RS485 | Modbus RTU | |
RFID | RS485 | 自定义 | |
地磅 | RS232 | 自定义 |
二、Modbus
2.1 modbus概要
Modbus协议分三种:运行在串行总线(多为RS485)上的modbus-RTU协议和modbus-ASCII协议,以及运行在以太网上的modbus-TCP协议。
三种协议功能相同、编码不同。
Modbus-RTU:二进制,如命令01,发送一个字节,值为1。
Modbus-ASCII:ASCII码,如命令01,发送两个字节,值为字符’0’和’1’。命令总是以’:’开始。由于发送数据量多一倍,实际很少用。
Modbus-TCP:使用TCP协议,默认端口502,命令和应答均以四字节标识和两字节数据长度开始,应答回复相同的标识。标识由事务标识和协议标识构成,实际由命令发送方自定。
2.2 协议组成
名称 | 字节数 | 说明 |
从站号 | 1 | 串行总线上可以接许多设备,用从站号来区分,发送命令的称为“主站”。大部分设备默认为1,可设置 |
命令 | 1 | |
起始地址 | 2高在前 | 此地址和设备内部地址无关(PLC内部地址可能为4开头的6位数,明显不在modbus两字节地址范围内)。由于某种原因存在一个混乱,某些软件显示起始地址从1开始,但实际发出的命令里的起始地址仍然从0开始(或许是内部地址从1开始造成的混乱)。 举个例子,PLC里面将内存100开始的32个字节设置为modebus模块的输出,那么命令03H的有意义的地址范围就是0-15,共16个保持寄存器,某些软件界面上第一个数据地址为0,而另外一些软件却是1,实际发出的指令里面都是0。 |
个数 | 2高在前 | 表示位的个数或寄存器的个数 |
数据字节数 | 1 | 只用于多写命令,因为只有一个字节,最多一次写255个字节 |
数据 | 寄存器数据每个两字节,高在前,位数据8位一个字节 | |
校验码 | 2低在前 | CRC校验码 |
2.3 常用命令
常用命令见下表,分别读写输入输出和内部寄存器,还有一些不常用的未列出。
名称比较专业,“线圈coil”就是输出,“继电器relay”就是输入,“保持寄存器”就是内存(一般是内存的一个段,而不是全部),寄存器总是两个字节16位。
命令 | 名称 | 格式 | 功能 |
01H | 读线圈 | 站号+命令+起始+个数+校验 | 读输出,按位 |
02H | 读离散量输入 | 站号+命令+起始+个数+校验 | 读输入,按位 |
03H | 读保持寄存器 | 站号+命令+起始+个数+校验 | 读内存,16位 |
04H | 读输入寄存器 | 站号+命令+起始+个数+校验 | 读输入,16位。跟02H的区别就是按双字节而不是按位读 |
05H | 写单个线圈 | 站号+命令+地址+数据+校验 | ON:FF 00 OFF:00 00 |
06H | 写单个寄存器 | 站号+命令+地址+数据+校验 | |
0FH | 写多个线圈 | 站号+命令+地址+个数+数据字节数+数据+校验 | 个数1-8数据1字节,个数9-16数据2字节 |
10H | 写多个寄存器 | 站号+命令+地址+个数+数据字节数+数据+校验 | 数据字节数=个数*2 |
写操作未详细验证。
2.4 常用命令的应答
命令 | 名称 | 格式 | 说明 |
01H | 读线圈 | ||
02H | 读离散量输入 | ||
03H | 读保持寄存器 | 站号+命令+数据字节数+数据+校验 | 数据字节数=个数*2 |
04H | 读输入寄存器 | ||
05H | 写单个线圈 | ||
06H | 写单个寄存器 | 同命令 | 与命令完全相同 |
0FH | 写多个线圈 | ||
10H | 写多个寄存器 |
2.5 异常码
如果有错误,可以回应异常码,异常码为命令码高位置1(即0?H变为8?H)。
格式为:站号+异常码+异常数据+校验
异常码 | 含义 |
01H | 非法功能 |
02H | 非法地址 |
03H | 非法数据 |
04H | 从站设备故障 |
05H | 命令已接受但需要较多时间处理,程序可以稍后查询 |
07H | 从站设备忙,程序可以稍后重试 |
08H | 存储奇偶校验错,主要与文件命令相关 |
0AH | 不可用网关路径 |
0BH | 网关目标设备响应失败 |
2.6 样本
2.6.1 modbusRTU
数据 | 说明 | |
请求 | 01 01 00 00 00 03 7C 0B | 从站:1 命令:1(读线圈,即输出) 起始地址:0 个数:3 校验:7C 0B |
应答 | 01 01 01 01 90 48 | 从站:1 命令:1 字节数:1 数据:01(第一个位为1) 校验:90 48 |
请求 | 01 02 00 00 00 03 38 0B | 从站:1 命令:2(读离散量输入) 起始地址:0 个数:3 校验:38 0B |
应答 | 01 02 01 00 A1 88 | 从站:1 命令:2 字节数:1 数据:00(所有位全0) 校验:A1 88 |
请求 | 01 03 00 00 00 03 05 CB | 从站:1 命令:3(读保持寄存器) 起始地址:0 个数:3 校验:05 CB |
应答 | 01 03 06 02 91 01 01 00 00 8D 76 | 从站:1 命令:3 字节数:6 数据1:02 91 数据2:01 01 数据3:00 00 校验:8D 76 |
请求 | 01 04 00 00 00 03 B0 0B | 从站:1 命令:4(读输入寄存器) 起始地址:0 个数:3 校验:B0 0B |
应答 | 01 04 06 00 00 00 00 00 00 60 93 | 除命令不同外其余同命令3 |
请求 | 01 05 00 00 00 00 CD CA 01 05 00 00 FF 00 8C 3A | 写单个线圈,地址:00 00 值:00 00 或 FF 00 |
应答 | 01 05 00 00 00 00 CD CA 01 05 00 00 FF 00 8C 3A | 操作成功,应答与请求完全相同 |
异常 | 01 85 02 C3 51 | 从站:1 异常命令:5(高位置1,因此为85) 错误码:2(地址无效) 校验:C3 51 |
请求 | 01 06 00 03 00 01 B8 0A | 从站:1 命令:6(写单个寄存器) 地址:3 数据:1 校验:B8 0A |
应答 | 01 06 00 03 00 01 B8 0A | 操作成功,应答与请求完全相同 |
请求 | 01 0F 00 01 00 09 02 FF 01 64 9D | 从站:1 命令:F(写多个线圈) 起始地址:1 个数:9 字节数:2 数据:FF 01(9个1) 校验:64 9D |
异常 | 01 8F 02 C5 F1 | 未观察到正常应答,总是返回异常码2 |
请求 | 01 10 00 03 00 02 04 00 03 00 04 42 79 | 从站:1 命令:10H(写多个寄存器) 起始地址:3 个数:2 字节数:4 数据:3 4 校验:42 79 |
应答 | 01 10 00 03 00 02 B1 C8 | 正常应答与请求相比只是没有携带数据,仍包含了起始地址和个数 |
2.6.2 modbusRTU、ASCII、TCP对比
类型 | 命令或应答 | 区别 |
RTU | 01 10 00 04 00 02 04 00 03 00 04 03 9F | 结尾:2字节校验码 |
ASCII | :0110000400020400030004DE(附加回车换行) | 起始:冒号 结尾:1字节校验码(转2个ASCII码)和回车换行 |
TCP | 00 02 00 00 00 0B 01 10 00 04 00 02 04 00 03 00 04 | 起始:4字节自定标识和2字节内容长度,本例中为11字节(即0BH) |
三、西门子S7协议
3.1 西门子S7协议概述
S7协议是西门子S7系列PLC的默认协议,开机即用,无需配置(串口和modebusTCP则必须首先编程配置才能使用),固定使用端口102。S7协议可以运行在MPI网络、PROFIBUS网络或以太网之上。
S7协议相当复杂,但我们关注点限于数据的读取和写入,类似modebus协议支持的功能,但稍多一些。
必须通过程序访问,而不是直接解析协议报文。
3.2 协议组成
名称 | 数据类型 | 说明 |
IP | IP地址(端口总是102) | |
机架rack | 整数 | 机架编号(实际用不用待确定) |
插槽slot | 整数 | 插槽位置 |
数据块 | 整数 | PLC内部数据块的编号 |
起始位置 | 整数 | 操作开始位置 |
字节数 | 整数 | 操作指定的字节数 |
个数 | 整数 | 操作的个数(对计时器和定时器) |
3.3 主要接口
主要参考S7操作库Snap7的client接口。与modbus相比主要增加了数据区读写,定时器、计数器和其他操作应该不用太关注。
操作 | 参数 | 说明 |
读写数据区 | 数据块 起始位置 字节数 | 按字节读,多字节整数高位在前 |
读写内部寄存器 | 起始位置 字节数 | 按字节读,高位在前 |
读写输入点位 | 起始位置 字节数 | |
读写输出点位 | 起始位置 字节数 | |
读写定时器 | 起始位置 个数 | 未实测,S7-1200不支持 |
读写计数器 | 起始位置 个数 | 未实测,S7-1200不支持 |
目录操作 | 以下未深究 | |
块操作 | ||
系统时间操作 | ||
系统信息操作 | ||
设备控制操作 | ||
安全功能操作 |
四、设备自定义协议
4.1 RFID
某款RFID读取设备。RS485上的自定义协议。
起始标记BB,结束标记7E,结束标记之前是校验码的低字节。
字节1:消息类型,0命令,1应答,2通知
字节2:指令代码
字节3和4:其后的数据字节数,不包括校验和结束标记
功能 | 格式/示例 | 说明 |
单读 | BB 00 22 00 00 22 7E | |
群读 | BB 00 27 00 03 22 FF FF 4A 7E | 红色两字节为读取次数 |
结束群读 | BB 00 28 00 00 28 7E | |
读取结果 | BB 02 22 00 11 D5 30 00 E2 00 10 71 00 00 52 9B 09 40 B4 02 EB 98 0C 7E | 红色12字节为卡号,其后两字节为卡的CRC |
未读到 | BB 01 FF 00 01 15 16 7E | 读取失败的应答 |
其它 |
4.2 地磅
某款地磅,RS232上的自定义协议,连续输出,每条数据18或17字节。
名称 | 字节数 | 说明 |
起始 | 1 | 02H |
状态字A | 1 | 小数点3位,分度2位 |
状态字B | 1 | 毛重、符号、超载、动态、单位各1位 |
状态字C | 1 | 打印、扩展显示各1位 |
显示重量 | 6 | 毛重或净重 |
皮重 | 6 | |
结束 | 1 | 0DH |
校验 | 1 | 可选 |
(这里是结束)