一、什么是Modbus

Modbus是一种串行通信协议,是Modicon公司于1979年为使用可编程逻辑控制器(PLC)通信而发表。Modbus是工业领域通信协议的业界标准,是工业电子设备之间常用的连接方式Modbus就是一个总线通信协议,像IIC SPI这种,但是他不依赖于硬件总线
  • Modbus之所以使用广泛,是有他的优点的
  • Modbus协议标准开放、公开发表且无版权要求
  • Modbus协议支持多种电气接口,包括RS232、RS485、TCP/IP等,还可以在各种介质上传输,如双绞线、光纤、红外、无线等
  • Modbus协议消息帧格式简单、紧凑、通俗易懂。用户理解和使用简单,厂商容易开发和集成,方便形成工业控制网络

二、modbus是哪一层协议

Modbus是 OSI 模型第 7 层上的应用层报文传输协议,它在连接至不同类型总线或网络的设备之间提供客户机/服务器通信。包括了ASCII、RTU、TCP三种报文类型,协议本身并没有定义物理层,定义了控制器能够认识和使用的消息结构,不管它们是经过何种网络进行通信的。Modbus协议使用串口传输时可以选择RTU或者ASCII模式,并规定了消息、数据结构、命令和应答方式,且需要对数据进行校验。ASCII模式采用LRC校验,RTU模式采用16位CRC校验。通过以太网传输时使用TCP,这种模式下不使用校验,因为TCP协议是一个面向连接的可靠协议。

三、Modbus 通讯方式

MODBUS 协议允许在各种网络体系结构内进行简单通信。每种设备(PLC、HMI、控制面板、驱动程序、动作控制、输入/输出设备)都能使用 MODBUS协议来启动远程操作。

Modbus有下列三种通信方式:

  • 以太网:对应的通信模式是Modbus TCP/IP
  • 异步串行传输(各种介质如有线RS-232-/422/485/;光纤、无线等), 对应的通信模式是Modbus RTU或Modbus ASCII
  • 高速令牌传递网络:对应的通信模式是Modbus PLUS

1、ASCII模式
当控制器设为在Modbus网络上以ASCII模式通信,在消息中的每个8Bit字节都作为两个ASCII字符发送。这种方式的主要优点是字符发送的时间间隔可达到1秒而不产生错误。

2、RTU模式
当控制器设为Modbus网络上以RTU(远程终端单元)模式通信,在消息中的每个8Bit字节包含两个4Bit的十六进制字符。这种方式的主要优点是:在同样的波特率下,可比ASCII方式传送更多的数据。

3、Modbus TCP
在Modbus TCP/IP协议中,串行链路中的主/从设备分别演变为客户端/服务器端设备。即客户端相当于主站设备,服务器端相当于从站设备。基于TCP/IP网络的传输特性,串行链路上一主多从的构造也演变为多客户端/多服务器端的构造模型。Modbus TCP/IP服务器端通常使用端口502作为接收报文的端口, IANA(Internet Assigned Numbers Authority,互联网编号分配管理机构)给Modbus协议赋予TCP端口号为502,这是目前在仪表与自动化行业中唯一分配到的端口号。

其通信过程:

  1. connect 建立TCP连接
  2. 准备Modbus报文
  3. 使用send命令发送报文
  4. 在同一连接下等待应答
  5. 使用recv命令读取报文,完成一次数据交换
  6. 通信任务结束时,关闭TCP连接

ModbusTCP数据帧:MBAP+PDU

MBAP:
内容长度解释
00 002字节可以理解为报文的序列号,一般每次通信之后就要加1以区别不同的通信数据报文。
00 002字节00 00表示ModbusTCP协议。
00 062字节表示接下来的数据长度,单位为字节。
011字节可以理解为设备地址。以上七个字节也被称为Modbus报文头

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

PDU结构详解-举个例子

0x03:读保持寄存器

从远程设备中读保持寄存器连续块的内容

请求:MBAP 功能码 起始地址H 起始地址L 寄存器数量H 寄存器数量L(共12字节)

响应:MBAP 功能码 数据长度 寄存器数据(长度:9+寄存器数量×2)

如:00 01 此次通信事务处理标识符,00 00 标识modbus TCP协议,00 06为数据长度,01 为设备地址,03  为功能码此时代表读取保持寄存器,00 00代表起始地址,00 03为寄存器数量

00 01 00 00 00 06 01 03 00 00 00 03

回:数据长度为0x06,第一个寄存器的数据为0x21,其余为0x00

00 01 00 00 00 09 01 03 06 00 21 00 00 00 00

其它PDU结构:

功能码含义位操作/字操作操作数量长度例子
0x01读线圈位操作单个或多个12字节

如:在从站0x01中,读取开始地址为0x0002的线圈数据,读0x0008位
00 01 00 00 00 06 01 01 00 02 00 08

0x05写单个线圈位操作单个12字节如:将地址为0x0003的线圈设为ON
00 01 00 00 00 06 01 05 00 03 FF 00
0x0F写多个线圈位操作多个12字节

如:将线圈03之后写入4个数据都是ON,01代表后面数据占用一个字节(F对应的二进制是1111)

046B00000008010F 0003 0004 01 0F

0x02读离散量输入位操作单个或多个12字节从地址0x0000开始读0x0012个离散量输入
00 01 00 00 00 06 01 02 00 00 00 12
0x04读输入寄存器字操作单个或多个12字节读起始地址为0x0002,数量0x0005的寄存器数据
00 01 00 00 00 06 01 04 00 02 00 05
0x03读保持寄存器字操作单个或多个12字节起始地址是0x0000,寄存器数量是 0x0003
00 01 00 00 00 06 01 03 00 00 00 03
0x06写单个保持寄存器字操作单个12字节向地址是0x0000的寄存器写入数据0x000A
00 01 00 00 00 06 01 06 00 00 00 0A
0x10写多个保持寄存器字操作多个13+寄存器数量×2向起始地址为0x0000,数量为0x0001的寄存器写入数据,数据长度为0x02,数据为0x000F
00 01 00 00 00 09 01 10 00 00 00 01 02 00 0F

四、通信过程

Modbus是一主多从的通信协议,控制器相互之间、或控制器经由网络(如以太网)可以和其它设备之间进行通信。Modbus协议使用的是主从通讯技术,即由主设备主动查询和操作从设备。一般将主控设备方所使用的协议称为Modbus Master,从设备方使用的协议称为Modbus Slave。典型的主设备包括工控机和工业控制器等;典型的从设备如PLC可编程控制器等。

Modbus的工作方式是请求/应答,每次通讯都是主站先发送指令,可以是广播,或是向特定从站的单播;从站响应指令,并按要求应答,或者报告异常。当主站不发送请求时,从站不会自己发出数据,从站和从站之间不能直接通讯 。

Modbus通讯物理接口可以选择串口,也可以选择以太网。它的通信遵循以下过程:

  • 主设备向从设备发送请求
  • 从设备分析并处理主设备的请求,然后向主设备发送结果
  • 如果出现任何差错,从设备将返回一个异常功能码

五、在Java中使用

关于Java的开源库

  • Jamod:Java Modbus实现:Java Modbus库。该库由Dieter Wimberger实施。
  • ModbusPal:ModbusPal是一个正在进行的Java项目,用于创建逼真的Modbus从站模拟器。由于预定义的数学函数和/或Python脚本,寄存器值是动态生成的。ModbusPal依赖于RxTx进行串行通信,而Jython则依赖于脚本支持。
  • Modbus4J:Serotonin Software用Java编写的Modbus协议的高性能且易于使用的实现。支持ASCII,RTU,TCP和UDP传输作为从站或主站,自动请求分区,响应数据类型解析和节点扫描。
  • JLibModbus:JLibModbus是java语言中Modbus协议的一种实现。jSSC和RXTX用于通过串行端口进行通信。该库是一个经过积极测试和改进的项目。

Java中能用来做什么

server端: 作为服务端(slave端、从端)接收数据:指的是java作为报文的接收者,接收硬件设备的反馈消息

client端:  作为客户端(master端、主动端)发送数据数据:指的是Java作为报文的发送者,来达到控制设备

参考资料:

  • https://blog.csdn.net/xixiyuguang/article/details/123353651【Java实现ModbusTCP通信】 
  • https://runlion.blog.csdn.net/article/details/108647301【jamod例子】
  • https://blog.csdn.net/Crazy_Cw/article/details/126613967【Netty 实现】
  • https://blog.csdn.net/xfx_1994/article/details/117687884【jlibmodbus例子 】
  • https://www.leftso.com/blog/83.html【modbus4j例子 】
  • https://zhuanlan.zhihu.com/p/529715356【串口调试工具——Modbus Poll】

六、仿真软件Modbus Poll的使用

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

七、后续

为什么要使用驱动库?我们知道了Modbus是一种总线协议,它可以基于串口或网口,以基于串口的Modbus-RTU为例,我们需要在Windows或Linux下实现一个上位机,上位机的功能是读写Modbus接口传感器设备的数据,或者是和单片机等从设备进行交互。
所以作为主机,写数据的流程是:

  • 构建一个Modbus-RTU数据帧
  • 等待从机响应的数据
  • 如果响应数据正确,说明写入成功,否则写入失败。

读数据也是同样的流程,我们可以基于串口发送、串口接收函数、定时器等,自己写一个Modbus驱动库,来实现对从设备的读写。当然,也可以直接使用别人写好的Modbus驱动库,比如libmodbus,本文将介绍如何使用libmodbus驱动库,实现Modbus主机和从机。

传送门:CentOS7下编译安装libmodbus库_雪域迷影的博客-CSDN博客【CentOS7下编译安装libmodbus库】

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