Modbus在Java中使用总结
一、什么是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
ASCII模式
当控制器设为在Modbus网络上以ASCII模式通信,在消息中的每个8Bit字节都作为两个ASCII字符发送。这种方式的主要优点是字符发送的时间间隔可达到1秒而不产生错误。
RTU模式
当控制器设为Modbus网络上以RTU(远程终端单元)模式通信,在消息中的每个8Bit字节包含两个4Bit的十六进制字符。这种方式的主要优点是:在同样的波特率下,可比ASCII方式传送更多的数据。
Modbus TCP
在Modbus TCP/IP协议中,串行链路中的主/从设备分别演变为客户端/服务器端设备。即客户端相当于主站设备,服务器端相当于从站设备。基于TCP/IP网络的传输特性,串行链路上一主多从的构造也演变为多客户端/多服务器端的构造模型。Modbus TCP/IP服务器端通常使用端口502作为接收报文的端口, IANA(Internet Assigned Numbers Authority,互联网编号分配管理机构)给Modbus协议赋予TCP端口号为502,这是目前在仪表与自动化行业中唯一分配到的端口号。
其通信过程:
- connect 建立TCP连接
- 准备Modbus报文
- 使用send命令发送报文
- 在同一连接下等待应答
- 使用recv命令读取报文,完成一次数据交换
- 通信任务结束时,关闭TCP连接
ModbusTCP数据帧:MBAP+PDU
MBAP:内容 | 长度 | 解释 |
---|---|---|
00 00 | 2字节 | 可以理解为报文的序列号,一般每次通信之后就要加1以区别不同的通信数据报文。 |
00 00 | 2字节 | 00 00表示ModbusTCP协议。 |
00 06 | 2字节 | 表示接下来的数据长度,单位为字节。 |
01 | 1字节 | 可以理解为设备地址。以上七个字节也被称为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位 |
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库】
来源地址:https://blog.csdn.net/neusoft2016/article/details/127725957
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341