Modbus总结文档

2017/8/30


1.    国际互联网组织保留TCP/IP协议栈上的系统502端口,专门用于访问Modbus设备。

 

2.    Modbus串行网络结构:

     

Modbus总结文档

 

3.    串行链路连接有两个模式: RTUASCII 两种模式之间不能通信。 RTU模式采用二进制表示数据,ASCII是人工可读。 RTU用循环冗余校验, ASCII采用纵向冗余检验。

TCP/IP的连接不需要检验和。

 

4.    通用的Modbus帧结构:
Modbus总结文档

 

       过程:

              主机设备Master(或客户端)创建Modbus应用数据单元形成查询报文。其中的功能码标识了向从机设备Slave(或服务器)指示将执行哪种操作。(注:每个系统只能有一个Master,每个Slave都有一个唯一地址),功能码一个字节,有效是1~255. 这其中128~255为异常响应保留。(也可以向一些功能码加入子功能码来定义多项操作)查询报文创建完毕,主机设备(或客户端)向从机或服务器发送该报文,收到后,根据功能码做相应动作,并发相应报文给主机设备。如图:
Modbus总结文档

但如果主机请求有错误,响应报文的功能码域将包括一个异常码。详细下图,从机设备返回一个功能码(注:异常的功能码8bit位的第一位位1. 也就是128~255)然后再还有一个异常码,所以回来的响应包括功能码和异常码
Modbus总结文档

 

5.    两种通用的Modbus消息帧格式:    

这地方字符概念比较模糊,没懂。

这里解释一下串行通信中的字符: 传送一个字符一般包括12位(也有其他情况的),1bit 起始位,通知对方接收, 8bit数据位,也就是你要传输的,1bit检验位(或没有),1bit2bit停止位。所以一般是12bit传输一个8bit的字节。

 

当以ASCII模式通信时,消息中每个8bit的字节都要用两个ASCII字符来发送,所以效率比RTU模式低。

 

ASCII消息帧格式:

消息以冒号(: )字符(ASCII0x3A)开始,以回车换行符结束(0x0D0x0A)处于网络中的设备不断侦测“ :”字符,当有一个时,进入解码阶段,根据地址来判断是否是发给自己的。
Modbus总结文档

RTU消息帧格式

区别每一帧的方法是监测中间的间隔时间。大于3.5个字符时间来区别。并且要求一帧数据必须连续发,每两个之间时间不能大于1.5个字符时间。(根据前面说的,假设1字符为11位,那3.5*11=38.5位,若波特率为9600, 那38.5*1000/9600=4.0104167ms,所以波特率为9600时,间隔大于4.0104167ms就行了。)
Modbus总结文档

注: 我们可以考虑用一个固定时间值来实现间隔。 协议规定,当波特率等于或小于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-8CRC-12CRC-16CRC-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校验。

 

9.    TCP/IP上的modbus协议的帧头是MBAP报文头。
Modbus总结文档

 

最大帧260字节, 0~6字节是MBAP报头。

 

对比:
Modbus总结文档

 

 

       MBAP报头说明:
Modbus总结文档

 

注: 一般情况下Unit Identifier填充0xFF,因为一般IP就可以识别了,所以这个就可有可无了。

例子:

查询报文: 00 00 00 00 00 06 09 03 00 04 00 01

       解释:0x06:后续还有6个字节

                0x09:单元标识码为9

                0x03:功能码为3,即为读保持寄存器的值

                0x00 0x04Modbus起始地址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总结文档

注:Modbus协议规定的PDU中,规定所有线圈或寄存器地址从0开始。比如功能号是01,要读取00020~00056的线圈地址,则Modbus地址为00019-00055. 再比如读取保持寄存器地址40201-40203,用03功能码,则Modbus地址为200-202.

 

(4)    下面是很好的例子:

 

功能码是01的报文

查询报文:

从设备地址为3,读取从设备Modbus地址00019~00055线圈共计37个的状态。起始线圈地址0x13(十进制00019)。
Modbus总结文档

注:线圈数量由两字节组成,取值范围只有0x0001~0x07D0(即1~2000

响应报文:

每个线圈占用1位, 1=ON0=OFF。例如线圈20~27的状态值为ON-ON-OFF-OFF-ON-OFF-ON-OFF,则表示为010100110x53)(注意对应关系!)如果不满就填0.比如37个需要5个字节来存放。
Modbus总结文档

           

 

功能码是03的报文(读保持寄存器)

从设备地址7, 读取保持寄存器地址40201~402033个寄存器内容。Modbus协议地址200~202, 所以起始地址0x00C8200),数量0x0003
Modbus总结文档

              响应报文:

       Modbus总结文档

 还没有总结完,以后继续完善。

相关文章: