Modbus通信协议
主要参考这两篇文章
https://blog.csdn.net/2302_80169672/article/details/147104790
https://blog.csdn.net/m0_62588333/article/details/142598313

1.协议中的寄存器定义
bit 操作涉及的寄存器有 2 类:线圈状态(可读可写)、离散输入状态(只读)
16bit 操作的寄存器有 2 类:保存寄存器(可读可写)、输入寄存器(只读)


存储区范围:
(1)无论是什么存储区,都会有一个范围的限制;Modbus 的每个存储区也规定了一个范围, 不能无限制使用。
(2)Modbus 规定每个存储区的最大范围是 65536,也就是 0~65535。
协议地址模型
Modbus 地址公式:存储区代号 + (地址 + 1) 如下表所示:
温馨提示:离散型也被称为输入线圈,因此线圈就称为输出线圈以此区分两者。
长地址模型:

但是这么多的地址,现实中我们根本用不完,所以就有了短地址模型 :

2.协议概述
Modbus协议是一种单主/多从的通信协议,其特点是在同一时间总线上只能有一个主设备,但可以有一个或者多个(最多247个)从设备。Modbus通信总是由主设备发起,当从设备没有收到来自主设备的请求时,从设备不会主动发送数据。从设备之间不能相互通信,主设备只能同时启动一个Modbus访回事务处理。主设备可以采用两种方式向从设备发送Modbus请求报文,即主设备可以对指定的单个从设备或者线路上所有的从设备发送请求报文,而从设备只能在被被动接收请求报文后给出响应报文,即应答。
(1)查询
主发给从。查询消息中的功能代码告之被选中的从设备要执行何种功能。数据段包含了从设备要执行功能的任何附加信息。例如功能代码03是要求从设备读保持寄存器并返回它们的内容。数据段必须包含要告之从设备的信息:从何寄存器开始读及要读的寄存器数量。错误检测域为从设备提供了一种验证消息内容是否正确的方法。
(2)回应
从回应主。如果从设备产生正常的回应,在回应消息中的功能代码是在查询消息中的功能代码的回应。数据段包括了从设备收集的数据:象寄存器值或状态。如果有错误发生,功能代码将被修改以用于指出回应消息是错误的,同时数据段包含了描述此错误信息的代码。错误检测域允许主设备确认消息内容是否可用。
单播模式:
主设备仅仅寻址单个从设备,从设备接收并处理请求后,向主设备返回一个响应报文,即应答。在这种模式下,一个Modbus事务处理包含两个报文:一个是主设备的请求报文,另一个是从设备的响应报文。每个从设备必须有唯一的地址(地址范围为1~247),这样才能区别于其它从设备,从而可以独立被寻址,同时主设备不占用地址。

广播模式:
此种模式下,主设备可以向所有从设备发送请求指令,而从设备在接收到广播指令后仅进行相关指令的事务处理,而不要求返回应答。因此广播模式下,请求指令必须是Modbus标准功能中的写指令。根据Modbus标准协议的要求,所有从设备必须接收广播模式下的写指令,且地址0被保留,用来识别广播通信。

3.使用串口的Modbus报文帧
一个报文就是一帧数据,一个数据帧就一个报文:指的是一串完整的指令数据,本质就是一串数据。Modbus报文是指主机发送给从机的一帧数据,其中包含着从机的地址,主机想执行的操作,校验码等内容。
Modbus RTU与Modbus ASCII,都使用串口通讯协议,Modbus RTU使用二进制格式进行数据传输,通讯效率更高,Modbus ASCII使用ASCII码进行数据传输,可读性好,但通讯效率更低。
3.1 Modbus ASCII模式
当控制器设为在 Modbus 网络上以 ASCII 模式通信时,在消息中每个 8 位(b)字节都将作 为两个 ASCII 字符发送。这种方式的主要优点是字符发送的时间可隔可达到 1 秒且不产生 错误。
在 ASCII 模式下,消息 以冒号(:)字符(ASCII码为0x3A) 开始,以回车换行结束(ASCII码为0x0D、0x0A)。消息的其他字段(域)可以使用的传输字符是十六进制的0···9、A···F。处于网络上的Modbus设备不断侦测“:”字符,当接收到一个冒号时,每个设备进入解码阶段,并解码下一个字段(地址域)以判断是否是发给自己的。消息帧中的字符间发送的时间间隔最长不能超过1秒,否则接收设备将认为发生传输错误。

需要注意的是,在消息中的每个字节都作为两个ASCII字符发送
3.2 Modbus RTU 模式
Modbus协议RTU报文格式如下所示:

帧结构 = 从机地址 + 功能码 + 数据 + 校验
从机地址: 每个从机都有唯一地址,占用一个字节,范围 0-255,其中有效范围是 1-247, 其中255是广播地址。
功能码: 占用一个字节,功能码的意义就是,知道这个指令是干啥的,比如你可以查询从机的数据,也可以修改从机的数据,所以不同功能码对应不同功能。
数据: 根据功能码不同,有不同功能,比方说功能码是查询从机的数据,这里就是查询数据的地址和查询字节数等。
校验: 在数据传输过程中可能数据会发生错误,CRC检验检测接收的数据是否正确。
3.3 功能码概要
Modbus标准在协议中规定了以下3类Modbus功能码。
公共功能码:
- 被明确定义的功能码;
- 保证唯一性;
- 由 Modbus 协会确认,并提供公开的文档;
- 可进行一致性测试;
- 包括协议定义的功能码和保留将来使用的功能码。
用户自定义功能码: - 有两个用户自定义功能码区域,分别是 65~72 和 100~110;
- 用户自定义,无法保证唯一性。
保留功能码: - 保留功能码因为历史遗留原因,某些公司的传统产品现行使用的功能码不作为公共使用。
常见功能码:

3.4 Modbus报文分析

帧结构 = 从机地址 + 功能码 + 数据 + 校验
其中数据包括起始地址+寄存器数量的高低位:

我们是从0开始一次性读取10个寄存器,所以起始地址高低位都为00,而A对应的就是10。
丛机回应的信息格式:

需要关注的是字节数,因为保存寄存器都是16位的,假如有N个寄存器,所以对应的字节数量就是2N个字节,这里有10个寄存器,所以就会有20个字节,HEX14对应的就是DEC的20。
后面的就是每个寄存器的高低位和CRC校验位了。
温馨提示:如果是线圈,每个寄存器都是一位,所以答应报文中的字节数需要将寄存器数N/8,然后如果有余数家需要+1.
例:有9个线圈寄存器,9/8=1......1,所以需要+1,所以就需要两个字节。
4. RS-485 RS-232
Modbus通讯物理接口可以选用串口(包括RS232、RS485和RS422),也可以选择以太网口。
RS232,RS485是一种电平标准
数据在通信双方之间传输,本质是传输物理的电平比方说传输5V的电压-1V的电压信号,这些物理信号在传输过程中会受到很多干扰,比方说你传输一个5V的电压,到了接收端可能就变成了4.8V,并且通信的双方高低电平的参考电压可能不同。
RS-232
异步传输标准接口,同时对应着电平标准和通信协议(时序)。
全双工
逻辑1:-15V ~ 5V
逻辑0:+3V ~ +15V

RS-485
RS485是一种串口接口标准,为了长距离传输采用差分方式传输,传输的是差分信号,抗干扰能力比RS232强很多。
半双工
逻辑1:+2V ~ +6V
逻辑0:-2V ~ -6V
注意485的电平指的是485-A和485-B两根传输线,两线间的电压差。而不是传输线上的电压。

5. 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 ;
}

浙公网安备 33010602011771号