Abstract: Modbus is a very popular communication protocol.

This article is shared from the article " Modbus Communication Protocol of the Internet of Things" 16170d7ba16578 in the Huawei Cloud Community 丨 [Please, the Internet of Things! ] ", author: jackwangcumt.

1 Overview

With the rapid development of IT technology, the current era of intelligence has entered, and the Internet of Things technology will occupy an increasingly important position in the future. According to the definition of Baidu Encyclopedia, the Internet of things (Internet of things, referred to as IOT) is the "Internet of Everything", which is an extension and expansion network based on the Internet. Any place, the interconnection of people, machines and things. From a technical point of view, the very important core of the Internet of Things is the communication protocol, that is, how to connect machines, things, and people to the Internet according to the agreed communication protocol for information communication, so as to realize the intelligent identification of people, machines and things. , Positioning, tracking, monitoring and management of a network.

Generally speaking, there are many common IoT communication protocols, such as Bluetooth, Zigbee, WiFi, ModBus, PROFINET, EtherCAT, cellular and so on. Among the many communication protocols for the Internet of Things, Modbus is a very popular communication protocol. It is a serial communication protocol developed by Modicon in 1979 for the use of programmable logic controller (PLC) communication. It can be said that it has become an industry standard for communication protocols in the industrial field. Its advantages are as follows:

  • Free and no royalties
  • Easy to deploy
  • Flexible and less restrictive

2 Overview of ModBus protocol

The Modbus communication protocol uses a request-response mechanism to exchange information between the Master (Client) and Slave (Server). The principle of Client-Server is a communication protocol model in which one master device controls multiple slave devices. should be noted here that the Master in the Modbus communication protocol corresponds to the Client, and the Slave corresponds to the Server . The official website of Modbus communication protocol is http://www.modbus.org. At present, the official website organization has suggested replacing Master-Slave with Client-Server. From the protocol type, it can be divided into: Modbus-RTU (ASCII), Modbus-TCP and Modbus-Plus. This article mainly introduces the principle of Modbus-RTU (ASCII) communication protocol. The standard Modbus protocol physical layer interfaces include RS232, RS422, RS485 and Ethernet interfaces.

The communication diagram is as follows:
image.png

Generally speaking, the principle of Modbus communication protocol has the following characteristics:

 Only one master (Master) is connected to the network at a time
 Only the master device (Master) can start communication and send requests to the slave device (Slave)
 The master device (Master) can use its specific address to address each slave device (Slave) individually, or it can use address 0 (broadcast) to address all slave devices (Slave) at the same time
 The slave device (Slave) can only send a reply to the master device (Master)
 The slave device (Slave) cannot start communication with the master device (Master) or other slave devices (Slave)

Modbus protocol can use 2 communication modes to exchange information:

 Unicast mode
 Broadcast mode

Regardless of whether it is a request message or a reply message, the data structure is as follows:
image.png

That is, the message (frame data) consists of 4 parts: address (Slave Number) + function codes (Function Codes) + data (Data) + check (Check) . The address represents the ID address of the slave device as the addressing information. The function code indicates the specific operation performed by the current request, such as reading or writing. The data represents the business data that needs to be communicated, which can be determined according to the actual situation. The last check is to verify whether the data is wrong. The function codes are as follows:
image.png

For example, a function code of 03 means reading one or more binary values in the current register, and 06 means writing a binary value to a single register. In order to simulate the Modbus communication protocol process, simulation software can be used here:

  • Modbus Poll(Master)
  • Modbus Slave

The specific installation process will not be repeated here. First of all, it is necessary to simulate an IoT sensor device, which is defined by Modbus Slave. First, open the software and define a device with ID 1:
image.png

This function code is 03. In addition, set the connection parameters, the sample interface is as follows:
image.png

Next, use Modbus Poll software to simulate the host to obtain data from the slave device. First define a read and write message.
image.png

Then define a connection information:
image.png

Note: The two COM ports should use different names.

After the communication is successfully established, the message format of the communication is as follows:
image.png

Tx stands for request message, and Rx stands for reply message.

3 ModBus Java implementation

Here's how to use Java to implement a Modbus TCP communication. Here the Java framework uses Spring Boot, and the Modbus library needs to be introduced first. The pom.xml of the Maven dependency library is defined as follows:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!--Modbus Master -->
        <dependency>
            <groupId>com.digitalpetri.modbus</groupId>
            <artifactId>modbus-master-tcp</artifactId>
            <version>1.2.0</version>
        </dependency>
        <!--Modbus Slave -->
        <dependency>
            <groupId>com.digitalpetri.modbus</groupId>
            <artifactId>modbus-slave-tcp</artifactId>
            <version>1.2.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

