In compliance with high industry standards

Browse our Blog. You will find multiple applications, solutions, code examples. Navigate using the tag cloud or search using specific criteria

Modbus RTU Master Library for industrial automation

Modbus Master

Index

  1. Introduction

  2. Communicating by MODBUS RTU through an RS485 serial interface (Seneca Z-D-in Module)

  3. Modbus object types

  4. Communications of Modbus RTU

  5. Modbus RTU format frame

  6. Modbus function codes

  7. The data format of requests and responses for main Modbus RTU function codes

  8. Main Modbus Master exception codes

  9. Coil, discrete input, input register, holding register numbers and addresses

  10. Uses

  11. Software


Introduction of Modbus RTU Master library for industrial automation

Introduction

In the Arduino automation area, the Modbus RTU protocol is a means of communication that allows the exchange of data between programmable logic controllers (industrial PLC controller Arduino) and computers.

Electronic devices can exchange information through serial lines using the Modbus protocol.

This post will talk about how to use the Modbus RTU with our libraries.

First of all, it would be good for you to have a look at this other post so you can get information about what it is, its connection and its characteristics.

Communicating by MODBUS RTU through an RS485 serial interface (Seneca Z-D-in Module)

It is important to say that this type of communication has some limitations:

  • Large binary objects are not supported.

  • Its does not exist a standard way for a node to find the description of a data object.

  • It is not possible¬†to know (except for Ethernet TCP-IP) if there is a change in one of our peripheral devices. The only way to get this information is to ask constantly and look for changes in the data, but this fact consumes bandwidth and network time in apps where bandwidth may be expensive, for example over a low-bit-rate radio link.

  • Limitation in addressing 254 devices on one data link¬†restricts the number of field devices that we can connect to our master (we can resolve this problem with Ethernet TCP/IP).

  • The transmissions must be contiguous, which limits the types of remote communications devices to those that can buffer data to avoid gaps in the transmission.

  • This protocol does not provide security against unauthorized commands or interception of data, but it is not usual to find those facts in the industry.

In summary, Modbus RTU is used in serial communication and makes use of a compact, binary representation of the data for protocol communication.

The RTU format follows the data with a cyclic redundancy check checksum as an error tests mechanism to ensure the reliability of data. Modbus RTU is the most common implementation available for Modbus. This protocol message must be transmitted constantly without inter-character hesitations. Modbus messages are divided by idle periods.

Modbus object types

Modbus object types
Communications of Modbus RTU Master library

Communications of Modbus RTU

Each device on a Modbus communication has a unique address.

The Modbus RTU works by RS-485 which is a single cable multi-drop network, only the node assigned as the Master may initiate a command.

All the other devices are slaves and answer to requests and commands.

Some many modems and gateways support Modbus Master, as it is a very simple and often copied protocol. Some of them were specifically designed for this protocol.

Different implementations use wireline, wireless communication, such as in the ISM band, and even SMS or GPRS. One of the more common designs of wireless networks makes use of mesh networking. 

A Modbus command contains the Modbus address of the device it is intended for (1 to 247). Only the addressed device will respond and act on the command, even though other devices might receive it (an exception is specific broadcastable commands sent to node 0, which are acted on but not acknowledged). 

Also, it is important to say that all Modbus commands contain checksum information to allow the recipient to detect transmission errors.

Modbus RTU format frame

Modbus RTU format frame 

Available functions/command codes

Reading, writing and other operations are categorized as follows. Prominent entities within a Modbus slave are:

  • Coils: readable and writable, 1 bit (on-off)

  • Discrete Inputs: readable, 1 bit (on-off)

  • Inputs Registers: readable, 16 bits (0 to 65.535), essentially measurements and statuses.

  • Holding Registers: readable and writable, 16 bits (0 to 65.535), essentially configuration values.

Modbus function codes

Modbus function codes 


The data format of requests and responses for main Modbus RTU function codes

