PLC通信协议
Modbus
Modbus协议介绍
Modbus是一种标准通信协议,是Modicon公司(现在的施耐德电气Schneider Electric)于1979年为使用可编程逻辑控制器(PLC)通信而发表。
Modbus协议是一个Master/Slave架构的协议:
- 1.即仅一设备(主设备)能初始化传输(查询),其它设备(从设备)根据主设备查询提供的数据作出相应反应;理论上最多支持247(10进制)台从设备。
- 2.主设备可单独和从设备通信,也能以 广播方式(站号0) 和所有从设备通信。如果单独通信,从设备返回一消息作为回应,如果是以广播方式查询的,则不作任何回应。
Modbus协议的应用
- 最早也应用最广泛的协议,几乎所有设备都支持
- 虽有标准,但都遵循的不是那么规范
Modbus通信模式
序号 | 类型与描述 | 典型应用特点 |
---|---|---|
1 | RTU模式(串口) | 传输大量数据,适合工业 |
2 | ASCII模式(串口) | 传输少量数据,适合计算机 |
3 | TCP模式(网口) | 传输严谨,效率低 |
4 | UDP模式(网口) | 传输效率高 |
Modbus RTU通讯
Modbus RTU报文
Modbus协议的报文(或帧)的基本格式是:地址码 + 功能码 + 数据区 + 校验码(注意“十六进制” “字节”)
地址码 | 功能码 | 寄存器地址 | 寄存器数量 | CRC校验 | |
---|---|---|---|---|---|
Modbus RTU | 1 byte | 1 byte | 2 byte | ||
eg: | 01 | 03 | 00 01 | 00 04 | 15 C9 |
数据字节:高位在前,低位在后
CRC校验:低位在前,高位在后
每报文(数据帧)最长为252字节,即最多126 个字
映射寄存器
设备类型 | 读写属性 | 应用定义 | 功能码(16进制) | Modbus协议地址 | 内部地址 |
---|---|---|---|---|---|
0x | 可读可写 | 线圈(输出点) | 01、05、0F | 0000 - FFFF | 000001 065536(0x) |
1x | 只读 | 离散量输入(输入) | 02 | 0000 - FFFF | 100001 165536(1x) |
3x 3x_Bit | 只读 | 输入寄存器(数据寄存器) | 04 | 0000 - FFFF | 300001 365536(3x) |
4x 4x_Bit | 可读可写 | 保持寄存器,写的时候功能码多为10 | 03、06、10 | 0000 - FFFF | 400001 465536(4x) |
5x | 可读可写 | 同4x,但在32位数据类型时,数据排放相反 | 03、06、10 | 0000 - FFFF | 500001 565536(5x) |
6x | 可读可写 | 同4x,但在写功能功能码为06 | 03、06、10 | 0000 - FFFF | 500001 565536(5x) |
常见功能码
功能码 | 名称 | 功能 | 对应的地址类型 |
---|---|---|---|
01 | 读线圈状态 | 读位(读N个bit)–读从机线圈寄存器,位操作 | 0x |
02 | 读输入离散量 | 读位(读N个bit)–读离散输入寄存器,位操作 | 1x |
03 | 读多个寄存器 | 读整型、字符型、状态字、浮点型(读N个words)–读保持寄存器,字节操作 | 4x |
04 | 读输入寄存器 | 读整型、状态字、浮点型(读N个words)–读输入寄存器,字节操作 | 3x |
05 | 写单个线圈 | 写位(写1个bit)–写线圈寄存器,位操作 | 0x |
06 | 写单个保持寄存器 | 写整型、字符型、状态字、浮点型(写一个word)–写保持寄存器,字节操作 | 4x |
0F | 写多个线圈 | 写位(写n个bit)–强置一串连续逻辑线圈的通断 | 0x |
10 | 写多个保持寄存器 | 写整型、字符型、状态字、浮点型(写n个word)–把具体的二进制值装入一串连续的保持寄存器 | 4x |
01 / 02 / 03 / 04 / 05 / 06等功能码的请求报文一定是8个字节
所有带CRC的完整报文再次进行CRC的结果一定是0000
数据类型
存储值 | 占用寄存器 | 类型名称 | 数据范围 | 解析结果 | 解析原理 |
---|---|---|---|---|---|
AE41 | 40108 | 16位无符号整数 | 0 - 65535 | 44609 | 16进制转10进制 |
AE41 | 40108 | 16位有符号整数 | -32768 到 32767 | -20927 | 最高位是0,则直接等于无符号;最高位是1,取补码 |
AE41 | 40108 | ASCII字符串 | RA | 扩展ASCII字符表 ISO-8859-1标准 | |
AE41 5652 | 40108 40109 | 32无符号整数 | 0 - 4294967295 | 2923517522 | 16进制转10进制 |
AE41 5652 | 40108 40109 | 双精度浮点数 | -4.395978E-11 | 浮点数的存储机制为(-1)^s * M * (2^E) |
Modbus CRC校验计算
- 预置16位寄存器为十六进制FFFF(即全为1)。称此寄存器为CRC寄存器;
- 把第一个8位数据与16位CRC寄存器的低位相异或,把结果放于CRC寄存器;
- 把寄存器的内容右移一位(朝低位),用0填补最高位,检查最低位;
- 如果最低位为0:重复第3步(再次移位);如果最低位为1:CRC寄存器与多项式A001(1010 0000 0000 0001)进行异或;
- 重复步骤3和4,直到右移8次,这样整个8位数据全部进行了处理;
- 重复步骤2到步骤5,进行下一个8位数据的处理;
- 最后得到的CRC寄存器即为CRC码。
CRC几余码在线计算网址:http://www.ip33.com/crc.html
Modbus RTU举例(读位)
发送:(02) (01) (00 00) (00 03) (7C 38)
主站告诉从站02,我要读取的位地址偏移为0、1、2的状态。其中 “01” 是读位的功能码,“00 00” 是位寄存器的起始地址,“00 03” 说明要连续读三个位寄存器的值。“7C 38” 代表最后的校验位。
接收:(02) (01) (01) (05) (91 CF)
从站回复:“02 01” 是复制了主站发来的地址和功能码,“01” 代表接下来的数据共有1个字节(8个位)。该字节寄存器地址值为05,转二进制 “0101” (即位寄存器0的值为1,位寄存器1的值为0,位寄存器2的值为1)。“91 CF” 代表最后的校验位。
Modbus RTU举例(读字)
发送:(09) (03) (00 04) (00) (03) 45 42
主站告诉从站09,我要读取的地址偏移为4、5、6的Holding Register的数值。其中"03"是读Holding Register的功能码,“00 04” 是字寄存器的起始地址,“00 03” 说明要连续读三个字寄存器的值,"45 42"代表最后的校验位。
接收:(09) (03) (06) (02 2B) (00 01) (00 64) 33 7A
其中"09 03"是复制了主站发来的地址和功能码,"06"代表接下来的数据共有6个字节。其中地址偏移为4的寄存器值为02 2B,地址偏移为5的寄存器值为00 01,地址偏移为6的寄存器值为00 64。33 7A"代表最后的校验位。
1.Modbus 协议报文(两个帧)间隔需要大于3.5个字符计算:
有校验位
1个字符 = 1(起始位)+ 8(数据位)+ 1(奇偶校验位)+ 1(停止位)= 11位
3.5个字符 = 3.5 * 11 = 38.5位
如果波特率 = 9600bps,则3.5个字符间隔时间为38.5 / 9.6 = 4.0104167ms;
字节间间隔时间 = 1.5 * 字符间隔时间 = 2.6042ms
无校验位
1个字符 = 1(起始位)+ 8(数据位)+ 0(无校验位)+ 1(停止位)= 10位
3.5个字符 = 3.5 * 10 = 35位
如果波特率 = 9600bps,则3.5个字符间隔时间为 36 / 9.6 = 3.6458ms
2.通常可以将传输45位的时间四舍五入后作为报文时间间隔
如果波特率 = 9600bps,则45位传输时间为 45 / 9.6 = 4.6875ms
Modbus TCP协议应用
TCP数据帧
ModbusTCP的数据帧可分为两部分:MBAP + PDU(报文头 + 帧结构)
MBAP为报文头,长度为7字节,由事务处理标识 + 协议标识符 + 长度 + 单元标识符 组成
内容 | 长度 | 解释 |
---|---|---|
00 00 | 2字节 | 可以理解为报文的序列号,一般每次通信之后就要加1以区别不同的通信数据报文 |
00 00 | 2字节 | 00 00表示ModbusTCP协议 |
00 06 | 2字节 | 表示接下来的数据长度,单位为字节 |
01 | 1字节 | 可以理解为设备地址。以上七个字节也被称为Modbus报文头 |
PDU(协议数据单元)由功能码 + 数据组成。功能码为1字节,数据长度不定,由具体功能决定。
Modbus TCP报文
读输出线圈(01功能码)
事务处理标识 | 协议标识 | 长度 | 单元标识 | 功能码 | 起始地址 | 数据长度 | |
---|---|---|---|---|---|---|---|
发送报文 | 2字节 | 2字节 | 2字节 | 1字节 | 1字节 | ||
示例: | 00 00 | 00 00 | 00 06 | 01 | 01 | 00 13 | 00 10 |
事务处理标识 | 协议标识 | 长度 | 单元标识 | 功能码 | 起始地址 | 数据长度 | |
---|---|---|---|---|---|---|---|
返回报文 | 2字节 | 2字节 | 2字节 | 1字节 | 1字节 | ||
示例: | 00 00 | 00 00 | 00 05 | 01 | 01 | 02 | 3C 25 |
读输入线圈(02功能码)
事务处理标识 | 协议标识 | 长度 | 单元标识 | 功能码 | 起始地址 | 数据长度 | |
---|---|---|---|---|---|---|---|
发送报文 | 2字节 | 2字节 | 2字节 | 1字节 | 1字节 | ||
示例: | 00 00 | 00 00 | 00 06 | 01 | 02 | 00 13 | 00 10 |
事务处理标识 | 协议标识 | 长度 | 单元标识 | 功能码 | 起始地址 | 数据长度 | |
---|---|---|---|---|---|---|---|
返回报文 | 2字节 | 2字节 | 2字节 | 1字节 | 1字节 | ||
示例: | 00 00 | 00 00 | 00 05 | 01 | 02 | 02 | 3C 25 |
读保持寄存器(03功能码)
事务处理标识 | 协议标识 | 长度 | 单元标识 | 功能码 | 起始地址 | 数据长度 | |
---|---|---|---|---|---|---|---|
发送报文 | 2字节 | 2字节 | 2字节 | 1字节 | 1字节 | ||
示例: | 00 00 | 00 00 | 00 06 | 01 | 03 | 00 13 | 00 02 |
事务处理标识 | 协议标识 | 长度 | 单元标识 | 功能码 | 起始地址 | 数据长度 | |
---|---|---|---|---|---|---|---|
返回报文 | 2字节 | 2字节 | 2字节 | 1字节 | 1字节 | ||
示例: | 00 00 | 00 00 | 00 07 | 01 | 03 | 04 | 2D 12 03 19 |
读输入寄存器(04功能码)
事务处理标识 | 协议标识 | 长度 | 单元标识 | 功能码 | 起始地址 | 数据长度 | |
---|---|---|---|---|---|---|---|
发送报文 | 2字节 | 2字节 | 2字节 | 1字节 | 1字节 | ||
示例: | 00 00 | 00 00 | 00 06 | 01 | 04 | 00 13 | 00 02 |
事务处理标识 | 协议标识 | 长度 | 单元标识 | 功能码 | 起始地址 | 数据长度 | |
---|---|---|---|---|---|---|---|
返回报文 | 2字节 | 2字节 | 2字节 | 1字节 | 1字节 | ||
示例: | 00 00 | 00 00 | 00 07 | 01 | 04 | 04 | 2D 12 03 19 |
写单个线圈(05功能码)
事务处理标识 | 协议标识 | 长度 | 单元标识 | 功能码 | 起始地址 | 数据长度 | |
---|---|---|---|---|---|---|---|
发送报文 | 2字节 | 2字节 | 2字节 | 1字节 | 1字节 | ||
示例: | 00 00 | 00 00 | 00 06 | 01 | 05 | 00 0A | FF 00 |
其中:通断标识为 FF00,标识线圈置ON;0000表示线圈置OFF。
返回报文:原文返回
写单个寄存器(06功能码)
事务处理标识 | 协议标识 | 长度 | 单元标识 | 功能码 | 起始地址 | 数据长度 | |
---|---|---|---|---|---|---|---|
发送报文 | 2字节 | 2字节 | 2字节 | 1字节 | 1字节 | ||
示例: | 00 00 | 00 00 | 00 06 | 01 | 06 | 00 0A | 00 2C |
返回报文:原文返回
写多个线圈(0F功能码)
事务处理标识 | 协议标识 | 长度 | 单元标识 | 功能码 | 起始地址 | 线圈数量 | 字节计数 | 写入值 | |
---|---|---|---|---|---|---|---|---|---|
发送报文 | 2字节 | 2字节 | 2字节 | 1字节 | 1字节 | 2字节 | 2字节 | 1字节 | 2字节 |
示例: | 00 00 | 00 00 | 00 09 | 01 | 0F | 00 0A | 00 10 | 02 | 1C A0 |
事务处理标识 | 协议标识 | 长度 | 单元标识 | 功能码 | 起始地址 | 线圈数量 | |
---|---|---|---|---|---|---|---|
返回报文 | 2字节 | 2字节 | 2字节 | 1字节 | 1字节 | 2字节 | 2字节 |
示例: | 00 00 | 00 00 | 00 09 | 01 | 0F | 00 0A | 00 10 |
写多个寄存器(10功能码)
事务处理标识 | 协议标识 | 长度 | 单元标识 | 功能码 | 起始地址 | 数量 | 字节计数 | 写入值 | |
---|---|---|---|---|---|---|---|---|---|
发送报文 | 2字节 | 2字节 | 2字节 | 1字节 | 1字节 | 2字节 | 2字节 | 1字节 | 2字节 |
示例: | 00 00 | 00 00 | 00 0B | 01 | 10 | 00 1C | 00 02 | 04 | 1C A0 20 41 |
事务处理标识 | 协议标识 | 长度 | 单元标识 | 功能码 | 起始地址 | 数量 | |
---|---|---|---|---|---|---|---|
返回报文 | 2字节 | 2字节 | 2字节 | 1字节 | 1字节 | 2字节 | 2字节 |
示例: | 00 00 | 00 00 | 00 06 | 01 | 10 | 00 1C | 00 02 |
ADS
ADS简介
- ADS即(Automation Device Specification)自动化设备规范。
- TwinCAT系统各模块均作为独立的设备
- 每个任务均存在一个服务模块,服务端或客户端
- 由Message Router统一交换数据
ADS支持多种协议
- 应用程序间TCP/IP通讯
- 基于Web的HTTP通讯
- 通过其他第三方协议(串口等)
ADS通讯原理
ADS设备唯一标识
- AdsAmsNetId(NetId):用于确定设备硬件
- AdsPortNr(AdsPort):用于确定软件服务
通讯端口 48898
- 基于TCP/IP协议
- TwinCAT ADS Router(ADS Server)监听端口 48898用于等待新的客户端
数据包格式
数据包 | 大小 | 描述 |
---|---|---|
AMS/TCP Header | 6 bytes | 包含了ADS Data的长度。 |
AMS Header | 32 bytes | 此处包含了通讯的发送发和接收方地址,以及ADS错误代码、ADS命令代码和其他一些信息。 |
ADS Data | n bytes | 此处包含了一个ADS命令的参数。参数的数据结构由ADS命令所决定,一些ADS命令也可以没有附加的数据。 |
AdsNetId组成
格式:xxx.xxx.xxx.xxx.xxx.xxx
例如:192.168.131.67.1.1
AdsNetId作为TCP/IP地址的扩展
注意:AdsNetId不是在IP地址后加 .1.1
AdsNetId构成
- 安装完TwinCAT,第一次启动时的IP地址加
.1.1
;NetId在任何时候都不会自动改变。 - 部分BC9000,BCXXXX控制器在当前的IP地址后加
.1.1
USS
USS协议
SIEMENS自己为PLC与驱动(变频器)定义的协议。
USS协议是一个 Master/Slave 架构的协议,适用于通讯效率不高,数据量不大。
- 即仅一设备(主设备)能初始化传输(查询),其他设备(从设备)根据主设备查询提供的数据做出相应反应;理论上最多支持31台从设备。
- 主设备可单独和从设备通信,也能以广播方式和所有从设备通信。如果单独通信,从设备返回一消息作为回应,如果是以广播方式查询的,则不作任何回应。
- 报文简单,报文数据长度可自由定义。
- 在从站端区分:部分数据PZD区支持实时通讯,所有数据PKW后台缓慢处理。
- USS协议与自由口协议只能任选一种。
设定从站变频器的通讯相关参数,保存后断电重启
P0010 | 用于对参数进行过滤,从而可以只选择与特定功能相关的部分参数 |
---|---|
P0970 | 设置 P0970 = 21,所有参数以及用户默认设置复位至出厂状态 |
P0003 | 设置 P0003 = 3,用户访问等级为专家等级 |
P0700 | 设置 P0700 = 5,即控制源来自 RS 485上的 USS 通信 |
P1000 | 设置 P1000 = 5,即设定源来自 RS 485上的 USS 通信 |
P2023 | 设置 P2023 = 1,RS 485 协议选择为 USS |
P2010[0] | 设置 RS485 上的 USS 通信速率。与PLC端设置一样 |
P2011 | 设置 P2011[0] = 1至31,即从站地址 |
P2012 | 设置 P2012[0] = 2,即 PZD 区长度为2个字长 (适配PLC库指令) |
P2013 | 设置 P2013[0] = 127,即 PKW区的长度可变 (适配PLC库指令) |
P2014 | 设置 P2014[0] = 0至65535,检查主站断线超时时间 |
P0971 | 设置 P0970 = 1,所有参数掉电保存 |