We have already explained the basic business of Modbus and designed the operation flow of the master-slave station that we are going to implement. This is directly related to Modbus is the creation of Modbus message frames. Modbus message frame is also the fundamental to realize Modbus communication protocol.
1 , Modbus Message Frame Analysis
The Modbus protocol has some differences in the message frames on different physical links, but we'll look at the same parts in these different message frames, which is important for us to achieve uniform data manipulation, as described below:
( 1 ), simple Protocol data unit
The Modbus protocol defines a simple protocol data unit (PDU) that is independent of the underlying communication layer. The Simple Protocol data unit is structured as follows:
A PDU is a section that is independent of a specific transport network and contains function codes and data. The MODBUS protocol on a particular bus or network simply introduces some additional domains on the Application Data Unit (ADU) based on the PDU.
The development of the data unit part is the most basic part, mainly is the class capacity of 2 aspects: one is to generate the command part of the client (master) Access server (slave), and the other is to generate the server (slave) response Client (master) reply part.
( 2 ), RTU the Application Data unit
For the Modbus protocol running on a serial link, its Application Data unit (ADU) is based on the PDU, preceded by an address field, followed by a data check. The format is as follows:
The Address field is the address of the slave that is visited, a 8-bit unsigned number, a value of 0-255, but 0 and 255 have fixed meanings that cannot be used. The CRC check uses the CRC16 check method.
( 3 ), TCP the Application Data unit
The Modbus protocol running on the Ethernet link, the Application Data unit (ADU) is formed on the basis of the PDU plus the MBAP packet header, the specific format as follows:
For MBAP headers, the following domains are included:
Domain |
Length |
Describe |
Client |
Server |
Transaction Meta identifier |
2 bytes |
MODBUS Request/Response Transaction Processing Identification code |
Client Startup |
The server re-replicates from the received request |
Protocol identifiers |
2 bytes |
0=modbus protocol |
Client Startup |
The server re-replicates from the received request |
Length |
2 bytes |
The number of the following bytes |
Client startup (Request) |
Server (response) startup |
Unit identifiers |
1 bytes |
Identification number of the remote slave connected on the serial link or other bus |
Client Startup |
The server re-replicates from the received request |
The message header is 7 bytes long from the table above:
Transaction identifier: Used for transaction pairing. In the response, the MODBUS server replicates the requested transaction identifier.
Protocol identifier: Used for multiplexing within the system. The MODBUS protocol is identified by a value of 0.
Length: The Length field is the number of bytes in the next field, including the cell identifier and data field.
Unit identifier: Use this domain for intra-system routing. Specifically used to communicate with the Modbus or modbus+ serial link slave through the gateway between the Ethernet TCP-IP network and the Modbus serial link. The simple point is that the Address field in the serial link. The Modbus client sets this domain in the request and the server must return the domain with the same value in the response.
2 , data frame analysis of the specific composition
From the analysis of the simple protocol basic data element, RTU Application Data unit and TCP Application Data unit message format, we find that the basic data unit part is consistent, so we can consider the layered encapsulation protocol operation part:
The first implementation of the Modbus basic data unit, which is the common part of the data is not related to the specific application, only need to encapsulate once, for this part of the development only need to follow the standard protocol of Modbus development is good, this time we plan to achieve 8 features:
function code |
Name |
Realize |
Describe |
0x01 |
Read Coil |
Is |
Read-write-readable state amount |
0x02 |
Read discrete input |
Is |
Reading a read-only state amount |
0x03 |
Read Hold Register |
Is |
Read-write-readable register quantum |
0x04 |
Read Input Register |
Is |
Read-only register quantum |
0x05 |
Write a single coil |
Is |
Write to a single read-write state amount |
0x06 |
Write a single register |
Is |
Write to a single read-write register quantum |
0x0F |
Write multiple coils |
Is |
Write to multiple read-write state quantities |
0x10 |
Write multiple registers |
Is |
Write to multiple read-write register quanta |
These 8 are also the most important functions defined by the Modbus protocol, and now the message formats for these function codes are described as follows:
( 1 ) Read Coil 0x01
Read the coil is a kind of can write the switch amount, because the Modbus protocol originated in the PLC application, and the coil is the name of the PLC do output, generally applies to the master station to release the Operation command from the station. The data format for reading this state volume with read and write capabilities is as follows:
Its issued command format is: domain + function code + start address + number.
( 2 ) Read discrete input 0x02
The read state input is a read-only switching signal that corresponds to the digital input in the PLC. The format for reading this read-only switch input is as follows:
Its issued command format is: domain + function code + start address + number.
( 3 ) Read hold register 0x03
The hold register refers to 16-bit data that can be read and written, and can be used to represent various data, such as 8-bit integers, 16 integers, 32-bit integers, 64-bit integers, and single-double precision floating-point numbers, by single or multiple hold registers. The message format for reading the hold register is as follows:
Its issued command format is: domain + function code + start address + number.
( 4 ) Read input register 0x04
The input register is a read-only form of 16-bit data. A single or multiple input registers can represent 8-bit integers, 16 integers, 32-bit integers, 64-bit integers, and single-and double-precision floating-point numbers. The message format for reading the input register is as follows:
Its issued command format is: domain + function code + start address + number.
( 5 ) write a single coil 0x05
Write a single coil volume is to operate on a single read and write switch, but it is not directly write "0" or "1", but to write "1" when it is required to send 0xff00, and in the need to write "0" when the 0x0000, the specific message format is as follows:
Its issued command format is: domain + function code + output address + output value. The specific content of the command differs from the read operation, but the format is exactly the same, and the actual read and write can be encapsulated together during programming.
( 6 ) write a single register 0x06
To write a single register is to operate on a single hold register, the format of the data is still the same, the actual application is only applicable to 16-bit integer data operation, for floating-point numbers, etc. can not.
Its issued command format is: domain + function code + output address + output value. The specific content of the command differs from the read operation, but the format is exactly the same, and the actual read and write can be encapsulated together during programming.
( 7 ) write multiple coils 0x0F
Write multiple coils of the operation of the object and write a single coil is exactly the same, the difference is the number and operation value, especially the value, write "1" is "1", write "0" is "0", which is the difference between writing a single coil.
The command format is: domain + function code + start address + Output quantity + bytes + output value. The command message differs greatly from the previous reading and writing operations and must be handled separately.
( 8 ) write multiple registers 0x10
Writing multiple registers is the simultaneous operation of multiple read/write registers, the format of the data message is consistent with the writing of multiple coils.
The command format is: domain + function code + start address + Output quantity + bytes + output value.
3 , basic data unit programming
Through the above analysis, we found that no matter what kind of physical link implementation of the application data, the basic data segment is the same. In fact, plus the domain name segment format is the same, so we will
Domain name +PDU is implemented together as the most basic data unit.
The implementation of the basic data unit is divided into 2 cases: first, as the Master (client), the slave (server) issued the command, and the second is as a slave (server), the response to the Master (client) command. So we encapsulate each of these two scenarios as 2 basic functions:
(1), as the RTU Master (TCP client), generate commands to read and write RTU slave (TCP Server) objects:
uint16_t Generatereadwritecommand (objaccessinfo objinfo,bool *statuslist,uint16_t *registerList,uint8_t * Commandbytes)
The parameters are the basic information of the PDU unit, the corresponding data of the write object, and the generated command byte. The return value is the length of the generated command.
(2), as a Slave (server), generates a response to the master Read access. For a response because the response to the write operation is actually part of the command that replicates the master (client), the response we actually need to generate is the case of 0x01, 0x02, 0x03, and 0x04 function codes.
uint16_t Generatemasteraccessrespond (uint8_t *receivedmessage,bool *statuslist,uint16_t *registerList,uint8_t * Respondbytes)
The parameters are the received information, the data of the object being read, and the response message returned. The return value is the length of the response message that is returned.
4 , RTU programming of the Application Data unit
For the RTU Application Data unit, the message format is: "Domain name +PDU+CRC", and the domain name +PDU we have implemented in the previous section, so to implement the RTU data unit actually we just need to add CRC checksum has been completed.
The implementation of the RTU data unit is divided into 2 cases: first, as the main station, the command issued to the slave, and the second, as a slave, the response to the command of the master station. So we encapsulate each of these two scenarios as 2 basic functions:
(1), as the main station of the RTU, generate commands to read and write Rtu slave objects:
/* command to generate read-write Slave data Objects, command length includes 2 check bytes */
uint16_t Syntheticreadwriteslavecommand (objaccessinfo slaveinfo,bool *statuslist,uint16_t *registerList,uint8_t * Commandbytes)
The parameters are the slave basic information, the data list issued, and the resulting command array. The return value is the length of the command.
(2), as a slave, generates a master Read access response:
/* Generate a response from the slave answering master */
uint16_t Syntheticslaveaccessrespond (uint8_t *receivedmessage,bool *statuslist,uint16_t *registerList,uint8_t * Respondbytes)
The parameters are the received information, the returned data list, and the resulting response information list. The return value is the length of the response information list.
5 , TCP programming of the Application Data unit
And for the TCP Application Data unit, and the RTU class, the message format is: "MBAP head +pdu", and PDU unit is defined previously, so only need to add mbap head on it, in fact mbap the implementation of the head of the format is fixed.
The implementation of the TCP Application Data unit is also divided into 2 cases: first, as a client, the server issued a command, and the second, as a server, the response to the client command. So we encapsulate each of these two scenarios as 2 basic functions:
(1), as a TCP client, generate commands to read and write to the TCP server object:
/* Generate commands to read and write server objects */
uint16_t Syntheticreadwritetcpservercommand (objaccessinfo objinfo,bool *statuslist,uint16_t *registerList,uint8_t * Commandbytes)
(2), as (server, generate client read-Write access response:
/* Composite response to server access, return value is command length */
uint16_t Syntheticserveraccessrespond (uint8_t *receivedmessage,bool *statuslist,uint16_t *registerList,uint8_t * Respondbytes)
6 , concluding remarks
In fact, we have basically realized the basic protocol of Modbus, even using these basic operation can realize modbus communication. In fact, many people in the application of the Modbus communication protocol is simpler than this, but also to achieve some of the modbus communication functions. Of course, this is not our goal, otherwise we do not need to specifically develop the library, we want to further encapsulation, so that it is more general and easier to use is what we need.
Modbus Library Development Note II: The generation of Modbus message frames