Here you will find the details of data formats of the most used function codes

    *Function code 1 (read coils) and function code 2 (read discrete inputs)

Request

  • Address of first coil/discrete input to read (16 - bit)

  • Number of coils/discrete inputs to read (16 - bit)

Normal response

  • Number of bytes of coil/discrete input values to follow (8 bit)¬†

  • Coil/discrete input values (8 coils/discrete inputs per byte)

We have to know that each coil/discrete input value is binary (0-off, 1-on). The first requested coil/discrete input is stored as the least significant bit or first byte in reply. In case that the number of coils/discrete inputs is not a multiple of 8, the most significant bit of the last byte will be stuffed with zeros. Because the byte count returned in the reply message is only 8 bits wide and the protocol overhead is 5 bytes, a maximum of 2008 ( 251 x 8 ) discrete inputs or coils can be read at once.


    *Function code 5 (force/write single coil)

Request

  • Address of coil (16-bit)

  • Value to force/write:¬†0 for off and 65280 (FF00 in hexadecimal) for on.

Normal response

The same as Request.


    *Function code 15 (force/write multiple coils)

Request

  • Address of the first coil to force/write (16-bit)

  • Number of coils to force/write (16-bit)

  • Number of bytes of coil values to follow (8-bit)

  • Coil values (8 coil values per byte)

The value of each coil is binary (0-off,  1-on). The first requested coil is stored as the least significant bit of the first byte in the request. If the number of coils isn't a multiple of 8, the most significant bit of the last byte should be stuffed with zeros. 

Normal response

  • Address of first coil (16-bit)

  • The number of coils (16-bit)


    *Function code 4 (read input registers) and function code 3 (read holding registers).

Request

  • Address of the first register to read (16-bit)

  • Number of registers to read (16-bit)

Normal response

  • Number of bytes of the register to read (16-bit)

  • Register values (16 bits per register)

Because the number of bytes for register values is 8-bit wide and the maximum Modbus message size is 256 bytes, only 125 registers for Modbus RTU and 123.


*Function code 6 (preset/write single holding register)

Request

  • Address of holding register to preset/write (16-bit)

  • The new value of the holding register (16-bit)

Normal response

The same as Request.


    *Function code 16 (preset/write multiple holding registers)

Request

  • Address of first holding register to preset/write (16-bit)

  • Number of holding registers to preset/write (16-bit)

  • Number of bytes of register values to follow (8-bit)

  • New values of holding registers (16 bits per register)

Because register values are 2-bytes wide and only 127 bytes worth of values can be sent, only 63 holding registers can be preset/written at once.

Normal response

  • Address of first preset/written holding register (16-bit)

  • Number of present/written holding registers (16-bit)

Main Modbus exception codes

 


Coil, discrete input, input register, holding register numbers and addresses

Entity numbers combine entity type and entity location within their description table.

Entity address is the starting address, as a 16-bit value in the data part of the Modbus frame. As such its range goes from 0 to 65.535

In the traditional standard, numbers for those entities start with a digit, followed by a number of 4 digits in the range 1-9.999:

  • Coils numbers start with 0 and span from 00001 to 09999

  • Discrete input numbers start with 1 and span from 10001 to 19999

  • Input register numbers start with 3 and span from 30001 to 39999

  • Holding register numbers start with 4 and span from 40001 to 49999

This results in addresses between 0 and 9.999 in data frames. For example, to read holding registers, starting at number 40001, the corresponding address in the data frame will be 0 with a function code of ( as seen above ). For holding registers starting at number 40100, the address will be 99. etc...

This limits the number of addresses to 9.999 for each entity. A de facto referencing extends this to the maximum of 65.536. Basically consists of adding one digit to the previous list:
  • Coil numbers span from 000001 to 065536

  • Discrete input numbers span from 100001 to 165536

  • Input register numbers span from 300001 to 365536

  • Holding register numbers span from 400001 to 465536

