解释
指令 | 含义 |
---|---|
0x01 | 读线圈寄存器 |
0x02 | 读离散输入寄存器 |
0x03 | 读保持寄存器 |
0x04 | 读输入寄存器 |
0x05 | 写单个线圈寄存器 |
0x06 | 写单个保持寄存器 |
0x10 | 写多个保持寄存器 |
0x0F | 写多个线圈寄存器 |
线圈寄存器:实际上就可以类比为开关量(继电器状态),每一个bit对应一个信号的开关状态。所以一个byte就可以同时控制8路的信号。比如控制外部8路io的高低。 线圈寄存器不仅支持读还支持写,写在功能码里面又分为写单个线圈寄存器和写多个线圈寄存器。对应上面的功能码也就是:0x01(读) 0x05(写单个) 0x0F(写多个)
离散输入寄存器:如果线圈寄存器理解了这个自然也明白了。离散输入寄存器就相当于线圈寄存器的只读模式,它也是每个bit表示一个开关量,而他的开关量只能读取输入的开关信号,是不能够写的。比如我读取外部按键的按下还是松开。所以功能码也简单,就一个读的 0x02
保持寄存器:这个寄存器的单位不再是bit而是两个byte,也就是可以存放具体的数据量的,并且是可读写的。一般对应参数设置,比如我我设置时间年月日,不但可以写也可以读出来现在的时间。写也分为单个写和多个写,所以功能码有对应的三个:0x03(读) 0x06(写单个) 0x10(写多个)
输入寄存器:这个和保持寄存器类似,但是也是只支持读而不能写,一般是读取各种实时数据。一个寄存器也是占据两个byte的空间。类比我我通过读取输入寄存器获取现在的AD采集值。对应的功能码也就一个 0x04
区块 | 访问长度 | 访问方式 |
---|---|---|
线圈 | 位(bit) | 读/写 |
离散量输入 | 位(bit) | 只读 |
输入寄存器 | 字(word) | 只读 |
保持寄存器 | 字(word) | 读/写 |
使用硬石电子的ModbusSlaver和ModbusMaster和VSPD(虚拟串口软件)进行实操测试。
- 主机对从机读数据操作
上图Tx是主机Master发送的数据,Rx是从机Slave回传的数据
主机发送报文格式如下:
从机地址 | 功能码 | 起始地址(高) | 起始地址(低) | 查询数量(高) | 查询数量(低) | 校验码 |
---|---|---|---|---|---|---|
0x01 | 0x03 | 0x00 | 0x01 | 0x00 | 0x09 | 0xD4 0x0C |
/*发送数据解析*/
0x01 :从机的地址.
0x03 :查询功能,读取从机保持寄存器的数据.
0x00 0x01:代表读取的起始寄存器地址.说明从0x0001开始读取.
(注意:ModBus发送数据是高字节在前,低字节在后,并且Modbus把数据存放在寄存器中,通过查询寄存器来得到不同变量的值,一个寄存器地址对应2字节数据.)
0x00 0x09:查询的寄存器数量为0x0009(9)个,结合前面的(0x0001),意思是查询从0x0001开始的(9)个寄存器的值.
0xD4 0x0C:循环冗余校验,是ModBus的校验公式,从首个字节开始到D4前面为止.
从机回复报文格式如下:
从机地址 | 功能码 | 字节计数 | 字节1 | 字节N | 校验码 |
---|---|---|---|---|---|
0x01 | 0x03 | 0x12 | 0x00… | …0x01 | 0xD4 0xFF |
/*回复数据解析*/
0x01 :从机的地址.
0x03 :查询功能,读取从机保持寄存器的数据.
0x12 :返回字节数为0x12(18)个.
0x00 ... 0x01:寄存器的值(高位在前,低位在后.)
0xD4 0xFF : 循环冗余校验CRC.
- 主机对从机写单个数据操作
上图Tx是主机Master发送的数据,Rx是从机Slave回传的数据
主机发送报文格式如下:
从机地址 | 功能码 | 数据地址(高) | 数据地址(低) | 数据(高) | 数据(低) | 校验码 |
---|---|---|---|---|---|---|
0x01 | 0x06 | 0x00 | 0x0A | 0xBC | 0xDE | 0x59 0x50 |
/*发送数据解析*/
0x01 :从机的地址.
0x06 :修改功能,修改单个保持寄存器的数据.
0x00 0x0A:代表修改的寄存器地址,因为功能码是06,所以只修改这一个地址的数据.
0xBC 0XDE:代表修改的值为BC DE.结合前面的00 0A,意思是修改000A号寄存器的值为BC DE.
0x59 0x50:循环冗余校验CRC.
从机回复报文格式如下:
从机地址 | 功能码 | 数据地址(高) | 数据地址(低) | 数据(高) | 数据(低) | 校验码 |
---|---|---|---|---|---|---|
0x01 | 0x06 | 0x00 | 0x0A | 0xBC | 0xDE | 0x59 0x50 |
/*回复数据解析*/
0x01 :从机的地址.
0x06 :修改功能,修改单个保持寄存器的数据.
0x00 0x0A:代表修改的寄存器地址,因为功能码是06,所以只修改这一个地址的数据.
0xBC 0XDE:代表修改的值为BC DE.结合前面的00 0A,意思是修改000A号寄存器的值为BC DE.
0x59 0x50:循环冗余校验CRC.
从机的回复和主机的发送是一样的,如果不一样说明出现了错误!!!
- 主机对从机写多个数据操作
上图Tx是主机Master发送的数据,Rx是从机Slave回传的数据
主机发送报文格式如下:
从机地址 | 功能码 | 数据地址(高) | 数据地址(低) | 修改数量(高) | 修改数量(低) | 修改字节数量 | 字节1 | 字节N | 校验码 |
---|---|---|---|---|---|---|---|---|---|
0x01 | 0x10 | 0x00 | 0x01 | 0x00 | 0x03 | 0x06 | 0xAB… | …0xCD | 0x8C 0x30 |
/*发送数据解析*/
0x01 :从机的地址.
0x10 :修改功能,修改多个保持寄存器的数据.
0x00 0x01 :代表修改的起始寄存器地址,说明从0x0001开始.
0x00 0X03 :代表修改的寄存器数量.
0x06 :代表修改的总字节数,由于修改了3个寄存器,所以数据要有6个字节.
0xAB ... 0xCD:代表修改的值,结合上面,就是从第0001寄存器开始修改(3)个寄存器值为AB CD.
0xBC 0x30 :循环冗余校验CRC.
从机回复报文格式如下:
从机地址 | 功能码 | 数据地址(高) | 数据地址(低) | 修改数量(高) | 修改数量(低) | 校验码 |
---|---|---|---|---|---|---|
0x01 | 0x10 | 0x00 | 0x01 | 0x00 | 0x03 | 0xD1 0xC8 |
/*回复数据解析*/
0x01 :从机的地址.
0x10 :修改功能,修改多个保持寄存器的数据.
0x00 0x01:代表修改的起始寄存器地址,说明从0x0001开始.
0x00 0X03:代表修改的寄存器数量.从机告诉主机,你修改了哪几个寄存器
0xD1 0xC8:循环冗余校验CRC.
ModBus RTU 协议只需要看懂功能码0x03,0x06,0x10这三个基本的就已经足够了,分别回想下其数据域部分
03(查询
)-主机需要发送起始地址+寄存器数量,从机回复总字节数+数据;
06(修改单个
)-主机发送起始地址+数据内容(因为只需要修改一个,所以起始地址就是所要修改的地址),从机返回起始地址+数据内容(发现居然一样!)
10(修改多个
)-主机发送起始地址+寄存器个数+总字节数+数据,从机返回起始地址+寄存器数量