Modbus的基础学习

Modbus相关知识点

一、基本概念

1.1 Modbus基本概念

1.1.1 什么是Modbus?

Modbus是Modicon(施耐德)公司于1979年开发的串行通信协议。它最初设计用于公司的可编程逻辑控制器(PLC)。Modbus是一种开放式协议,支持使用RS232/RS485/RS422协议的串行设备,同时还支持调制解调器。它的简单性以及制造商可以免费将其纳入其产品的事实使其成为连接工业电子设备的最流行的方法。Modbus比其他通信协议使用的更广泛的主要原因有以下几点:

  • 公开发表并且无著作权要求;
  • 易于部署和维护;
  • 对供应商来说,修改移动本地的比特或字节没有很多限制;

Modbus通过设备之间的串行线进行数据传输。最简单的设置是使用一根串行电缆连接两个设备(主设备和从设备)上的串行端口。数据以称为比特的1和0的序列发送。每个位都作为电压发送。0被发送为正电压,1被发送为负电压。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-evUMELhb-1631626547711)(https://i.loli.net/2021/08/11/ZgVDlzY2uyk95UL.png)]

1.1.2 主从模式

Modbus解决了通过串行线路在电子设备之间发送信息的问题。该协议在遵循该协议的体系结构中实现主/从模型。Modbus主站(Master)负责从其他设备(Slave)请求信息。标准Modbus网络中有一个Modbus主站。具体如下图所示;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wH2nBQA6-1631626547713)(https://i.loli.net/2021/08/11/GtmOi1xVpfacUIh.png)]

主设备向从设备请求信息,最多大约可达到240个 . 每个从设备都有自己唯一的从设备地址标识(Slave Address)。除了从从设备请求信息之外,主设备还可以写入从设备的内部寄存器

1.2 应用场景

modbus是专为工业开发的协议,所以主要用于工业场合,也可以用于基础设施,如:住宅、商业中心、机场、水处理、电厂等。

modbus RTU协议紧凑,可以使用RS232/RS485、无线、等介质,用于速度要求不高的场合,如:楼宇、工业现场、管道输送、远程泵站等;

modbusASCII协议比较宽松,时序要求不高,可以用于条形码阅读器、打印机、仪器仪表读取等;

modbusTCP速度很高,可以用于实时控制、时钟对时、全局数据、发送邮件、故障设备替换、网络管理、用户网页制定和浏览、固件更新等多种服务。

1.3 三种通信模式

最常用Modbus协议总共有以下三种:Modbus ASCIIModbus RTUModbus TCP

Modbus TCP基于以太网和TCP/IP协议

Modbus RTU和Modbus ASCII则是使用异步串行传输(通常是RS-232/422/485)

1.3.1 Modbus ASCII模式
起始地址码功能码数据校验回车换行
字符 ‘:’(冒号)两字节两字节0到2 * 252字节两字节(LRC校验)两字节(CR,LF)

帧的起始一字符 ’ : '冒号开始,结束为回车换行,其对应的16进制可以到ASCII表中进行查询。字节间传输的间隔时间不能大于1s,大于1s认为这一帧数据丢失.同样我们可以计算出来ASCII帧的最大长度是513字节。

RTU使用CRC校验ASCII使用LRC校验。

当设备设置为使用ASCII(美国信息交换标准代码)模式在MODBUS串行线上进行通信时,消息中的每个8位字节将作为两个ASCII 4位字符发送。当物理通信链路或设备的功能不允许符合RTU计时器管理要求时,使用此模式。所以此模式的效率不如RTU,因为每个字节需要两个字符。示例:字节0x7D编码为两个字符:0x35和0x42(在ASCII表中为0x37 =‘7’,而0x44 =‘D’)。

1.3.2 Modbus RTU模式
地址码功能码数据校验码
一字节一字节n字节两字节(CRC)

从机都有相应的地址码,便于主机识别,从机地址为0到255,0为广播地址,248-255保留。总线上只能有一个主设备,但可以有一个或者多个(最多247个 ip地址1-247)从设备。

广播模式:主设备向所有的从设备发送请求指令,从设备收到指令后,各自处理,不要求返回应答;这种模式下,请求指令必须是Modbus标准功能中的写指令;比如 0x06,0x10 功能码。

其中数据以帧为单位进行数据传输,每帧最长为252字节,最短为0字节。如果一byte数据的传输时间为T,那么每两帧之间的间隔最小应该要大于3.5T,否则从机不能分辨这是两帧。第二,同一帧连续的两个数据之间的间隔时间不能超过1.5T,否则节点会认为这一帧数据不完整,这说明我们在modbus传输的时候要使能一个定时器的工作。

例子:

发送:09 03 00 04 00 03 XX

主站告诉从站09,我要读取的地址偏移为4、5、6的Holding Register的数值。其中"03"是读Holding Register的功能码,"00 04 00 03"是数据区,"00 04"是寄存器的地址,"00 03"说明要连续读三个寄存器的值。"XX"代表最后的校验位。

接收:09 03 06 02 2B 00 01 00 64 XX

从站回应该地址偏移为4的寄存器值为02 2B,地址偏移为5的寄存器值为00 01,地址偏移为6的寄存器值为00 64。其中"09 03"是复制了主站发来的地址和功能码,"06"代表接下来的数据共有6个字节。

Modbus RTU是一种紧凑的,采用二进制表示数据的方式;因为使用二进制编码和CRC错误检查的结合使得Modbus RTU适用于工业应用,因为它比ASCII字符的替代方案更有效地传输。在Modbus RTU与ASCII之间进行选择时,如果考虑性能,则RTU是首选。

1.3.3 Modbus TCP模式

ModbusTCP的数据帧可分为两部分:MBAP+PDU。

主站为client端,主动建立连接;从站为server端,等待连接。

1.报文头MBAP

MBAP为报文头,长度为7字节,组成如下:

事务处理标识协议标识长度单元标识符
2字节2字节2字节1字节

事务处理标识:可以理解为报文的序列号,一般每次通信之后就要加1以区别不同的通信数据报文
协议标识符:00 00表示ModbusTCP协议
长度:表示接下来的数据长度,单位为字节
单元标识符:可以理解为设备地址

2.帧结构PDU

PDU由功能码+数据组成。功能码为1字节,数据长度不定,由具体功能决定。

例子:

发送:01 c8 00 00 00 06 01 03 00 14 00 0a

序列号:01 c8 ,协议标识符:00 00 ,长度:00 06 ,单元标识符/服务器地址:01,功能码:03,寄存器地址:00 14 ,读取几位数据:00 0a。

接收:01 c8 00 00 00 17 01 03 14 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 03 00 00

序列号:01 c8 ,协议标识符:00 00 ,长度:00 17 ,单元标识符/服务器地址:01 ,功能码:03,数据长度:14 ,数据:就是后面的在第6位和第9位有数据。

下一条数据序,列号就会加一,变为01 c9。

Modbus TCP TCP/IP网络上运行的Modbus的实现,旨在允许Modbus ASCII / RTU协议在基于TCP / IP的网络上传输。Modbus / TCP将Modbus消息嵌入TCP / IP帧内。尽管实现起来非常简单,但是与网络相关的特性增加了一些挑战。例如,由于Modbus主机期望并要求在一定时间范围内对其轮询做出响应,因此必须考虑TCP / IP网络的不确定性(和其他方面)。Modbus ASCII和Modbus TCP之间的主要区别在于,Modbus ASCII所需的LRC错误检查由IP层执行。

对于以上TCP/RTU/ASCII的这三种通信协议在数据模型和功能调用上都是相同的,只有封装方式是不同的。

1.4 广播模式与单播模式

在串行链路的主从通信中,Modbus主设备可以连接一个或N(最大为247)个从设备,主从设备之间的通信包括单播模式和广播模式。

广播模式中,Modbus主设备可同时向多个从设备发送请求(设备地址0用于广播模式),从设备对广播请求不进行响应。

所谓广播模式,是主节点向所有的子节点发送请求,当主节点发送的请求报文的地址域值为0时,代表广播请求,所有的从节点都需要接受处理,但不需要向主节点返回报文。

图片4

单播模式中,主设备发送请求至某个特定的从设备(每个Modbus从设备具有唯一地址),请求的消息帧中会包含功能代码和数据,比如功能代码“01”用来读取离散量线圈的状态。从设备接到请求后,进行应答并把消息反馈主设备。

所谓单播模式就是主节点给某个指定的节点发送消息(通过ADU中的地址域指定),从节点收到并处理完请求后,从节点向主节点返回一个应答报文,在这种模式下,一个Modbus事务包含两个报文,一个来自主节点的请求,一个来自子节点的应答

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-riMsj0KM-1631626547715)(https://i.loli.net/2021/08/11/NEkywuR4l1TdUhP.png)]

其实在物理层所有设备都会收到所有的请求,但地址域不为0时,从机判断当前为单播模式,只有地址域和自身地址号相同的从机才会响应请求,当地址域为0时,从机判断为广播消息,所有的从机都会执行指令,所有收到指令的设备都会运行,只不过不回应指令。

1.5 事务处理流程

​ 启动MODBUS 事务处理的客户机创建 MODBUS 应用数据单元。当从客户机向服务器设备发送报文时,功能码向服务器指示将执行哪种操作。

​ **正常事务处理流程:**从客户机向服务器设备发送的报文数据域包括附加信息,服务器使用这个信息执行功能码定义的操作。如果在一个正确接收的 MODBUS ADU 中,不出现与请求 MODBUS 功能有关的差错,那么服务器至客户机的响应数据域包括请求数据。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sCOKYFWM-1631626547717)(https://i.loli.net/2021/08/11/oMjFgJln7fQdSxz.png)]

**异常事务处理流程:**如果出现与请求 MODBUS 功能有关的差错,那么域包括一个异常码,服务器应用能够使用这个域确定下一个执行的操作。当服务器对客户机响应时,它使用功能码域来指示正常(无差错)响应或者出现某种差错(称为异常响应)。对于一个正常响应来说,服务器仅对原始功能码响应。

图片6

1.6 寄存器相关概念

modbus完整支持很多功能码,但是实际在应用的时候常用的也就那么几个。具体如下:

0x01: 读线圈寄存器

0x02: 读离散输入寄存器

0x03: 读保持寄存器

0x04: 读输入寄存器

0x05: 写单个线圈寄存器

0x06: 写单个保持寄存器

0x0f: 写多个线圈寄存器

0x10: 写多个保持寄存器

如上所示一共8种功能码。这其中有涉及到线圈、离散输入、保持、输入四种寄存器

线圈寄存器:实际上就可以类比为开关量,没一个bit都对应一个信号的开关状态。所以一个byte就可以同时控制8路的信号。比如控制外部8路io的高低。 线圈寄存器支持读也支持写,写在功能码里面又分为写单个线圈寄存器和写多个线圈寄存器。对应上面的功能码也就是:0x01 0x05 0x0f。

离散输入寄存器:如果线圈寄存器理解了这个自然也明白了。离散输入寄存器就相当于线圈寄存器的只读模式,他也是每个bit表示一个开关量,而他的开关量只能读取输入的开关信号,是不能够写的。比如我读取外部按键的按下还是松开。所以功能码也简单就一个读的 0x02。

保持寄存器:这个寄存器的单位不再是bit而是两个byte,也就是可以存放具体的数据量的,并且是可读写的。比如我我设置时间年月日,不但可以写也可以读出来现在的时间。写也分为单个写和多个写,所以功能码有对应的三个:0x03 0x06 0x10。

输入寄存器:只剩下这最后一个了,这个和保持寄存器类似,但是也是只支持读而不能写。一个寄存器也是占据两个byte的空间。类比我我通过读取输入寄存器获取现在的AD采集值。对应的功能码也就一个 0x04。

二、数据帧格式

功能码描述访问类型PLC地址数据类型操作数量
01H线圈寄存器00001-09999单/多
02H离散输入寄存器只读10001-19999单\多
03H保持寄存器40001-49999单\多
04H输入寄存器30001-39999单\多
05H线圈寄存器00001-09999
06H保持寄存器40001-49999
0FH线圈寄存器00001-09999
10H保持寄存器40001-49999

2.1 0X01功能码

0X01:读线圈状态

描述:读取从机线圈寄存器,位操作,可读单个或者多个;

2.1.1 发送指令

假设从机地址位0x01,线圈寄存器开始地址0x0023,总共读取21个线圈寄存器:

从机地址功能码起始地址高八位起始地址低八位寄存器数量高八位寄存器数量低八位CRCHCRCL
0x010x010x000x230x000x150xXX0xXX

从机地址:要通信的设备

功能码:实现的功能

起始地址:从哪个线圈寄存器地址开始读

线圈数量:从起始地址往后读多少个线圈寄存器

2.1.2 正常响应

返回数据的每一位对应线圈状态,1-ON,0-OFF,如下图;

从机地址功能码返回字节数data1data2data3CRCHCRCL
0x010x010x030xa50xd40x180xXX0xXX
  • 返回字节数 = 线圈寄存器数量/8 (线圈寄存器数量/%8还有余数,则字节数+1)(1个字节最多可以表示8个线圈寄存器)
  • data1的最低位代表最低地址的线圈寄存器状态,data3的最高位代表最高地址的线圈寄存器状态,可以理解为小端模式
  • data1表示地址0x0023-0x002a的线圈寄存器状态
  • data2表示地址0x002b-0x0032的线圈寄存器状态
  • data3表示地址0x0033-0x0037的线圈寄存器状态(不够8位,字节高位填充为0

data1:

0x2a0x290x280x270x260x250x240x23
10100101

data2:

0x320x310x300x2f0x2e0x2d0x2c0x2b
11010100

data3:

0xxx0xxx0xxx0x370x360x350x340x33
00011000
2.1.3 异常码响应

假设发生了01异常

从机地址功能码0x01|0x80异常码CRCHCRCL
0181010xXX0xXX
  • 01异常码:功能码错误

  • 02异常码:起始地址超出范围(或起始地址+输出线圈数量超出范围)

  • 03异常码:输出线圈数量小于0x0001或者大于0x07d0

2.1.4 不响应
  • 从机地址错误

  • 接收到的数据位数不对,例如少了功能码、或者少了线圈寄存器地址

  • CRC校验错误

2.2 0X03功能码

0X03-读保持寄存器

描述:读保持寄存器,字节指令操作,可读单个或者多个;

2.2.1 发送指令

从机地址0x01,保持寄存器起始地址0x0023,读2个保持寄存器

从机地址功能码起始地址高八位起始地址低八位寄存器数量高八位寄存器数量低八位CRCHCRCL
0x010x030x000x230x000x020xXX0xXX

从机地址:要通信的设备

功能码:实现的功能

寄存器起始地址:从哪个寄存器地址开始读

寄存器数量:从起始地址往后读多少个寄存器

2.2.2 正常响应
从机地址功能码返回字节数Data1HData1LData2HData2LCRCHCRCL
0x010x030x040xA50xA40x180x120xXX0xXX
  • 返回字节数=寄存器数量*2 (1个寄存器返回一个寄存器高8位,一个寄存器低8位,共两个字节)

  • Data1H = 第一个寄存器里面高8位

  • Data1L = 第一个寄存器里面低8位

  • Data2H = 第二个寄存器里面高8位

  • Data2L = 第二个寄存器里面低8位

Data1:04 B1(十六进制)–>1201(十进制)

Data2:08 FF(十六进制)–>2303(十进制)

数据存储顺序

0x00260x00250x00240x0023
0x040xB10x080xFF
2.2.3 异常码响应

假设发生了02异常

从机地址功能码0x03|0x80异常码CRCHCRCL
0183020xXX0xXX
  • 01异常码:功能码错误

  • 02异常码:起始地址超出范围(或起始地址+寄存器数量超出范围)

  • 03异常码:输出数量小于0x0001或者大于0x007D

2.2.4 不响应
  • 从机地址错误

  • 接收到的数据位数不对,例如少了功能码、或者少了寄存器地址

  • CRC校验错误

2.3 0X0F功能码

0X0F-写多个线圈

描述:写多个线圈寄存器。若数据区的某位值为“1”表示被请求的相应线圈状态为ON,若某位值为“0”,则为状态为OFF。

2.3.1 发送指令

线圈寄存器地址为0x0023,写10个线圈寄存器:

从机地址功能码起始地址高八位起始地址低八位寄存器数量高八位寄存器数量低八位字节数DATA1DATA2CRCHCRCL
0x010x0F0x000x230x000x0A0x020x0C0x020xXX0xXX
  • 字节数 = 线圈寄存器数量/8 (线圈寄存器数量/%8还有余数,则字节数+1)(1个字节最多可以表示8个线圈寄存器)

  • data1的最低位代表最低地址的线圈寄存器状态,data2的最高位代表最高地址的线圈寄存器状态,可以理解为小端模式

  • DATA1:表示地址0x0023-0x002a的线圈寄存器状态

  • DATA2:表示地址0x002B-0x002C的线圈寄存器状态(不够8位,字节高位填充为0

DATA1:

0x002A0x00290x00280x00270x00260x00250x00240x0023
00001100

DATA2:

0xxx0xxx0xxx0xxx0xxx0xxx0x002C0x002B
00000010
2.3.2 正常响应:
从机地址功能码线圈寄存器地址高八位线圈寄存器地址低八位寄存器数量高八位寄存器数量低八位CRCHCRCL
0x010x0F0x040x050x000x0d0xXX0xXX
2.3.3 异常码响应

假设发生了03异常

从机地址功能码0x0F|0x80异常码CRCHCRCL
018F030xXX0xXX
  • 01异常码:功能码错误

  • 02异常码:起始地址超出范围(或起始地址+寄存器数量超出范围)

  • 03异常码:输出数量小于0x0001或者大于0x07B0(或字节数位与后面的字节数不对应)

2.3.4 不响应
  • 从机地址错误
  • 接收到的数据位数不对,例如少了功能码、或者少了寄存器地址
  • CRC校验错误

2.4 0X10功能码

0X10-写多个保持寄存器

描述:写多个保持寄存器,字节指令操作,可写多个;

2.4.1 发送指令

线圈寄存器地址为0x0023,写10个线圈寄存器:

例如:保持寄存器起始地址为0x0023,写2个寄存器,共4个字节的数据;

从机地址功能码起始地址高八位起始地址低八位寄存器数量高八位寄存器数量低八位字节数DATA1HDATA1LDATA2HDATA2LCRCHCRCL
0x010x100x000x230x000x020x040x040xB10x080xFF0xXX0xXX
  • 字节数=寄存器数量*2 (1个寄存器返回一个寄存器高8位,一个寄存器低8位,共两个字节)

  • Data1H = 第一个寄存器里面高8位

  • Data1L = 第一个寄存器里面低8位

  • Data2H = 第二个寄存器里面高8位

  • Data2L = 第二个寄存器里面低8位

Data1:04 B1(十六进制)–>1201(十进制)

Data2:08 FF(十六进制)–>2303(十进制)

3.4.2正常响应
从机地址功能码起始地址高八位起始地址低八位寄存器数量高八位寄存器数量低八位CRCHCTCL
0x010x100x000x340x000x020xXX0xXX
2.4.3 异常码响应

假设发生了03异常

从机地址功能码0x10|0x80异常码CRCHCRCL
0190030xXX0xXX
  • 01异常码:功能码错误

  • 02异常码:起始地址超出范围(或起始地址+寄存器数量超出范围)

  • 03异常码:输出数量小于0x001或者大于0x007B(或字节数不等于寄存器数*2)

2.4.4 不响应
  • 从机地址错误

  • 接收到的数据位数不对,例如少了功能码、或者少了寄存器地址

  • CRC校验错误

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Freemodbus Slave是一种开源的MODBUS通信协议从站实现,用于在工业自动化系统中实现与主站的通信。下面是关于Freemodbus Slave学习的一些建议。 首先,要了解MODBUS通信协议的基础知识。MODBUS是一种常用的用于工业领域的通信协议,它定义了从站和主站之间的通信规则和数据格式。学习MODBUS基础知识可以帮助理解Freemodbus Slave的实现原理。 其次,阅读Freemodbus Slave的文档和用户手册。官方提供了详细的文档和用户手册,其中包含了安装、配置以及使用Freemodbus Slave的详细说明。仔细阅读这些文档可以帮助理解Freemodbus Slave的各个功能和参数设置。 然后,实践操作和编程。使用开发板或者模拟器,将Freemodbus Slave添加到自己的工程中进行实验和测试。通过实践操作和编程,可以更好地理解Freemodbus Slave的使用方法和功能。 此外,参考社区和论坛的资源。Freemodbus有一个积极的开发者社区,这里有很多经验丰富的开发者和用户分享他们的经验和解决方案。在这些社区和论坛中进行交流和讨论,可以获得更多关于Freemodbus Slave的学习资源和帮助。 最后,不断练习和提升。通过不断实践和使用Freemodbus Slave,深入了解其各种功能和使用场景。并且保持学习的态度,关注最新的更新和发布,不断提高自己的技能和知识。 总结来说,学习Freemodbus Slave需要掌握MODBUS通信协议的基础知识,阅读官方文档和用户手册,进行实践操作和编程,参考社区和论坛的资源,持续练习和提升。通过这些步骤,可以逐渐掌握Freemodbus Slave的使用方法和技巧。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值