C#实现MODBUS TCP 通信 第一章(MODBUS 基础理论篇)
Modbus由MODICON公司于1979年开发,是一种工业现场总线协议标准。1996年施耐德公司推出基于以太网TCP/IP的Modbus协议:ModbusTCP。Modbus协议是一项应用层报文传输协议,包括ASCII、RTU、TCP三种报文类型。标准的Modbus协议物理层接口有RS232、RS422、RS485和以太网接口,采用master/slave方式通信。ModbusTCP的数据帧可分为两部分:MBAP+PDU。
MBAP为报文头,长度为7字节,组成如下:事务处理标识+协议标识+长度+单元标识符(2字节+2字节+2字节+1字节) ,通俗理解:MODBUS通信的数据内容开头部分,必须有7个字节,而且有固定规律。
MBAP各组成部分详细解释:
1.事务处理标识:可以理解为报文的序列号,一般每次通信之后就要加1以区别不同的通信数据报文。(可以固定为0x00 0x00,也可以是其他的,或者随机都可以,新学人员建议固定采用0x00 0x00,便于理解)
2.协议标识符:00 00表示ModbusTCP协议。(固定的,不可变)
3.长度:表示接下来的数据长度,单位为字节。(具体数据为:单元标识符+功能码+数据内容,是可变的但有规律)
4.单元标识符:可以理解为设备地址。(可以默认为0x01,可以固定)
PDU为数据内容(想要发送的消息内容):由功能码+数据内容组成。
功能码:功能码为1字节,数据长度不定,由具体功能决定。分别对应四种操作对象:线圈、离散输入、保持寄存器、输入寄存器。
根据操作对象以及是读还是写等动作,Modbus的功能码有:
0x01:读线圈
0x05:写单个线圈
0x0F:写多个线圈
0x02:读离散量输入
0x04:读输入寄存器
0x03:读保持寄存器
0x06:写单个保持寄存器
0x10:写多个保持寄存器
由此可以确定,功能码的内容只能是上面8个内容中的一个。
数据内容:即具体的通信内容(字节长度可变,不固定),这部分我们由示例来进行讲解
示例1:读线圈
具体的结构组成如下:
请求:MBAP 功能码 起始地址H 起始地址L 数量H 数量L(共12字节)
响应:MBAP 功能码 数据长度 数据(一个地址的数据为1位)
如:在从站0x01中,读取开始地址为0x0002的线圈数据,读0x0008位
00 01 00 00 00 06 01 01 00 02 00 08
回:数据长度为0x01个字节,数据为0x01,第一个线圈为ON,其余为OFF
00 01 00 00 00 04 01 01 01 01
具体拆分开分析上面的内容:
请求内容:00 01 00 00 00 06 01 01 00 02 00 08
事务处理标识(2字节):00 01
协议标识符(2字节):00 00
长度(2字节):00 06
单元标识符(1字节):01
功能码(1字节):01
数据内容(4字节):00 02 00 08
响应内容:00 01 00 00 00 04 01 01 01 01
事务处理标识(2字节):00 01
协议标识符(2字节):00 00
长度(2字节):00 04
单元标识符(1字节):01
功能码(1字节):01
数据内容(2字节):01 01
整理可得:示例1为我们做了一个查询,查询开始地址为0x0002,的8个线圈的状态,得到的结果为只有第一个线圈即地址为0x0002的线圈是ON状态,其余都是闭合状态,如果第一个和第二个都为ON状态返回的数据就应该是:00 01 00 00 00 04 01 01 01 01 02 01 ,以此类推。
示例2:读保持寄存器
请求:MBAP 功能码 起始地址H 起始地址L 寄存器数量H 寄存器数量L(共12字节)
响应:MBAP 功能码 数据长度 寄存器数据(响应内容的长度:9+寄存器数量×2)
如:起始地址是0x0000,寄存器数量是 0x0003
00 01 00 00 00 06 01 03 00 00 00 03
回:数据长度为0x06,第一个寄存器的数据为0x21,其余为0x00
00 01 00 00 00 09 01 03 06 00 21 00 00 00 00
具体拆分开分析上面的内容:
请求内容:00 01 00 00 00 06 01 03 00 00 00 03
事务处理标识(2字节):00 01
协议标识符(2字节):00 00
长度(2字节):00 06
单元标识符(1字节):01
功能码(1字节):03
数据内容(4字节):00 00 00 03
响应内容:00 01 00 00 00 09 01 03 06 00 21 00 00 00 00
事务处理标识(2字节):00 01
协议标识符(2字节):00 00
长度(2字节):00 09
单元标识符(1字节):01
功能码(1字节):03
数据内容(7字节):06 00 21 00 00 00 00
整理可得:示例2为我们查询了寄存器起始地址是0x0000,连续三个寄存器的值,得到的结果是第一个寄存器的数据为0x21,其余为0x00,其中返回的内容中的数据内容(06 00 21 00 00 00 00)由数据长度(06)+寄存器数据结果(00 21 00 00 00 00)构成
示例3:写单个保持寄存器
请求:MBAP 功能码 寄存器地址H 寄存器地址L 寄存器值H 寄存器值L(共12字节)
响应:MBAP 功能码 寄存器地址H 寄存器地址L 寄存器值H 寄存器值L(共12字节)
如:向地址是0x0000的寄存器写入数据0x0009
00 01 00 00 00 06 01 06 00 00 00 09
回:写入成功
00 01 00 00 00 06 01 06 00 00 00 09
具体拆分开分析上面的内容:
请求内容:00 01 00 00 00 06 01 06 00 00 00 09
事务处理标识(2字节):00 01
协议标识符(2字节):00 00
长度(2字节):00 06
单元标识符(1字节):01
功能码(1字节):06
数据内容(4字节):00 00 00 09
响应内容:00 01 00 00 00 06 01 06 00 00 00 09
事务处理标识(2字节):00 01
协议标识符(2字节):00 00
长度(2字节):00 06
单元标识符(1字节):01
功能码(1字节):06
数据内容(7字节):00 00 00 09
整理可得:示例3为我们向地址是0x0000的寄存器写入数据0x0009,并且写入成功,可以发现的是,写入寄存器的请求和响应的内容是一样的。即发送什么就返回什么表示写入成功。
示例4:写多个保持寄存器
请求:MBAP 功能码 起始地址H 起始地址L 寄存器数量H 寄存器数量L 字节长度 寄存器值(13+寄存器数量×2)
响应:MBAP 功能码 起始地址H 起始地址L 寄存器数量H 寄存器数量L(共12字节)
如:向起始地址为0x0000,数量为0x0002的寄存器写入数据,数据长度为0x04,数据为0x0099和0x1155
00 00 00 00 00 0B 01 10 00 00 00 02 04 00 99 11 55
回:写入成功
00 01 00 00 00 06 01 10 00 00 00 02
具体拆分开分析上面的内容:
请求内容:00 00 00 00 00 0B 01 10 00 00 00 02 04 00 99 11 55
事务处理标识(2字节):00 01
协议标识符(2字节):00 00
长度(2字节):00 0B
单元标识符(1字节):01
功能码(1字节):10
数据内容(4字节):00 00 00 02 04 00 99 11 55
响应内容:00 01 00 00 00 06 01 10 00 00 00 02
事务处理标识(2字节):00 01
协议标识符(2字节):00 00
长度(2字节):00 06
单元标识符(1字节):01
功能码(1字节):06
数据内容(7字节):00 00 00 02
整理可得:示例4为我们向地址为0x0000,和0x0001两个寄存器分别写入0x0099和0x1155,并且成功
以上就是我们对MODBUS TCP 通信协议的报文的解读,具体通信过程和程序实现我们另外在发帖具体说明。
不知道您还在不在这里,我有一个问题,您里面有一段是这样的:如果第一个和第二个都为ON状态返回的数据就应该是:00 01 00 00 00 04 01 01 01 01 02 01 ,以此类推。请问下这个状态不应该是“00 01 00 00 00 04 01 01 01 02”吗? 阳光下的心动 发表于 2022-11-13 20:56
不知道您还在不在这里,我有一个问题,您里面有一段是这样的:如果第一个和第二个都为ON状态返回的数据就应 ...
希望可以得到您的回复或者是别人的回复 的确写的不错 工作中常接触modbus通讯协议,但是看不懂啊,妥妥的菜鸟,从头开始慢慢认识它,谢谢楼主分享。 TCP 和rtu有什么区别呢? songxp03 发表于 2022-2-14 14:04
TCP 和rtu有什么区别呢?
最直观的就是TCP用的是网口,rtu用的是串口 15181692257 发表于 2022-2-15 07:52
最直观的就是TCP用的是网口,rtu用的是串口
谢谢大佬回复 很有用,学习了 感谢楼主分享,正在学习这个! 15181692257 发表于 2022-2-15 07:52
最直观的就是TCP用的是网口,rtu用的是串口
可以详细说下协议里面的区别吗?
页:
[1]
2