共计 4680 个字符,预计需要花费 12 分钟才能阅读完成。
简介:一般来说,常见的物联网通信协定泛滥,如蓝牙、Zigbee、WiFi、ModBus、PROFINET、EtherCAT、蜂窝等。而在泛滥的物联网通信协定中,Modbus 是以后十分风行的一种通信协定。它一种串行通信协议,是 Modicon 公司于 1979 年为应用可编程逻辑控制器(PLC)通信而制订的,能够说,它曾经成为工业畛域通信协议的业界规范。
1 概述
随着 IT 技术的疾速倒退,以后曾经步入了智能化时代,其中的物联网技术将在将来占据越来越重要的位置。依据百度百科的定义,物联网(Internet of things,简称 IOT)即“万物相连的互联网”,是互联网根底上的延长和扩大的网络,物联网将各种信息有机的联合起来,实现任何工夫、任何地点,人、机、物的互联互通。物联网从技术上来说,很重要的外围是通信协定,即如何按约定的通信协定,把机、物和人与互联网相连接,进行信息通信,以实现对人、机和物的智能化辨认、定位、跟踪、监控和治理的一种网络。
一般来说,常见的物联网通信协定泛滥,如蓝牙、Zigbee、WiFi、ModBus、PROFINET、EtherCAT、蜂窝等。而在泛滥的物联网通信协定中,Modbus 是以后十分风行的一种通信协定。它一种串行通信协议,是 Modicon 公司于 1979 年为应用可编程逻辑控制器(PLC)通信而制订的,能够说,它曾经成为工业畛域通信协议的业界规范。其劣势如下:
- 收费无版税限度
- 容易部署
- 灵便限度少
2 ModBus 协定概述
Modbus 通信协定应用申请 - 应答机制在主(Master)(客户端 Client)和从(Slave)(服务器 Server)之间替换信息。Client-Server 原理是通信协议的模型,其中一个主设施管制多个从设施。这里须要留神的是:Modbus 通信协定当中的 Master 对应 Client,而 Slave 对应 Server。Modbus 通信协定的官网为 www.modbus.org。目前官网组织曾经倡议将 Master-Slave 替换为 Client-Server。从协定类型上能够分为:Modbus-RTU(ASCII)、Modbus-TCP 和 Modbus-Plus。本文次要介绍 Modbus-RTU(ASCII)的通信协定原理。规范的 Modbus 协定物理层接口有 RS232、RS422、RS485 和以太网接口。
通信示意图如下:
一般来说,Modbus 通信协议原理具备如下的特色:
- 一次只有一个主机(Master)连贯到网络
- 只有主设施(Master)能够启动通信并向从设施 (Slave) 发送申请
- 主设施(Master)能够应用其特定地址独自寻址每个从设施 (Slave),也能够应用地址 0(播送) 同时寻址所有从设施(Slave)
- 从设施 (Slave) 只能向主设施(Master)发送回复
- 从设施 (Slave) 无奈启动与主设施(Master)或其余从设施 (Slave) 的通信
Modbus 协定可应用 2 种通信模式替换信息:
- 单播模式
- 播送模式
不论是申请报文还是回答报文,数据结构如下:
即报文(帧数据)由 4 局部形成:地址(Slave Number)+ 性能码(Function Codes)+ 数据(Data)+ 校验(Check)。其中的地址代表从设施的 ID 地址,作为寻址的信息。性能码示意以后的申请执行具体什么操作,比方读还是写。数据代表须要通信的业务数据,能够依据理论状况来确定。最初一个校验则是验证数据是否有误。其中的性能码阐明如下:
比方性能码为 03 代表读取以后寄存器内一个或多个二进制值,而 06 代表将二进制值写入繁多寄存器。为了模仿 Modbus 通信协定过程,这里能够借助模仿软件:
- Modbus Poll(Master)
- Modbus Slave
具体的装置过程这里不再赘述。首先这里须要模仿一个物联网传感器设施,这里用 Modbus Slave 来定义,首先关上此软件,并定义一个 ID 为 1 的设施:
此性能码为 03。另外,设置连贯参数,示例界面如下:
上面再用 Modbus Poll 软件来模仿主机,来获取从设施的数据。首先定义一个读写报文。
而后再定义一个连贯信息:
留神:两个 COM 口要应用不同的名称。
胜利建设通信后,通信的报文格式如下:
Tx 代表申请报文,而 Rx 代表回答报文。
3 ModBus Java 实现
上面介绍一下如何用 Java 来实现一个 Modbus TCP 通信。这里 Java 框架采纳 Spring Boot,首先须要引入 Modbus4j 库。Maven 依赖库的 pom.xml 定义如下:
<dependency> | |
<groupId>com.infiniteautomation</groupId> | |
<artifactId>modbus4j</artifactId> | |
<version>3.0.3</version> | |
</dependency> | |
<dependency> | |
<groupId>org.rxtx</groupId> | |
<artifactId>rxtx</artifactId> | |
<version>2.1.7</version> | |
</dependency> |
其中的 modbus4j 库可能在 Maven 中无奈失常下载,能够手动下载后放于我的项目中,并增加到我的项目库中。如下图所示:
留神:首次实用串口时,须要进行装置,否则会报 no rxtxSerial in java.library.path 的谬误。
拜访 http://fizzed.com/oss/rxtx-fo… 下载对应操作系统的库文件,解压后装置如下领导进行拷贝后装置。
For a JDK installation: | |
Copy RXTXcomm.jar ---> <JAVA_HOME>\jre\lib\ext | |
Copy rxtxSerial.dll ---> <JAVA_HOME>\jre\bin | |
Copy rxtxParallel.dll ---> <JAVA_HOME>\jre\bin |
另外,须要留神,这里还须要串口反对,这里能够用虚构串口软件来解决。
上面给出 Java 外围代码片段。
public static SerialPort open(String portName, Integer baudRate, Integer dataBits, | |
Integer stopBits, Integer parity) { | |
SerialPort result = null; | |
try {CommPortIdentifier identifier = CommPortIdentifier.getPortIdentifier(portName); | |
// 关上端口 | |
CommPort commPort = identifier.open(portName, 2000); | |
// 判断是不是串口 | |
if (commPort instanceof SerialPort) {result = (SerialPort) commPort; | |
// 设置串口的参数 | |
result.setSerialPortParams(baudRate, dataBits, stopBits, parity); | |
log.info("关上串口 {} 胜利", portName); | |
}else{log.info("{}不是串口", portName); | |
} | |
} catch (Exception e) {log.error("关上串口 {} 谬误", portName, e); | |
} | |
return result; | |
} |
首先须要启动 Modbus RTU Slave 程序,外围代码片段如下:
public static void createRtuSlave(){ | |
// 串口是 COM3,波特率是 9600 | |
SerialPortWrapperImpl wrapper = new SerialPortWrapperImpl("COM3", 9600, | |
SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE, 0, 0); | |
ModbusFactory modbusFactory = new ModbusFactory(); | |
创立 RTU Slave | |
final ModbusSlaveSet slave = modbusFactory.createRtuSlave(wrapper); | |
// 寄存器里能够设置线圈状态、离散输出状态、放弃寄存器和输出寄存器 | |
// 从站设施 ID 是 1 | |
BasicProcessImage processImage = new BasicProcessImage(1); | |
processImage.setInvalidAddressValue(Short.MIN_VALUE); | |
slave.addProcessImage(processImage); | |
// 增加监听器,监听 slave 线圈状态和放弃寄存器的写入 | |
processImage.addListener(new MyProcessImageListener()); | |
// 设置数据 | |
setCoil(processImage); | |
setInput(processImage); | |
setHoldingRegister(processImage); | |
setInputRegister(processImage); | |
// 开启线程启动 | |
new Thread(() -> { | |
try {slave.start(); | |
} | |
catch (ModbusInitException e) {e.printStackTrace(); | |
} | |
}).start();} |
而 Modbus RTU Master 程序,外围代码片段如下:
private static void createRtuMaster() throws Exception{ | |
// 串口是 COM4,波特率是 9600 | |
SerialPortWrapperImpl wrapper = new SerialPortWrapperImpl("COM4", 9600, | |
SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE, 0, 0); | |
ModbusFactory modbusFactory = new ModbusFactory(); | |
//RTU Master | |
ModbusMaster master = modbusFactory.createRtuMaster(wrapper); | |
master.init(); | |
// 从站设施 ID 是 1 | |
int slaveId = 1; | |
// 读取放弃寄存器 | |
readHoldingRegisters(master, slaveId, 0, 3); | |
// 将地址为 0 的放弃寄存器数据批改为 0 | |
writeRegister(master, slaveId, 0, 0); | |
// 再读取放弃寄存器 | |
readHoldingRegisters(master, slaveId, 0, 3); | |
} |
启动后输入如下所示:
//Slave | |
[Thread-1] INFO cn.wu.demo.modbus4j.util.SerialPortUtils - 关上串口 COM3 胜利 | |
放弃寄存器地址 =0,旧值 =8,新值 =0 | |
//Master ////////////////////////////////////////////////////////////////////// | |
[main] INFO cn.wu.demo.modbus4j.util.SerialPortUtils - 关上串口 COM4 胜利 | |
读取放弃寄存器 =[8, 56, 0] | |
写放弃寄存器胜利 | |
读取放弃寄存器 =[0, 56, 0] |
参考开源我的项目:https://github.com/wu-boy/mod…
原文链接
本文为阿里云原创内容,未经容许不得转载。