The dependency on the Modbus library is com.digitalpetri.modbus , which is divided into modbus-master-tcp and modbus-slave-tcp . This example uses a Java project to simulate a Modbus Master, and Modbus Slave software to simulate a Slave. The communication connection mode selects Modbus TCP/IP, and the IP address and port limit the Slave device. The schematic diagram is as follows:
image.png

Since Modbus TCP is used as the connection method here, it is necessary to adjust the connection method in the Modbus Slave connection configuration. The schematic screenshot is as follows:
image.png

The core Java code is as follows:

package com.example.demo.modbus;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import com.digitalpetri.modbus.codec.Modbus;
import com.digitalpetri.modbus.master.ModbusTcpMaster;
import com.digitalpetri.modbus.master.ModbusTcpMasterConfig;
import com.digitalpetri.modbus.requests.ReadHoldingRegistersRequest;
import com.digitalpetri.modbus.responses.ReadHoldingRegistersResponse;
import io.netty.buffer.ByteBufUtil;
import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MBMaster {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

    private final List<ModbusTcpMaster> masters = new CopyOnWriteArrayList<>();
    private volatile boolean started = false;

    private final int nMasters ;
    private final int nRequests ;

    public MBMaster(int nMasters, int nRequests) {
        if (nMasters < 1){
            nMasters = 1;
        }
        if (nRequests < 1){
            nMasters = 1;
        }
        this.nMasters = nMasters;
        this.nRequests = nRequests;
    }
   //启动
    public void start() {
        started = true;

        ModbusTcpMasterConfig config = new ModbusTcpMasterConfig.Builder("127.0.0.1")
                .setPort(50201)
                .setInstanceId("S-001")
                .build();

        new Thread(() -> {
            while (started) {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                double mean = 0.0;
                int mcounter = 0;

                for (ModbusTcpMaster master : masters) {
                    mean += master.getResponseTimer().getMeanRate();
                    mcounter += master.getResponseTimer().getCount();
                }

                logger.info("Mean Rate={}, counter={}", mean, mcounter);
            }
        }).start();

        for (int i = 0; i < nMasters; i++) {
            ModbusTcpMaster master = new ModbusTcpMaster(config);
            master.connect();
            masters.add(master);
            for (int j = 0; j < nRequests; j++) {
                sendAndReceive(master);
            }
        }
    }
   //发送请求
    private void sendAndReceive(ModbusTcpMaster master) {
        if (!started) return;

        //10个寄存器
        CompletableFuture<ReadHoldingRegistersResponse> future =
                master.sendRequest(new ReadHoldingRegistersRequest(0, 10), 0);

       //响应处理
        future.whenCompleteAsync((response, ex) -> {
            if (response != null) {
                //System.out.println("Response: " + ByteBufUtil.hexDump(response.getRegisters()));
                System.out.println("Response: " + ByteBufUtil.prettyHexDump(response.getRegisters()));
                //[00 31 00 46 00 00 00 b3 00 00 00 00 00 00 00 00]
                byte[] bytes = ByteBufUtil.getBytes(response.getRegisters());
                System.out.println("Response Value = " + bytes[3]);//根据业务情况获取寄存器数值
                ReferenceCountUtil.release(response);
            } else {
                logger.error("Error Msg ={}", ex.getMessage(), ex);
            }
            scheduler.schedule(() -> sendAndReceive(master), 1, TimeUnit.SECONDS);
        }, Modbus.sharedExecutor());
    }

    public void stop() {
        started = false;
        masters.forEach(ModbusTcpMaster::disconnect);
        masters.clear();
    }

    public static void main(String[] args) {
       //启动Client进行数据交互
        new MBMaster(1, 1).start();
    }
}

First, you need to use ModbusTcpMasterConfig to initialize the configuration information of a Modbus Tcp Master host, such as IP address (127.0.0.1) and port number (50201), which need to be consistent with Slave. Second, the configuration information config is passed as a parameter to the ModbusTcpMaster object to build a master instance. Finally, use the master.sendRequest(new ReadHoldingRegistersRequest(0, 10), 0) object to query the data. The function code is 03 and the register data is 10. After Modbus Slave opens the connection, the setting interface is as follows:
image.png

Run the Java program. An example of console output is as follows:

Response Value = 16
Response:          +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 08 00 11 00 1b 00 00 00 00 00 00 00 00 00 00 |................|
|00000010| 00 00 00 00                                     |....            |
+--------+-------------------------------------------------+----------------+
Response Value = 17
Response:          +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 09 00 12 00 1c 00 00 00 00 00 00 00 00 00 00 |................|
|00000010| 00 00 00 00                                     |....            |
+--------+-------------------------------------------------+----------------+
Response Value = 18

From this, it can be known that there are required service data in the 15 positions from 0 to f in the returned message, and which position to obtain depends on the settings of the slave device.

Click to follow and learn about Huawei Cloud's fresh technology for the first time~


华为云开发者联盟
1.4k 声望1.8k 粉丝

生于云,长于云,让开发者成为决定性力量