If you are using extended referencing, all the number references must have exactly 6 digits. This avoids confusion between coils and other entities. For example, to know the difference between holding register #40001 and coil #40001 is the target, it must appear as #040001.

Uses

Some of the most common uses of Modbus RTU

Data types

  • IEEE floating-point number

  • 32-bit integer¬†

  • 8-bit data

  • Mixed data types

  • Bit fields in integers

  • Multipliers to change data to/from integer. 10, 100, 1000, 256...

Protocol extensions

  • 16-bit slave addresses

  • 32-bit data size (1 address=32 bit of data returned)

  • Word-swapped data

Software with Modbus Library

Modbus RTU Master with Arduino IDE

The Modbus RTU Master Module implements the Modbus RTU Master capabilities. We are going to work with the modbusrtumaster.h function:

#include <ModbusRTUMaster.h>


There is the possibility to use any hardware Serial Arduino stream:

  • RS-485

#include <RS485.h>

ModbusRTUMaster master(RS485);


  • RS-232

#include <RS232.h>

ModbusRTUMaster master(RS232);


Before using it, it is required to call the begin function in the setup for both the serial and the Modbus variable. It is a good practice to set the baud rate (default: 19200 bps) also in the Modbus variable to define the Modbus internal timeouts.

RS485.begin(9600, HALFDUPLEX, SERIAL_8E1);
master.begin(9600);


The functions to read and write slave values are:

readCoils(slave_address, address, quantity);
readDiscreteInputs(slave_address, address, quantity);
readHoldingRegisters(slave_address, address, quantity);
readInputRegisters(slave_address, address, quantity);
writeSingleCoil(slave_address, address, value);
writeSingleRegister(slave_address, address, value);
writeMultipleCoils(slave_address, address, values, quantity);
writeMultipleRegisters(slave_address, address, values, quantity);


Where :

  • slave_address¬†is the Modbus RTU slave address.

  • address¬†is the coil, digital input, holding register or input register address. Usually, this address is the coil, digital input, holding register or input register number minus 1: the holding register number¬†40009¬†has the address¬†8.
    quantity is the number of coils, digital, holding registers or input registers to read/write.
  • value¬†is the given value of the coil or holding registers on a write operation. Depending on the function the data type changes. A coil is represented by a¬†bool¬†value and a holding register is represented by a¬†uint16_t¬†value.

On a multiple read/write function the address argument is the first address. On a multiple write function, the values argument is an array of values to write.

It is important to say that these functions are non-blocking, so they do not return the read value. They return true or false depending on the current module state. If there is a pending Modbus request, they return false.  

// Read 5 holding registers from address 0x24 of slave with address 0x10
if (master.readHoldingRegisters(0x10, 0x24, 5)) {
	// OK, the request is being processed
} else {
	// ERROR, the master is not in an IDLE state
}

There is the function vailable()  to check for responses from the slave:

ModbusResponse response = master.available();
if (response) {
	// Process response
}


The ModbusResponse implements some functions to get the response information:

hasError();
getErrorCode();
getSlave();
getFC();
isCoilSet(offset);
isDiscreteInputSet(offset);
isDiscreteSet(offset);
getRegister(offset);
ModbusResponse response = master.available();
if (response) {
	if (response.hasError()) {
		// There is an error. You can get the error code with response.getErrorCode()
	} else {
		// Response ready: print the read holding registers
		for (int i = 0; i < 5; ++i) {
			Serial.println(response.getRegister(i));
		}
	}
}

 

The possible error codes are:

0x01 ILLEGAL FUNCTION
0x02 ILLEGAL DATA ADDRESS
0x03 ILLEGAL DATA VALUE
0x04 SERVER DEVICE FAILURE


Looking for your ideal PLC?

Take a look at this product comparison with other industrial controllers Arduino.

We are comparing inputs, outputs, communications and other features with the ones of the relevant brands.


Industrial PLC controller comparison >>

Do you want more information?

Just fill the form!

Tell me more!