Modbus总结文档
1. 国际互联网组织保留TCP/IP协议栈上的系统502端口,专门用于访问Modbus设备。
2. Modbus串行网络结构:
3. 串行链路连接有两个模式: RTU和ASCII 两种模式之间不能通信。 RTU模式采用二进制表示数据,ASCII是人工可读。 RTU用循环冗余校验, ASCII采用纵向冗余检验。
TCP/IP的连接不需要检验和。
过程:
5. 两种通用的Modbus消息帧格式:
这地方字符概念比较模糊,没懂。
这里解释一下串行通信中的字符: 传送一个字符一般包括12位(也有其他情况的),1bit 起始位,通知对方接收, 8bit数据位,也就是你要传输的,1bit检验位(或没有),1bit或2bit停止位。所以一般是12bit传输一个8bit的字节。
当以ASCII模式通信时,消息中每个8bit的字节都要用两个ASCII字符来发送,所以效率比RTU模式低。
ASCII消息帧格式:
RTU消息帧格式:
注: 我们可以考虑用一个固定时间值来实现间隔。 协议规定,当波特率等于或小于19200bps时,要严格遵循时间间隔,大于时可用固定值,建议1.5字符时间间隔为750us,帧间间隔1750us。
6. 简述:一主多从。从设备最多247个,1~247(不知道为什么)。从设备之间不能通信。主设备与从设备有两种模式:单播模式和广播模式。
单播模式: 没什么说的,请求与应答。
广播模式: 主设备向所有设备发请求指令,其中地址码为0. 所有从设备接收到后处理,但不要求返回应答。请求指令必须是Modbus标准功能中的写指令。
7. Modbus寄存器:
线圈状态(coil status): 可读写,数字量输出。 例如:电磁阀输出LED显示
离散输入状态(input status): 可读不可写,数字输入。例如:拨码开关
保持寄存器(holding register): 可读写, 模拟量输入,例如:PID运行参数,传感器值。
输入寄存器(input register): 可读不可写, 模拟量输入。
8. CRC校验:
CRC有很多版本,比如CRC-8,CRC-12,CRC-16,CRC-32等。
Modbus采用CRC-16。
简述CRC过程,以CRC-16为例:
(1) 一个16位数与第一个8位二进制数相异或,把这个16位右移一位,最高位补0,看移出位是1还是0,若是0,继续右移,当是1,则这个16位于0xA001异或。
(2) 重复与这个8位数操作。共进行8次。
(3) 然后进行下一个8位数。
(4) 最后剩下的就是CRC检验码。
具体实现有两种: 查表法和计算法。查表速度更快,计算适用于所有长度数据,但慢一点。
计算法:
Unsigned short CRC16(unsigned char*puchMsg, unsigned short usDataLen)
{
inti, j;
unsignedshort usRegCRC = 0xFFFF;
for(i= 0; i < usDataLen; i++)
{
usRegCRC^= *puchMsg++;
for(j= 0; j < 8; j++)
{
If(usRegCRC& 0x0001)
{
usRegCRC= usRegCRC >>1 ^ 0xA001;
}
Else
{
usRegCRC >>= 1;
}
}
}
return usRegCRC;
}
查表法:
有一个表,可以上网查,书中没详细介绍。后面再看。
还有LRC校验。
最大帧260字节, 0~6字节是MBAP报头。
注: 一般情况下Unit Identifier填充0xFF,因为一般IP就可以识别了,所以这个就可有可无了。
例子:
查询报文: 00 00 00 00 00 06 09 03 00 04 00 01
解释:0x06:后续还有6个字节
0x09:单元标识码为9
0x03:功能码为3,即为读保持寄存器的值
0x00 0x04:Modbus起始地址4(即40005)
0x00 0x01:读取寄存器个数为1
响应报文: 00 00 00 00 00 05 09 03 02 00 05
解释:0x05:后续还有5字节
0x09:同查询报文
0x03:功能码,同查询报文
0x02:返回数据字节数
0x00 0x05:寄存器值。
10. Modus功能码详解:
(1) 占一个字节,范围1~127.之所以这样,是128代表异常(也就是最高位为1),然后异常后面加异常码也就是129~255(比如10000001为异常码为1的异常)。
(2) 有三类功能码: 公共功能码;用户自定义功能码(65~72,100~110);保留功能码(历史原因,不可用)
(3) 公共功能码:
注:Modbus协议规定的PDU中,规定所有线圈或寄存器地址从0开始。比如功能号是01,要读取00020~00056的线圈地址,则Modbus地址为00019-00055. 再比如读取保持寄存器地址40201-40203,用03功能码,则Modbus地址为200-202.
(4) 下面是很好的例子:
功能码是01的报文
查询报文:
注:线圈数量由两字节组成,取值范围只有0x0001~0x07D0(即1~2000)
响应报文:
功能码是03的报文(读保持寄存器)
响应报文: