My Cart

Modbus Tutorial for Arduino, Raspberry Pi and Intel Galileo

Difficulty Level: Intermediate -


Modbus is a serial communications protocol originally published by Schneider Electric in 1979 for use with their programmable logic controllers (PLCs). Modbus is located in the level 2 of the OSI model, and uses a master/slave (or client-server) architecture. Simple and robust, it has since become a de facto standard communication protocol, and it is now a commonly available means of connecting industrial electronic devices. Modbus communication protocol presents the follow features:

  • It has been developed with industrial applications in mind
  • Openly published and royalty-free
  • Easy development and maintenance

Modbus allows communication between many devices connected to the same network, for example a system that measures temperature and humidity and communicates the results to a computer. Many of the data types are named from its use in driving relays: a single-bit physical output is called a coil, and a single-bit physical input is called a discrete input or a contact.

This list includes some of the most common uses of the standard:

  • Multiple master-slave applications
  • Sensors and instruments
  • Industrial networking
  • Building and infrastructure
  • Transportation and energy applications
Modbus
Data area Up to 255 bytes per job
Interface Layer 7 of the ISO-OSI reference model
Number of possible connections Up to 32 in multi point systems
Frame format RTU
Operating mode Master/Slave

Get the shields

Kits

1. Features

Modbus for Arduino/RaspberryPi/Galileo uses RTU mode of transmission. This mode is used in serial communication and makes use of a compact, binary representation of the data for protocol communication. The RTU format follows the commands/data with a cyclic redundancy check checksum as an error check mechanism to ensure the reliability of data. Modbus RTU is the most common implementation available for Modbus. A Modbus RTU message must be transmitted continuously without inter-character hesitations. Modbus messages are framed by idle periods.

The Modbus RTU transmission mode usually includes a parity bit to detect transmission errors. You can choose to transmit data with or without parity checking, but always make sure that all equipment connected to Modbus has the same configuration mode, otherwise communication will not be possible.

Modbus RTU frame

An RTU frame includes the following information:

  • Address: Valid slave device addresses are in the range of 0 ... 247 (decimal). The individual slave devices are assigned addresses in the range of 1... 247. Value 0 is reserved for broadcast messages (no response). When the slave sends its response, it places its own address in this address field of the response frame to let the master know which slave is responding.
  • Code Function: Valid codes are in the range of 1... 255 (decimal). The function code field tells the slave what kind of action to perform. For a normal response, the slave simply echoes the original function code. For an exception response, the slave returns a code that is equivalent to the original function code with its most significant bit set to a logic 1. All Modbus devices recognize the same set of function codes.
  • Data: The data field contains additional information which the slave must use to take the action defined by the function code. This can include items like register addresses, quantity of items to be handled, etc. If no error occurs, the data field contains the data requested. If an error occurs, the field contains an exception code that the master application can use to determine the next action to be taken.
  • CRC: The checksum is calculated by the master and sent to the slave. The checksum is re-calculated by the slave and compared to the value sent by the master. If a difference is detected, the slave will not construct a response to the master.

2. The boards

RS-485 and RS-232 PCBs

The Modbus protocol can be implemented over RS-485 and RS-232 phisical layers. Cooking-Hacks provides the necesary hardware and software for working with both protocols. The name and use of the functions are the same for RS-232 and RS-485, and the only changes are the library to include and the instantiation of the object. The diferences between the two standards are explained in the corresponding tutorials.

Modbus over Arduino

The RS-485 module must be used in combination with the Multiprotocol Radio Shield. The Multiprotocol Radio Shield has two sockets. The RS-485 module must be connected as shown in the next figures.

The RS-232 module is compatible with the Multiprotocol Radios Shield and the XBee shield.

Please, see the Multiprotocol Radio Shield Tutorial for more information.

Get Arduino
Get the RS-485 module
Get the RS-232 module
Get the Multiprotocol Radio Shield

Modbus over Raspberry Pi

Get Raspberry Pi
Get the Raspberry Pi to Arduino shields connection bridge
Get the RS-485 module
Get the RS-232 module

Warnings::

  • The RS-485 module must be connected in the corresponding socket as shown in this tutorial.
  • The RS-485 module is not compatible with the XBee Shield. You have to use the Multiprotocol Radio Shield as shown in this tutorial.
  • The RS-232 can be connected in the two sockets of the Multiprotocol Radio Shield.
  • The RS-232 module is compatible with the XBee Shield.
  • The RS-232 and the RS-485 modules have been tested with several devices, but we don't ensure the compatibility with all commercial devices.

3. The Library

The Modbus protocol counts with a C++ library that lets you manage the Modbus functions in a simple way. This library offers an simple-to-use open source system.

In order to ensure the same code is compatible in both platforms (Arduino and Raspberry Pi) we use the ArduPi libraries which allows developers to use the same code. Detailed info can be found here:

Using the library with Arduino

The Modbus protocol includes a high level library functions for a easy manage. Before start using this functions you should download the files from the next link. This zip includes all the files needed in several folders. These folders include the necessary file for using Modbus protocol in master and slave mode.

Download the Modbus / RS-485 library for Arduino

Download the Modbus / RS-232 library for Arduino

Libraries are often distributed as a ZIP file or folder. The name of the folder is the name of the library. Inside the folder will be the .cpp files, .h files and often a keywords.txt file, examples folder, and other files required by the library.

To install the library, first quit the Arduino application. Then uncompress the ZIP file containing the library. For installing libraries , uncompress zip file. Drag the folders into this folder (your libraries folder). Under Windows, it will likely be called "My Documents\Arduino\libraries". For Mac users, it will likely be called "Documents/Arduino/libraries". On Linux, it will be the "libraries" folder in your sketchbook.

The library won't work if you put the .cpp and .h files directly into the libraries folder or if they're nested in an extra folder. Restart the Arduino application. Make sure the new library appears in the Sketch->Import Library menu item of the software.

Using the library with Raspberry Pi

The Modbus libraries for Raspberry Pi requires the ArduPi library and both libraries should be in the same path.

Download the Modbus / RS-485 library for Raspberry Pi

Download the Modbus / RS-232 library for Raspberry Pi

Creating a program that uses the library is as simple as putting your code in this template where it says "your Arduino code here"

Code:
//Include Modbus library (it includes arduPi)


/*********************************************************
 *  IF YOUR ARDUINO CODE HAS OTHER FUNCTIONS APART FROM  *
 *  setup() AND loop() YOU MUST DECLARE THEM HERE        *
 * *******************************************************/

/**************************
 * YOUR ARDUINO CODE HERE *
 * ************************/

int main (){
        setup();
        while(1){
                loop();
        }
        return (0);
}
    

Compilation of the program (using Modbus library) can be done in two ways:

  • Compiling separately Modbus and arduPi, and using them for compiling the program in a second step:
g++ -c arduPi.cpp -o arduPi.o
g++ -c RS485.cpp -o RS485.o
g++ -c Modbusmaster485.cpp Modbusmaster485.o
g++ -lpthread -lrt user-Modbus-app.cpp arduPi.o RS485.o Modbusmaster485.o -o user-Modbus-app
  • Compiling everything in one step:
g++ -lpthread -lrt user-Modbus-app.cpp arduPi.cpp RS485.cpp ModbusMaster485.cpp -o user-Modbus-app

Executing your program is as simple as doing:

sudo ./user-Modbus-app

Using the library with Intel Galileo

The Modbus module includes a high level library functions for a easy manage. Before start using this functions you should download the files from the next link. This zip includes all the files needed in several folders. These folders include the necessary file for using Modbus protocol.

Download the Modbus / RS-485 library for Intel Galileo

Download the Modbus / RS-232 library for Intel Galileo

Libraries are often distributed as a ZIP file or folder. The name of the folder is the name of the library. Inside the folder will be the .cpp files, .h files and often a keywords.txt file, examples folder, and other files required by the library.

To install the library, first quit the Arduino application. Then uncompress the ZIP file containing the library. For installing libraries , uncompress zip file. Under Windows, it will likely be called "My Documents\Arduino\libraries". For Mac users, it will likely be called "Documents/Arduino/libraries". On Linux, it will be the "libraries" folder in your sketchbook.

The library won't work if you put the .cpp and .h files directly into the libraries folder or if they're nested in an extra folder. Restart the Arduino application. Make sure the new library appears in the Sketch->Import Library menu item of the software.

General Modbus function

Initialization functions

ModbusMaster485();        // Creates class object using default Modbus slave ID 1
ModbusMaster485(uint8_t); // Creates class object using specified Modbus slave ID
begin();                  // Sets up the serial port using default 19200 baud rate
begin(unsigned long );    // Sets up the serial port using specified baud rate

Send and receive functions

uint8_t readCoils(uint16_t, uint16_t);             // Modbus function 0x01 Read Coils  
uint8_t readDiscreteInputs(uint16_t, uint16_t);    // Modbus function 0x02 Read Discrete Inputs
uint8_t readHoldingRegisters(uint16_t, uint16_t);  // Modbus function 0x03 Read Holding Registers
uint8_t readInputRegisters(uint16_t, uint8_t);     // Modbus function 0x04 Read Input Registers
uint8_t writeSingleCoil(uint16_t, uint8_t);        // Modbus function 0x05 Write Single Coil
uint8_t writeSingleRegister(uint16_t, uint16_t);   // Modbus function 0x06 Write Single Register
uint8_t writeMultipleCoils(uint16_t, uint16_t);    // Modbus function 0x0F Write Multiple Coils  
uint8_t writeMultipleRegisters(uint16_t, uint16_t);// Modbus function 0x10 Write Multiple Registers

Utile functions

void    setSlaveAddress(uint8_t);     // Changes the slave address
uint8_t  available(void);             // Returns the availbale data read
uint16_t getResponseBuffer(uint8_t);  // Retrieve data from response buffer
void     clearResponseBuffer();       // Clear Modbus response buffer
uint8_t  setTransmitBuffer(uint8_t, uint16_t);  // Place data in transmit buffer
void     clearTransmitBuffer();       // Place data in transmit buffer

NOTE:

  • More functions are included in the Modbus libraries.
  • For complete information and description of Modbus functions view the libraries files.

4. Connecting Devices

Modbus communication protocol over RS-485

Modbus allows communication between many devices connected to the same network, for example a system that measures temperature and humidity and communicates the results to a computer. Many of the data types are named from its use in driving relays: a single-bit physical output is called a coil, and a single-bit physical input is called a discrete input or a contact.

In this example we are going to show how to use th RS-485 module to connect Arduino and Raspbery Pi platforms to Modbus devices measurement devices.

First of all, you must be sure that your device is compatible with Arduino and Raspberry. In the device manual will be described the communication parameters (device address, baud rate...). You also must check that the device uses RTU format. There are many variants of Modbus protocols, but the Arduino library implements the RTU format. Modbus RTU is the most common implementation available for Modbus.

Parameter Setting
Baud 19200
Parity N
Data bits 8
Stop bit 1
Flow control None

The next step is to know what Modbus commands uses the device. The supported commands should be listed in a table. In the next Figure you can see an example of the Modbus commands extracted from a data sheet. The Modbus library for Waspmote is compatible with the majority of the Modbus commands.

Command Name Command Number
Read Holding Register 03
Write (Preset) Single Register 06
Return Slave ID 17

Connect the signals A/B of the RS-485 module with the corresponding signal of the Modbus device. The name of these signal can change depending on the manufacturer. Usual names of these signal are A/B S+/S-, +/-, etc.

In our example, we are going to read the temperature value from our device. We can see in the register map, that the temperature value is stored in the register 101 and is accessible with the function readHoldingRegisters, and is stored in 16 bits format (2 bytes). So the necessary function to get the value of the temperature is shown in the next code example.

Address Bytes Range Defaults
(°C /°F)
Register and Description
0 to 3 4 - - Serial Number -4 byte value. Read-only
4 to 5 2 - - Serial Version -2 byte value. Read-only
6 1 255 254 ADDRESS. Modbus device address
100 2 0-1000 - ROOM TEMPERATURE reading in DegF
101 2 0-600 - ROOM TEMPERATURE reading in DegC
304 2 0-1000 - Relative Humidity reading. Writing a humidity value to the register will do calibration.

Arduino / Intel Galileo

Code:
/*  
 *  ModBus Module
 *  
 *  Copyright (C) Libelium Comunicaciones Distribuidas S.L. 
 *  http://www.libelium.com 
 *  
 *  This program is free software: you can redistribute it and/or modify 
 *  it under the terms of the GNU General Public License as published by 
 *  the Free Software Foundation, either version 3 of the License, or 
 *  (at your option) any later version. 
 *  a
 *  This program is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License 
 *  along with this program.  If not, see http://www.gnu.org/licenses/. 
 *  
 *  Version:           1.0
 *  Design:            David GascĂłn 
 *  Implementation:    Ahmad Saad
 */


// Include these libraries for using the RS-485 and Modbus functions
#include <RS485.h>
#include <ModbusMaster485.h>
#include <SPI.h>

// Instantiate ModbusMaster object as slave ID 1
ModbusMaster485 node(254);

// Define one addres for reading
#define address 101

// Define the number of bytes to read
#define bytesQty 2

void setup()
{
  
  // Power on the USB for viewing data in the serial monitor
  Serial.begin(115200);
  delay(100);
  // Initialize Modbus communication baud rate
  node.begin(19200);

  // Print hello message
  Serial.println("Modbus communication over RS-485");
  delay(100);
}


void loop()
{
  // This variable will store the result of the communication
  // result = 0 : no errors
  // result = 1 : error occurred
  int result =  node.readHoldingRegisters(address, bytesQty);

  if (result != 0) {
    // If no response from the slave, print an error message
    Serial.println("Communication error");
    delay(1000);
  }
  else {

    // If all OK
    Serial.print("Read value : ");

    // Print the read data from the slave
    Serial.print(node.getResponseBuffer(0));
    delay(1000);
  }

  Serial.print("\n");
  delay(2000);

  // Clear the response buffer
  node.clearResponseBuffer();

}
    

Raspberry Pi

You have to compile the Modbusmaster485 library:

g++ -c Modbusmaster485.cpp -o Modbusmaster485.o

g++ -lpthread -lrt Modbus_example.cpp arduPi.o RS485.o currentLoop.o -o  Modbus_example

Code:
/*  
 *  ModBus Module
 *  
 *  Copyright (C) Libelium Comunicaciones Distribuidas S.L. 
 *  http://www.libelium.com 
 *  
 *  This program is free software: you can redistribute it and/or modify 
 *  it under the terms of the GNU General Public License as published by 
 *  the Free Software Foundation, either version 3 of the License, or 
 *  (at your option) any later version. 
 *  a
 *  This program is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License 
 *  along with this program.  If not, see http://www.gnu.org/licenses/. 
 *  
 *  Version:           1.0
 *  Design:            David GascĂłn 
 *  Implementation:    Ahmad Saad
 */


// Include these libraries for using the RS-485 and Modbus functions

#include "ModbusMaster485.h"
#include "arduPi.h"


// Instantiate ModbusMaster object as slave ID 1
ModbusMaster485 node(254);

// Define one addres for reading
#define address 101

// Define the number of bytes to read
#define bytesQty 2

void setup()
{
  pinMode(5, OUTPUT);
  digitalWrite(5, LOW);
  
  // Power on the USB for viewing data in the serial monitor
  Serial.begin(115200);
  delay(100);
  // Initialize Modbus communication baud rate
  node.begin(19200);

  // Print hello message
  printf("Modbus communication over RS-485\n");
  delay(100);
}


void loop()
{
  // This variable will store the result of the communication
  // result = 0 : no errors
  // result = 1 : error occurred
  int result =  node.readHoldingRegisters(address, bytesQty);

  if (result != 0) {
    // If no response from the slave, print an error message
    printf("Communication error\n");
    delay(1000);
  }
  else {

    // If all OK
    printf("Read value : \n");

    // Print the read data from the slave
    Serial.print(node.getResponseBuffer(0));
    delay(1000);
  }

  printf("\n");
  delay(2000);

  // Clear the response buffer
  node.clearResponseBuffer();

}

int main (){
  setup();
  while(1){
    loop();
  }
  return (0);
}

You should receive the data in your serial monitor.

Dual protocol connection with Multriprotocol Radio Shield

The Multiprotocol Radio Shield can be used to connect two communication protocols at the same time and make interconnections between different systems and devices. In the next example we are going to interconnect a Modbus device over RS-485 module with wireless protocol using and XBee module.

NOTE:

  • In AP=0 all data send trough the UART will be send by the XBee module.
  • The XBee 802.15.4 modules must be connected using external pins. These pins must have the pin 4 of the XBee cut or disconnected to avoid interferences between modules.

Connect the RS-485 module and XBee modules in the corresponding sockets as shown in the next image.

If you are using 802.15.4, use external pine with pin4 disconnected.

You should receive all data in your gateway device.

Arduino

Code:
/*  
 *  ModBus Module
 *  
 *  Copyright (C) Libelium Comunicaciones Distribuidas S.L. 
 *  http://www.libelium.com 
 *  
 *  This program is free software: you can redistribute it and/or modify 
 *  it under the terms of the GNU General Public License as published by 
 *  the Free Software Foundation, either version 3 of the License, or 
 *  (at your option) any later version. 
 *  a
 *  This program is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License 
 *  along with this program.  If not, see http://www.gnu.org/licenses/. 
 *  
 *  Version:           1.0
 *  Design:            David GascĂłn 
 *  Implementation:    Ahmad Saad
 */


// Include these libraries for using the RS-485 and Modbus functions
#include <RS485.h>
#include <ModbusMaster485.h>
#include <SPI.h>

// Instantiate ModbusMaster object as slave ID 1
ModbusMaster485 node(254);

// Define one addres for reading
#define address 101

// Define the number of bytes to read
#define bytesQty 2

void setup()
{
  
  // XBee in SOCKET0
  pinMode(5, OUTPUT);
  digitalWrite(5, LOW);

  // Power on the USB for viewing data in the serial monitor
  Serial.begin(115200);
  delay(100);
  // Initialize Modbus communication baud rate
  node.begin(19200);

  // Print hello message
  Serial.println("Modbus communication over RS-485");
  delay(100);
}



void loop()
{
  // This variable will store the result of the communication
  // result = 0 : no errors
  // result = 1 : error occurred
  int result =  node.readHoldingRegisters(address, bytesQty);

  if (result != 0) {
    // If no response from the slave, print an error message
    Serial.println("Communication error");
    delay(1000);
  }
  else {

    // If all OK
    Serial.print("Read value : ");

    // Print the read data from the slave
    Serial.print(node.getResponseBuffer(0));
    delay(1000);
  }

  Serial.print("\n");
  delay(2000);

  // Clear the response buffer
  node.clearResponseBuffer();

}
    

Device Compatibility

This shield is tested and fully compatible with the following boards:

Arduino Boards

  • Arduino Uno

Raspberry Pi Boards

  • Raspberry Pi
  • Raspberry Pi (Model B+)
  • Raspberry Pi 2
  • Raspberry Pi 3