Modbus通信协议详解-超级小白必懂
一、什么是Modbus协议
Modbus协议是一种用于工业控制的网络通讯协议,可以片面的理解为,Modbus协议一种机器与机器之间进行数据、信息传递的一种格式规范。
Modbus协议还遵循主从协议,支持单主机,多从机,最多支持247个从机设备。并且,在同一个通信线路上只会有一个主机,所有的通讯过程全部由主机主动发起,从机接收到主机请求后,会对请求做出响应。从机不会主动进行数据的发送,从机之间也不会有通讯过程。
二、Modbus 通讯方式
Modbus通讯物理接口可以选用串口(包括RS232、RS485和RS422),也可以选择以太网口。
表现在物理层就是,可使用3线232、2线485、4线422进行主从机之间的连接,或通过光纤、网线、无线网络等进行主从机之间的连接。
通俗一点来说:
主机从机之间想要实现通讯,需要将主机与从机进行连接,然后再进行数据传输。而连接方式有上述几种方式,连接实现之后,主机与从机之间就可以进行数据传输了。而它们传输的数据内容,均按照Modbus协议规定的格式进行转换。这样,就保证了能够让同一个主机与不同功能、不同厂家的设备之间进行准确的通讯。
2.1 查询---回应
(1)查询
查询消息中的功能代码告之被选中的从设备要执行何种功能。数据段包含了从设备要执行功能的任何附加信息。例如 功能代码03是要求从设备读保持寄存器并返回它们的内容。数据段必须包含要告之从设备的信息:从何寄存器开始读及要读的寄存器数量。错误检测域为从设备提供了一种验证消息内容是否正确的方法。
(2)回应
如果从设备产生正常的回应,在回应消息中的功能代码是在查询消息中的功能代码的回应。数据段包括了从设备收集 的数据:象寄存器值或状态。如果有错误发生,功能代码将被修改以用于指出回应消息是错误的,同时数据段包含了描 述此错误信息的代码。错误检测域允许主设备确认消息内容是否可用。
三、Modbus通信协议的特点
- 标准、开放、免费
- 支持多种电器接口,如串行接口RS-232、RS-485等,还可以在各种介质上传递,如:光纤、无线等
- Modbus的帧格式简单、紧凑、通俗易懂。用户使用简单,厂商开发简单
四、Modbus的4种寄存器类型
- 线圈(Coils)
- 想象一下:家中的电灯开关。
- 解释:线圈就像是电路中的一个开关,它只有两种状态:开(1)或关(0)。在工业控制系统中,线圈通常用来表示某个设备是否应该开启或关闭,比如启动一个电机或打开一个阀门。
- 离散量输入(Discrete Input)
- 想象一下:家中的门铃按钮。
- 解释:离散量输入就像是传感器或按钮的读数,它告诉你某个条件是否为真。例如,它可能表示一个限位开关是否被触发,或者一个安全门是否关闭。这些输入是只读的,因为它们只是反映外部设备的状态。
- 输入寄存器(Input registers)
- 想象一下:家中的温度计。
- 解释:输入寄存器用于存储从传感器读取的数值数据,比如温度、湿度或压力等。这些寄存器也是只读的,因为它们提供的是实时监测到的数据。
- 保持寄存器(Holding registers)
- 想象一下:家中的恒温器。
- 解释:保持寄存器可以存储和修改数据,它们通常用于配置参数或控制设置。例如,你可以设置一个保持寄存器来定义一个电机应该运行的速率,或者一个过程应该维持的温度。这些寄存器是可读可写的,允许你读取它们的当前值或者改变它们的值。
总结:线圈和离散量输入通常用于表示二进制状态(开/关),而输入寄存器和保持寄存器用于存储数值数据,其中输入寄存器是只读的,而保持寄存器可以读写。
五、Modbus的协议版本
包括Modbus RTU、Modbus ASCII、Modbus TCP/IP、Modbus UDP/IP等
Modbus RTU与Modbus ASCII,都使用串口通讯协议,Modbus RTU使用二进制格式进行数据传输,通讯效率更高,Modbus ASCII使用ASCII码进行数据传输,可读性好,但通讯效率更低。
Modbus TCP/IP是基于以太网的一种通讯方式,它将Modbus协议封装在TCP/IP协议栈中,通过以太网传输数据。具有高速、稳定的特点。
Modbus UDP/IP是基于UDP/IP协议的一种通讯方式。与Modbus TCP/IP不同,Modbus UDP/IP采用无连接的通讯方式,不保证数据的可靠性和顺序。相比于Modbus TCP/IP,Modbus UDP/IP的通讯开销较小,可以减少网络负载。
六、Modbus数据帧格式
无论哪一种Modbus协议版本的帧格式都是一样的
地址域:主机要访问的从机的地址
功能码:主机对从机实现的操作,功能码有很多,不同的功能码也对应操作不同类型的寄存器。比如:0x01读线圈、0x03读保持寄存器、0x06写单个寄存器、0x10写多个寄存器等。(更多功能码见下方Modbus功能码列表)
数据:根据功能的不同,以及传输的数据为请求数据还是响应数据的不同,会有不同的内容。(详见七、报文结构解析)
差错校验:为保障传输数据的准确性,modbus会进行差错校验,如Modbus CRC16校验等。
常用功能码:
七、报文结构解析(Modbus RTU版本)
此处以使用Modbus RTU版本、使用Modbus CRC16校验的保持寄存器(Holding registers)做演示。
1、0x01 读线圈状态
设备地址 | 功能码 | 寄存器地址高 | 寄存器地址低 | 数据高 | 数据低 | 校验高 | 校验低 |
1B | 1B | 1B | 1B | 1B | 1B | 1B | 1B |
设备地址(1字节) 功能码(1字节) 寄存器起始地址(2字节)线圈数量(2字节) CRC校验码(2字节)
设备地址 | 功能码 | 字节数 | 数据 | 校验高 | 校验低 |
1B | 1B | 1B | 若干 | 1B | 1B |
示例指令:
请求:01 01 00 00 00 0A BC 0D
含义:从机设备地址(01)+ 功能码(01)+ 起始寄存器完整地址(00 00)+ 线圈数量(00 0A)+ CRC16校验码(BC 0D)
解释:从地址为1的从机读取寄存器开始地址为1,连续读10个线圈。
应答:01 01 02 FF 03 B8 0D
含义:从机设备地址(01)+ 功能码(01)+ 数据字节数(02) + 读取到的数据内容(FF 03)+ CRC16校验码(B8 0D)
解释:从地址为1的从机中读取到两个字节的数据,读出的内容是FF 03。
2、0x05 写单个线圈
请求:01 05 00 00 FF 00 8C 3A
含义: 从机设备地址(01) + 功能码(05)+ 线圈起始地址(00 00)+ 写入状态(FF 00)+ CRC16校验码(8C 3A)
解释:从地址为1的从机中写入状态1到线圈地址为0中。
注意: 在写入状态中(FF 00 )代表写入1 ,(00 00) 代表写入0.
应答:01 05 00 00 FF 00 8C 3A
含义:从机设备地址(01) + 功能码(05)+ 线圈起始地址(00 00)+ 写入状态(FF 00)+ CRC16校验码(8C 3A)
解释:成功写入状态1到从机设备地址为1中
3、0x0F 写多个线圈
请求:01 0F 00 00 00 08 01 FF BE D5
含义:从机设备地址(01)+ 功能码(0F)+ 线圈起始地址(00 00 )+ 线圈个数(00 08)+ 所占字节数(01)+ 线圈状态(FF)+ CRC16校验码(BE D5)
解释: 从地址为1的从机中的线圈起始地址(0000)中写入8个状态,状态是(FF)。
响应:01 0F 00 00 00 08 54 0D
含义:从机设备地址(01)+ 功能码(0F)+ 线圈起始地址(00 00 )+ 线圈个数(00 08)+ CRC16校验码(BE D5)
解释:从地址为1的从机的线圈地址中成功写入线圈个数8个。
4、0x02 读离线输入
请求:01 02 00 00 00 05 B8 09
含义:从机设备地址(01)+ 功能码(02)+ 起始地址(00 00 )+ 读取数量(00 05)+ CRC16校验码(B8 09)
解释:从设备地址为1的起始地址为0读取5个Bit
应答:01 02 01 02 20 49
含义:从机设备地址(01)+ 功能码(02)+ 所占字节(01)+ 读取的数据(02)+ CRC16校验码(20 49 )
解释:从从机设备地址为1中读取了1个字节的数据,数据是02。
5、0x04 读输入寄存器
请求:01 04 00 00 00 02 71 CB
含义:从机设备地址(01)+ 功能码(04)+ 起始地址(00 00 )+ 读取数量(00 02)+ CRC16校验码(71 CB)
解释:从设备地址为1的起始地址为0中读取两个输入寄存器的值。
应答:01 04 04 00 01 00 01 6B 84
含义:从机设备地址(01)+ 功能码(04)+ 所占字节(04)+ 读出来的两个寄存器的值(00 01 00 01)+ CRC16校验码(6B 84)
解释:从设备地址为1中成功读取4个字节,第一个寄存器的值是(00 01),第二个寄存器的值是(00 01)。
6、0x03 读保持寄存器
请求:01 03 00 00 00 03 05 CB
含义:从机设备地址(01)+ 功能码(03)+ 起始地址(00 00 )+ 读取数量(00 03)+ CRC16校验码(05 CB )
解释: 从从机设备地址为1,起始地址为0中读取3个寄存器。
应答:01 03 06 00 1E 22 22 33 33 77 E0
含义:从机设备地址(01)+ 功能码(03)+ 所占字节数(06) + 读取的数据( 00 1E 22 22 33 33)+ CRC16校验码(77 E0 )
解释:成功读取到的数据是( 00 1E 22 22 33 33)
7、0x06 写单个保持寄存器
请求:01 06 00 00 00 1E 09 C2
含义:从机设备地址(01)+ 功能码(06)+ 保持寄存器地址(00 00 )+ 写入数据(00 1E) + CRC16校验码(09 C2)
解释:向从机设备地址为1的保持寄存器地址为0中写入值00 1E。
应答:01 06 00 00 00 1E 09 C2
含义:从机设备地址(01)+ 功能码(06)+ 保持寄存器地址(00 00 )+ 写入数据(00 1E) + CRC16校验码(09 C2)
解释:成功向从机设备地址为1,保持寄存器地址为0中写入值00 1E。如果06功能写入成功的话,请求码和响应码会是一样的。
8、0x10 写多个保持寄存器
请求:01 10 00 00 00 03 06 11 11 22 22 33 33 E7 55
含义:从机设备地址(01)+ 功能码(10)+ 保持寄存器起始地址(00 00 )+ 写入寄存器数量(00 03)+ 写入的字节数(06)+ 写入的数据(11 11 22 22 33 33)+ CRC16校验码(E7 55)
解释:在地址为1的从机中,向起始地址为0000的连续3个寄存器,分别写入11 11、22 22、33 33,字节数6个。
9、0x17读/写多个寄存器(写完再读出来)
请求:01 17 00 00 00 02 00 00 00 02 04 12 34 56 78 BC 74
含义:设备地址(01)+ 功能码(17)+ 读寄存器起始地址(00 00)+ 读寄存器个数(00 02)+ 写寄存器起始地址(00 00 )+ 写寄存器个数(00 02)+ 所占字节数(04)+ 写寄存器值(12 34 56 78)+ CRC16校验码(BC 74)
解释:在地址为1的从机中,向起始地址为00 00 的连续两个2寄存器中分别写入 12 34 、56 78,然后再读出来。
应答:01 17 04 12 34 56 78 82 13
含义:设备地址(01)+ 功能码(17)+ 所占字节(04)+ 读出来的数据(12 34 56 78)+ CRC16校验码
解释:成功在地址为1的从机中读出来4个字节的数据,读出来的数据是1234、5678。
八、CRC16校验
CRC计算方法:
1.预置1个16位的寄存器为十六进制FFFF(即全为1);称此寄存器为CRC寄存器;
2.把第一个8位二进制数据(既通讯信息帧的第一个字节)与16位的CRC寄存器的低8位相异或,把结果放于CRC寄存器;
3.把CRC寄存器的内容右移一位(朝低位)用0填补最高位,并检查右移后的移出位;
4.如果移出位为0:重复第3步(再次右移一位);如果移出位为1:CRC寄存器与多项式A001(1010 0000 0000 0001)进行异或;
5.重复步骤3和4,直到右移8次,这样整个8位数据全部进行了处理;
6.重复步骤2到步骤5,进行通讯信息帧下一个字节的处理;
7.将该通讯信息帧所有字节按上述步骤计算完成后,得到的16位CRC寄存器的高、低字节进行交换;
校验参考代码:
//CRC校验
void CRC_Checkout_16(uint8_t *p_data,uint32_t data_len,uint8_t *data_crc) {uint16_t wcrc = 0xFFFF;uint8_t temp;uint32_t i=0,j=0;for(i=0;i<data_len;i++){temp = *p_data & 0X00FF;p_data++;wcrc = wcrc^temp;for(j=0;j<8;j++){if(wcrc & 0X0001){wcrc>>=1;wcrc^=0XA001;}else{wcrc>>=1;}}}temp=wcrc;data_crc[0]=wcrc;data_crc[1]=wcrc>>8;return ;}