MODBUS with Industrial Shields Raspberry PLC

Examples of using the Modbus RTU and TCP protocol with Raspberry PLC as a MASTER with different programming languages
April 29, 2024 by
MODBUS with Industrial Shields Raspberry PLC
Boot & Work Corp. S.L., DAVID CORONADO TRAVASET

What we find in this blog ?

In this blog, we will see how to use the most used Modbus functions and find examples of using the Mobus RTU and Modbus TCP protocols in different programming languages with an Industrial shields Raspberry PLC.


Requirements


Hardware

+ M-DUINO 21+ (Slave)

+ Raspberry PLC 21+ (Master)


Software

+ M-DUINO 21+


+ Raspberry PLC 21+


  • Modpoll
    • To download the program, we can do it with: wget https://www.modbusdriver.com/downloads/modpoll.tgz
    • Then we must unzip it: tar xzf modpoll.tgz
    • And we can run the executable that is inside the folder that we just unzipped or add it to the $PATH in this way:
    • We open the .bashrc file: nano ~/.bashrc
    • We add the following line, at the end of the file: export PATH=$PWD/modpoll/armv6-rpi-linux-gnueabihf:$PATH
    • We save and exit with Ctrl + S (save) and Ctrl + X (exit) and we execute:  source ~/.bashrc
    • At this point, we will have our Modbus Master Tester ready to use.


  • Python
    • Library PyModbus:  pip install pymodbus


  • Library for C++ an C
    • libmodbus: sudo apt install libmodbus-dev



Modbus functions used in this blog


READ

WRITE

FC1: Read Coil Status (Read 5 Coils or Digital Outputs)

FC2: Read Input Status (Read 7 Digital Inputs)

FC3: Read Holding Registers (Read 3 Registers or Analog Outputs)

FC4: Read Input Registers (Read 6 Analog Inputs)

FC5: Write Single Coil (Write Digital value to a Digital Output)

FC6: Write Single Register (Write Digital values to multiple Digital Output)

FC15: Write Multiple (Write Analog value to an Analog Output)

FC16: Write Multiple Registers (Write Analog values to multiple Analog Output)



INDEX CODES


NODE-RED


BASH + MODPOLL


PYTHON


C++


C


MODBUS RTU
MODBUS TCP
MODBUS RTU
MODBUS TCP
MODBUS RTU
MODBUS TCP
MODBUS RTU
MODBUS TCP
MODBUS RTU
MODBUS TCP


Concepts of each protocol

For these examples an M-Duino 21+ has been used as SLAVE (with the example codes provided by the Industrial Shields Modbus library, for both RTU SLAVE and TCP SLAVE) and a Raspberry PLC 21+ as MASTER, that is, the master sends the commands to the slave and it responds with the required actions or data.


Modbus RTU

We have used the Modbus RTU protocol over the RS485 connection interface, which means using two cables connected to pins A+ and B- of both devices.

For these examples we have used /dev/ttySC0 as the output port of the Raspberry PLC. The slave address is 31, and we have configured the connection with a baudrate of 38400, Databit with 8 bit for data, with even parity and 1 stop bit.


These data are very important for the use of this protocol, since they are what we have defined in the examples of the MODBUS library and if they are different it will not work with the examples made


Modbus TCP

We have used the TCP protocol over the ETHERNET connection interface, which means using the Ethernet connectors of both devices.

In this case we only have to take into account the IP of the Slave in this case 10.10.10.4


Source code

NODE-RED

After node-red-start, copy and import this JSON code: 


Something like this is going to be imported:

Then display and with the insert buttons you will be able to test this protocol.

BASH + MODPOLL

FC1: Read Coil Status: 

modpoll -m rtu -b 38400 -a 31 -d 8 -p even -s 1 -c 5 -t 0 /dev/ttySC0

FC2: Read Input Status:

modpoll -m rtu -b 38400 -a 31 -d 8 -p even -s 1 -c 7 -t 1 /dev/ttySC0

FC3: Read Holding Registers:

modpoll -m rtu -b 38400 -a 31 -d 8 -p even -s 1 -c 3 -t 4 /dev/ttySC0

FC4: Read Input Registers:

modpoll -m rtu -b 38400 -a 31 -d 8 -p even -s 1 -c 6 -t 3 /dev/ttySC0

FC5: Write Single Coil:

modpoll -m rtu -b 38400 -a 31 -r 6 -c 1 -p even -t 0 /dev/ttySC0 1
modpoll -m rtu -b 38400 -a 31 -r 6 -c 1 -p even -t 0 /dev/ttySC0 0

FC6: Write Single Register:

modpoll -m rtu -b 38400 -a 31 -r 3 -c 1 -p even -t 4 /dev/ttySC0 1000
modpoll -m rtu -b 38400 -a 31 -r 3 -c 1 -p even -t 4 /dev/ttySC0 200
modpoll -m rtu -b 38400 -a 31 -r 3 -c 1 -p even -t 4 /dev/ttySC0 0

FC15: Write Multiple:

modpoll -m rtu -b 38400 -a 31 -p even -t 0 /dev/ttySC0 1 1 1 1 1
modpoll -m rtu -b 38400 -a 31 -p even -t 0 /dev/ttySC0 0 0 0 0 0

FC16: Write Multiple Registers:

modpoll -m rtu -b 38400 -a 31 -p even -t 4 /dev/ttySC0 255 500 300
modpoll -m rtu -b 38400 -a 31 -p even -t 4 /dev/ttySC0 0 0 0


PYTHON

Code:
from pymodbus.client import ModbusSerialClient


# Client

serial_port = '/dev/ttySC0'

baud_rate = 38400

unit_id = 31


# FC1: Read Coil Status

def read_coil(client, address, quantity):

    result = client.read_coils(address, quantity, unit_id)


    if not result.isError():

        print(f"Successfully FC1 read coils: %s" % result.bits)

    else:

        print(f"Failed FC1 to read coils from address {address}")



# FC2: Read Input Status

def read_input_status(client, address, quantity):

    result = client.read_discrete_inputs(address, quantity, unit_id)


    if not result.isError():

        print(f"Successfully FC2 read: %s" % result.bits)

    else:

        print(f"Failed FC2 to read from address {address}")



# FC3: Read Holding Registers

def read_holding_register(client, address, quantity):

    result = client.read_holding_registers(address, quantity, unit_id)


    if not result.isError():

        print(f"Successfully FC3 read: %s" % result.registers)

    else:

        print(f"Failed FC3 to read from address {address}")



# FC4: Read Input Registers

def read_input_register(client, address, quantity):

    result = client.read_input_registers(address, quantity, unit_id)


    if not result.isError():

        print(f"Successfully FC4 read: %s" % result.registers)

    else:

        print(f"Failed FC4 to read from address {address}")



# FC5: Write Single Coil

def write_coil(client, address, value):


    result = client.write_coil(address, value, unit_id)


    if not result.isError():

        print(f"Successfully FC5 wrote value {value} to coil address {address}")

    else:

        print(f"Failed FC5 to write value to coil address {address}")



# FC6: Write Single Register

def write_register(client, address, value):


    result = client.write_register(address, value, unit_id)


    if not result.isError():

        print(f"Successfully FC6 wrote value {value} to coil address {address}")

    else:

        print(f"Failed FC6 to write value to coil address {address}")


# FC15: Write Multiple

def write_multiple_coils(client, address, value):


    result = client.write_coils(address, value, unit_id)


    if not result.isError():

        print(f"Successfully FC15 wrote value {value} to coil address {address}")

    else:

        print(f"Failed FC15 to write value to coil address {address}")



# FC16: Write Multiple Registers

def write_multiple_registers(client, address, value):


    result = client.write_registers(address, value, unit_id)


    if not result.isError():

        print(f"Successfully FC16 wrote value {value} to coil address {address}")

    else:

        print(f"Failed FC16 to write value to coil address {address}")


client = ModbusSerialClient(method='rtu', port=serial_port, baudrate=baud_rate, stopbits=1, bytesize=8, parity='E')


if client.connect():

    # FC1: Read Coil Status

    read_coil(client, 0, 5)

    # FC2: Read Input Status

    read_input_status(client, 0, 7)

    # FC3: Read Holding Registers

    read_holding_register(client, 0, 3)

    # FC4: Read Input Registers

    read_input_register(client, 0, 6)

    # FC5: Write Single Coil

    write_coil(client, 5, True)

    write_coil(client, 5, False)

    # FC6: Write Single Register

    write_register(client, 2, 200)

    write_register(client, 2, 0)

    # FC15: Write Multiple

    write_multiple_coils(client, 0, [True,True,True,True,True])

    write_multiple_coils(client, 0, [False,False,False,False,False])

    # FC16: Write Multiple Registers

    write_multiple_registers(client, 0, [255,500,300])

    write_multiple_registers(client, 0, [0,0,0])


    client.close()


else:

    print(f"Failed to connect to Modbus RTU on {serial_port}")


Execution: python3 modbus_example.py

C++

Code:
#include <iostream>

#include <modbus/modbus.h>


// FC1: Read Coil Status

void read_coil(modbus_t *ctx, int address, int quantity) {

    uint8_t *bits = new uint8_t[quantity];

    int rc = modbus_read_bits(ctx, address, quantity, bits);

    if (rc >= 0) {

        std::cout << "Successfully FC1 read coils:";

        for (int i = 0; i < quantity; ++i) {

            std::cout << " " << (int)bits[i];

        }

        std::cout << std::endl;

    } else {

        std::cerr << "Failed FC1 to read coils from address " << address << std::endl;

    }

    delete[] bits;

}


// FC2: Read Input Status

void read_input_status(modbus_t *ctx, int address, int quantity) {

    uint8_t *bits = new uint8_t[quantity];

    int rc = modbus_read_input_bits(ctx, address, quantity, bits);

    if (rc >= 0) {

        std::cout << "Successfully FC2 read:";

        for (int i = 0; i < quantity; ++i) {

            std::cout << " " << (int)bits[i];

        }

        std::cout << std::endl;

    } else {

        std::cerr << "Failed FC2 to read from address " << address << std::endl;

    }

    delete[] bits;

}


// FC3: Read Holding Registers

void read_holding_register(modbus_t *ctx, int address, int quantity) {

    uint16_t *registers = new uint16_t[quantity];

    int rc = modbus_read_registers(ctx, address, quantity, registers);

    if (rc >= 0) {

        std::cout << "Successfully FC3 read:";

        for (int i = 0; i < quantity; ++i) {

            std::cout << " " << registers[i];

        }

        std::cout << std::endl;

    } else {

        std::cerr << "Failed FC3 to read from address " << address << std::endl;

    }

    delete[] registers;

}


// FC4: Read Input Registers

void read_input_register(modbus_t *ctx, int address, int quantity) {

    uint16_t *registers = new uint16_t[quantity];

    int rc = modbus_read_input_registers(ctx, address, quantity, registers);

    if (rc >= 0) {

        std::cout << "Successfully FC4 read:";

        for (int i = 0; i < quantity; ++i) {

            std::cout << " " << registers[i];

        }

        std::cout << std::endl;

    } else {

        std::cerr << "Failed FC4 to read from address " << address << std::endl;

    }

    delete[] registers;

}


// FC5: Write Single Coil

void write_coil(modbus_t *ctx, int address, int value) {

    int rc = modbus_write_bit(ctx, address, value);

    if (rc >= 0) {

        std::cout << "Successfully FC5 wrote value " << value << " to coil address " << address << std::endl;

    } else {

        std::cerr << "Failed FC5 to write value to coil address " << address << std::endl;

    }

}


// FC6: Write Single Register

void write_register(modbus_t *ctx, int address, int value) {

    int rc = modbus_write_register(ctx, address, value);

    if (rc >= 0) {

        std::cout << "Successfully FC6 wrote value " << value << " to coil address " << address << std::endl;

    } else {

        std::cerr << "Failed FC6 to write value to coil address " << address << std::endl;

    }

}


// FC15: Write Multiple

void write_multiple_coils(modbus_t *ctx, int address, int quantity, uint8_t *values) {

    int rc = modbus_write_bits(ctx, address, quantity, values);

    if (rc >= 0) {

        std::cout << "Successfully FC15 wrote values to coil address " << address << std::endl;

    } else {

        std::cerr << "Failed FC15 to write values to coil address " << address << std::endl;

    }

}


// FC16: Write Multiple Registers

void write_multiple_registers(modbus_t *ctx, int address, int quantity, uint16_t *values) {

    int rc = modbus_write_registers(ctx, address, quantity, values);

    if (rc >= 0) {

        std::cout << "Successfully FC16 wrote values to coil address " << address << std::endl;

    } else {

        std::cerr << "Failed FC16 to write values to coil address " << address << std::endl;

    }

}


int main() {

    const char *serial_port = "/dev/ttySC0";

    int baud_rate = 38400;

    int unit_id = 31;


    modbus_t *ctx = modbus_new_rtu(serial_port, baud_rate, 'E', 8, 1);

    if (ctx == NULL) {

        std::cerr << "Failed to create Modbus context." << std::endl;

        return 1;

    }



    modbus_set_slave(ctx, unit_id); // Establecer el identificador del esclavo



    if (modbus_connect(ctx) == -1) {

        std::cerr << "Failed to connect to Modbus RTU on " << serial_port << std::endl;

        modbus_free(ctx);

        return 1;

    }


    // FC1: Read Coil Status

    read_coil(ctx, 0, 5);

    // FC2: Read Input Status

    read_input_status(ctx, 0, 7);

    // FC3: Read Holding Registers

    read_holding_register(ctx, 0, 3);

    // FC4: Read Input Registers

    read_input_register(ctx, 0, 6);

    // FC5: Write Single Coil

    write_coil(ctx, 5, 1);

    write_coil(ctx, 5, 0);

    // FC6: Write Single Register

    write_register(ctx, 2, 200);

    write_register(ctx, 2, 0);

    // FC15: Write Multiple

    uint8_t multiple_coils[] = {1, 1, 1, 1, 1};

    write_multiple_coils(ctx, 0, 5, multiple_coils);

    uint8_t multiple_coils_off[] = {0, 0, 0, 0, 0};

    write_multiple_coils(ctx, 0, 5, multiple_coils_off);

    // FC16: Write Multiple Registers

    uint16_t multiple_registers[] = {255, 500, 300};

    write_multiple_registers(ctx, 0, 3, multiple_registers);

    uint16_t multiple_registers_off[] = {0, 0, 0};

    write_multiple_registers(ctx, 0, 3, multiple_registers_off);


    modbus_close(ctx);

    modbus_free(ctx);


    return 0;

}


Compilation: g++ -o modbus_example modbus_example.cpp -lmodbus
Execution: ./modbus_example

C

Code:

#include <stdio.h>

#include <stdlib.h>

#include <modbus/modbus.h>

#include <errno.h>


#define SERIAL_PORT "/dev/ttySC0"

#define BAUD_RATE 38400

#define UNIT_ID 31


void read_coil(modbus_t *ctx, int address, int quantity) {

    uint8_t tab_rq_bits[quantity];

    int rc;


    rc = modbus_read_bits(ctx, address, quantity, tab_rq_bits);

    if (rc != -1) {

        printf("Successfully FC1 read coils: ");

        for (int i = 0; i < quantity; i++) {

            printf("%d ", tab_rq_bits[i]);

        }

        printf("\n");

    } else {

        printf("Failed FC1 to read coils from address %d\n", address);

    }

}


void read_input_status(modbus_t *ctx, int address, int quantity) {

    uint8_t tab_rq_bits[quantity];

    int rc;


    rc = modbus_read_input_bits(ctx, address, quantity, tab_rq_bits);

    if (rc != -1) {

        printf("Successfully FC2 read: ");

        for (int i = 0; i < quantity; i++) {

            printf("%d ", tab_rq_bits[i]);

        }

        printf("\n");

    } else {

        printf("Failed FC2 to read from address %d\n", address);

    }

}


void read_holding_register(modbus_t *ctx, int address, int quantity) {

    uint16_t tab_reg[quantity];

    int rc;


    rc = modbus_read_registers(ctx, address, quantity, tab_reg);

    if (rc != -1) {

        printf("Successfully FC3 read: ");

        for (int i = 0; i < quantity; i++) {

            printf("%d ", tab_reg[i]);

        }

        printf("\n");

    } else {

        printf("Failed FC3 to read from address %d\n", address);

    }

}


void read_input_register(modbus_t *ctx, int address, int quantity) {

    uint16_t tab_reg[quantity];

    int rc;


    rc = modbus_read_input_registers(ctx, address, quantity, tab_reg);

    if (rc != -1) {

        printf("Successfully FC4 read: ");

        for (int i = 0; i < quantity; i++) {

            printf("%d ", tab_reg[i]);

        }

        printf("\n");

    } else {

        printf("Failed FC4 to read from address %d\n", address);

    }

}


void write_coil(modbus_t *ctx, int address, int value) {

    int rc;


    rc = modbus_write_bit(ctx, address, value);

    if (rc != -1) {

        printf("Successfully FC5 wrote value %d to coil address %d\n", value, address);

    } else {

        printf("Failed FC5 to write value to coil address %d\n", address);

    }

}


void write_register(modbus_t *ctx, int address, int value) {

    int rc;


    rc = modbus_write_register(ctx, address, value);

    if (rc != -1) {

        printf("Successfully FC6 wrote value %d to coil address %d\n", value, address);

    } else {

        printf("Failed FC6 to write value to coil address %d\n", address);

    }

}


void write_multiple_coils(modbus_t *ctx, int address, int quantity, uint8_t *values) {

    int rc;


    rc = modbus_write_bits(ctx, address, quantity, values);

    if (rc != -1) {

        printf("Successfully FC15 wrote values to coil address %d\n", address);

    } else {

        printf("Failed FC15 to write values to coil address %d\n", address);

    }

}


void write_multiple_registers(modbus_t *ctx, int address, int quantity, uint16_t *values) {

    int rc;


    rc = modbus_write_registers(ctx, address, quantity, values);

    if (rc != -1) {

        printf("Successfully FC16 wrote values to coil address %d\n", address);

    } else {

        printf("Failed FC16 to write values to coil address %d\n", address);

    }

}


int main() {

    modbus_t *ctx;

    int rc;


    ctx = modbus_new_rtu(SERIAL_PORT, BAUD_RATE, 'E', 8, 1);

    if (ctx == NULL) {

        fprintf(stderr, "Unable to create the libmodbus context\n");

        return 1;

    }


    modbus_set_slave(ctx, UNIT_ID);


    rc = modbus_connect(ctx);

    if (rc == -1) {

        fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));

        modbus_free(ctx);

        return 1;

    }


    // FC1: Read Coil Status

    read_coil(ctx, 0, 5);

    // FC2: Read Input Status

    read_input_status(ctx, 0, 7);

    // FC3: Read Holding Registers

    read_holding_register(ctx, 0, 3);

    // FC4: Read Input Registers

    read_input_register(ctx, 0, 6);

    // FC5: Write Single Coil

    write_coil(ctx, 5, 1);

    write_coil(ctx, 5, 0);

    // FC6: Write Single Register

    write_register(ctx, 2, 200);

    write_register(ctx, 2, 0);

    // FC15: Write Multiple

    uint8_t coil_values[] = {1, 1, 1, 1, 1};

    write_multiple_coils(ctx, 0, 5, coil_values);

    uint8_t coil_values_off[] = {0, 0, 0, 0, 0};

    write_multiple_coils(ctx, 0, 5, coil_values_off);

    // FC16: Write Multiple Registers

    uint16_t reg_values[] = {255, 500, 300};

    write_multiple_registers(ctx, 0, 3, reg_values);

    uint16_t reg_values_off[] = {0, 0, 0};

    write_multiple_registers(ctx, 0, 3, reg_values_off);


    modbus_close(ctx);

    modbus_free(ctx);


    return 0;

}


Compilation: gcc -o modbus_example modbus_example.c -lmodbus
Execution: ./modbus_example

NODE-RED

After node-red-start, copy and import this JSON code: 


Something like this is going to be imported:


Then display and with the insert buttons you will be able to test this protocol.

BASH + MODPOLL

FC1: Read Coil Status: 

modpoll -m tcp -c 5 -t 0 10.10.10.4

FC2: Read Input Status:

modpoll -m tcp -c 7 -t 1 10.10.10.4

FC3: Read Holding Registers:

modpoll -c 3 -t 4 10.10.10.4

FC4: Read Input Registers:

modpoll -c 6 -t 3 10.10.10.4

FC5: Write Single Coil:

modpoll -t 0 10.10.10.4 1
modpoll -t 0 10.10.10.4 0

FC6: Write Single Register:

modpoll -t 4 10.10.10.4 1000
modpoll -t 4 10.10.10.4 200
modpoll -t 4 10.10.10.4 0

FC15: Write Multiple:

modpoll -t 0 10.10.10.4 1 1 1 1 1
modpoll -t 0 10.10.10.4 0 0 0 0 0

FC16: Write Multiple Registers:

modpoll -t 4 10.10.10.4 255 500 300
modpoll -t 4 10.10.10.4 0 0 0


PYTHON

Code:

from pymodbus.client import ModbusTcpClient


# Client


tcp_host = '10.10.10.4'

tcp_port = 502


# FC1: Read Coil Status

def read_coil(client, address, quantity):

    result = client.read_coils(address, quantity)


    if not result.isError():

        print(f"Successfully FC1 read coils: %s" % result.bits)

    else:

        print(f"Failed FC1 to read coils from address {address}")



# FC2: Read Input Status

def read_input_status(client, address, quantity):

    result = client.read_discrete_inputs(address, quantity)


    if not result.isError():

        print(f"Successfully FC2 read: %s" % result.bits)

    else:

        print(f"Failed FC2 to read from address {address}")



# FC3: Read Holding Registers

def read_holding_register(client, address, quantity):

    result = client.read_holding_registers(address, quantity)


    if not result.isError():

        print(f"Successfully FC3 read: %s" % result.registers)

    else:

        print(f"Failed FC3 to read from address {address}")



# FC4: Read Input Registers

def read_input_register(client, address, quantity):

    result = client.read_input_registers(address, quantity)


    if not result.isError():

        print(f"Successfully FC4 read: %s" % result.registers)

    else:

        print(f"Failed FC4 to read from address {address}")



# FC5: Write Single Coil

def write_coil(client, address, value):


    result = client.write_coil(address, value)


    if not result.isError():

        print(f"Successfully FC5 wrote value {value} to coil address {address}")

    else:

        print(f"Failed FC5 to write value to coil address {address}")



# FC6: Write Single Register

def write_register(client, address, value):


    result = client.write_register(address, value)


    if not result.isError():

        print(f"Successfully FC6 wrote value {value} to coil address {address}")

    else:

        print(f"Failed FC6 to write value to coil address {address}")


# FC15: Write Multiple

def write_multiple_coils(client, address, value):


    result = client.write_coils(address, value)


    if not result.isError():

        print(f"Successfully FC15 wrote value {value} to coil address {address}")

    else:

        print(f"Failed FC15 to write value to coil address {address}")



# FC16: Write Multiple Registers

def write_multiple_registers(client, address, value):


    result = client.write_registers(address, value)


    if not result.isError():

        print(f"Successfully FC16 wrote value {value} to coil address {address}")

    else:

        print(f"Failed FC16 to write value to coil address {address}")



client = ModbusTcpClient(host=tcp_host, port=tcp_port)


if client.connect():

    # FC1: Read Coil Status

    read_coil(client, 0, 5)

    # FC2: Read Input Status

    read_input_status(client, 0, 7)

    # FC3: Read Holding Registers

    read_holding_register(client, 0, 3)

    # FC4: Read Input Registers

    read_input_register(client, 0, 6)

    # FC5: Write Single Coil

    write_coil(client, 5, True)

    write_coil(client, 5, False)

    # FC6: Write Single Register

    write_register(client, 2, 200)

    write_register(client, 2, 0)

    # FC15: Write Multiple

    write_multiple_coils(client, 0, [True,True,True,True,True])

    write_multiple_coils(client, 0, [False,False,False,False,False])

    # FC16: Write Multiple Registers

    write_multiple_registers(client, 0, [255,500,300])

    write_multiple_registers(client, 0, [0,0,0])


    client.close()


else:

    print(f"Failed to connect to Modbus TCP on {tcp_host}")


Execution: python exemple_modbus.py

C++

Code:

#include <iostream>

#include <modbus/modbus.h>


// Modbus context

modbus_t *ctx;


// TCP connection parameters

const char *tcp_host = "10.10.10.4";

const int tcp_port = 502;


// Function to read coil status

void read_coil(int address, int quantity) {

    uint8_t tab_coils[quantity];


    if (modbus_read_bits(ctx, address, quantity, tab_coils) == quantity) {

        std::cout << "Successfully FC1 read coils: ";

        for (int i = 0; i < quantity; ++i) {

            std::cout << static_cast<int>(tab_coils[i]) << " ";

        }

        std::cout << std::endl;

    } else {

        std::cerr << "Failed FC1 to read coils from address " << address << std::endl;

    }

}


// Function to read input status

void read_input_status(int address, int quantity) {

    uint8_t tab_input[quantity];


    if (modbus_read_input_bits(ctx, address, quantity, tab_input) == quantity) {

        std::cout << "Successfully FC2 read: ";

        for (int i = 0; i < quantity; ++i) {

            std::cout << static_cast<int>(tab_input[i]) << " ";

        }

        std::cout << std::endl;

    } else {

        std::cerr << "Failed FC2 to read from address " << address << std::endl;

    }

}


// Function to read holding registers

void read_holding_register(int address, int quantity) {

    uint16_t tab_registers[quantity];


    if (modbus_read_registers(ctx, address, quantity, tab_registers) == quantity) {

        std::cout << "Successfully FC3 read: ";

        for (int i = 0; i < quantity; ++i) {

            std::cout << tab_registers[i] << " ";

        }

        std::cout << std::endl;

    } else {

        std::cerr << "Failed FC3 to read from address " << address << std::endl;

    }

}


// Function to read input registers

void read_input_register(int address, int quantity) {

    uint16_t tab_input_registers[quantity];


    if (modbus_read_input_registers(ctx, address, quantity, tab_input_registers) == quantity) {

        std::cout << "Successfully FC4 read: ";

        for (int i = 0; i < quantity; ++i) {

            std::cout << tab_input_registers[i] << " ";

        }

        std::cout << std::endl;

    } else {

        std::cerr << "Failed FC4 to read from address " << address << std::endl;

    }

}


// Function to write single coil

void write_coil(int address, int value) {

    if (modbus_write_bit(ctx, address, value) != -1) {

        std::cout << "Successfully FC5 wrote value " << value << " to coil address " << address << std::endl;

    } else {

        std::cerr << "Failed FC5 to write value to coil address " << address << std::endl;

    }

}


// Function to write single register

void write_register(int address, int value) {

    if (modbus_write_register(ctx, address, value) != -1) {

        std::cout << "Successfully FC6 wrote value " << value << " to coil address " << address << std::endl;

    } else {

        std::cerr << "Failed FC6 to write value to coil address " << address << std::endl;

    }

}


// Function to write multiple coils

void write_multiple_coils(int address, int quantity, uint8_t *value) {

    if (modbus_write_bits(ctx, address, quantity, value) != -1) {

        std::cout << "Successfully FC15 wrote value to coil address " << address << std::endl;

    } else {

        std::cerr << "Failed FC15 to write value to coil address " << address << std::endl;

    }

}


// Function to write multiple registers

void write_multiple_registers(int address, int quantity, uint16_t *value) {

    if (modbus_write_registers(ctx, address, quantity, value) != -1) {

        std::cout << "Successfully FC16 wrote value to coil address " << address << std::endl;

    } else {

        std::cerr << "Failed FC16 to write value to coil address " << address << std::endl;

    }

}


int main() {

    // Create a Modbus context

    ctx = modbus_new_tcp(tcp_host, tcp_port);

    if (ctx == nullptr) {

        std::cerr << "Failed to create the Modbus context" << std::endl;

        return 1;

    }


    // Connect to the Modbus server

    if (modbus_connect(ctx) == -1) {

        std::cerr << "Failed to connect to Modbus TCP on " << tcp_host << std::endl;

        modbus_free(ctx);

        return 1;

    }


    // Perform Modbus operations

    read_coil(0, 5);

    read_input_status(0, 7);

    read_holding_register(0, 3);

    read_input_register(0, 6);

    write_coil(5, 1);

    write_coil(5, 0);

    write_register(2, 200);

    write_register(2, 0);

    uint8_t value_coils[] = {1, 1, 1, 1, 1};

    write_multiple_coils(0, 5, value_coils);

    uint16_t value_registers[] = {255, 500, 300};

    write_multiple_registers(0, 3, value_registers);


    // Close the Modbus connection and free the context

    modbus_close(ctx);

    modbus_free(ctx);


    return 0;

}


Compilation: g++ -o modbus_example modbus_example.cpp -lmodbus
Execution: ./modbus_example

C

Code:

#include <stdio.h>

#include <stdlib.h>

#include <modbus/modbus.h>

#include <errno.h>


#define SERVER_ID 1

#define ADDR_COILS 0

#define ADDR_DISCRETE_INPUTS 0

#define ADDR_HOLDING_REGISTERS 0

#define ADDR_INPUT_REGISTERS 0


int main() {

    modbus_t *ctx;

    uint16_t tab_reg[32];

    int rc;


    ctx = modbus_new_tcp("10.10.10.4", 502);

    if (ctx == NULL) {

        fprintf(stderr, "Unable to allocate libmodbus context\n");

        return -1;

    }


    if (modbus_connect(ctx) == -1) {

        fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));

        modbus_free(ctx);

        return -1;

    }


    // FC1: Read Coil Status

    rc = modbus_read_bits(ctx, ADDR_COILS, 5, tab_reg);

    if (rc >= 0) {

        printf("Successfully FC1 read coils: ");

        for (int i = 0; i < 5; i++)

            printf("%d ", tab_reg[i]);

        printf("\n");

    } else {

        fprintf(stderr, "Failed FC1 to read coils: %s\n", modbus_strerror(errno));

    }


    // FC2: Read Input Status

    rc = modbus_read_input_bits(ctx, ADDR_DISCRETE_INPUTS, 7, tab_reg);

    if (rc >= 0) {

        printf("Successfully FC2 read: ");

        for (int i = 0; i < 7; i++)

            printf("%d ", tab_reg[i]);

        printf("\n");

    } else {

        fprintf(stderr, "Failed FC2 to read: %s\n", modbus_strerror(errno));

    }


    // FC3: Read Holding Registers

    rc = modbus_read_registers(ctx, ADDR_HOLDING_REGISTERS, 3, tab_reg);

    if (rc >= 0) {

        printf("Successfully FC3 read: ");

        for (int i = 0; i < 3; i++)

            printf("%d ", tab_reg[i]);

        printf("\n");

    } else {

        fprintf(stderr, "Failed FC3 to read: %s\n", modbus_strerror(errno));

    }


    // FC4: Read Input Registers

    rc = modbus_read_input_registers(ctx, ADDR_INPUT_REGISTERS, 6, tab_reg);

    if (rc >= 0) {

        printf("Successfully FC4 read: ");

        for (int i = 0; i < 6; i++)

            printf("%d ", tab_reg[i]);

        printf("\n");

    } else {

        fprintf(stderr, "Failed FC4 to read: %s\n", modbus_strerror(errno));

    }


    // FC5: Write Single Coil

    rc = modbus_write_bit(ctx, 5, 1);

    if (rc >= 0) {

        printf("Successfully FC5 wrote value 1 to coil address 5\n");

    } else {

        fprintf(stderr, "Failed FC5 to write: %s\n", modbus_strerror(errno));

    }


    rc = modbus_write_bit(ctx, 5, 0);

    if (rc >= 0) {

        printf("Successfully FC5 wrote value 0 to coil address 5\n");

    } else {

        fprintf(stderr, "Failed FC5 to write: %s\n", modbus_strerror(errno));

    }


    // FC6: Write Single Register

    rc = modbus_write_register(ctx, 2, 200);

    if (rc >= 0) {

        printf("Successfully FC6 wrote value 200 to register address 2\n");

    } else {

        fprintf(stderr, "Failed FC6 to write: %s\n", modbus_strerror(errno));

    }


    rc = modbus_write_register(ctx, 2, 0);

    if (rc >= 0) {

        printf("Successfully FC6 wrote value 0 to register address 2\n");

    } else {

        fprintf(stderr, "Failed FC6 to write: %s\n", modbus_strerror(errno));

    }


    // FC15: Write Multiple

    uint8_t tab_bits[5] = {1, 1, 1, 1, 1};

    rc = modbus_write_bits(ctx, 0, 5, tab_bits);

    if (rc >= 0) {

        printf("Successfully FC15 wrote value 1 to coil address 0-4\n");

    } else {

        fprintf(stderr, "Failed FC15 to write: %s\n", modbus_strerror(errno));

    }


    uint8_t tab_bits_off[5] = {0, 0, 0, 0, 0};

    rc = modbus_write_bits(ctx, 0, 5, tab_bits_off);

    if (rc >= 0) {

        printf("Successfully FC15 wrote value 0 to coil address 0-4\n");

    } else {

        fprintf(stderr, "Failed FC15 to write: %s\n", modbus_strerror(errno));

    }


    // FC16: Write Multiple Registers

    uint16_t tab_registers[3] = {255, 500, 300};

    rc = modbus_write_registers(ctx, 0, 3, tab_registers);

    if (rc >= 0) {

        printf("Successfully FC16 wrote values to register address 0-2\n");

    } else {

        fprintf(stderr, "Failed FC16 to write: %s\n", modbus_strerror(errno));

    }


    uint16_t tab_registers_off[3] = {0, 0, 0};

    rc = modbus_write_registers(ctx, 0, 3, tab_registers_off);

    if (rc >= 0) {

        printf("Successfully FC16 wrote values 0 to register address 0-2\n");

    } else {

        fprintf(stderr, "Failed FC16 to write: %s\n", modbus_strerror(errno));

    }


    modbus_close(ctx);

    modbus_free(ctx);


    return 0;

}

Compilation: gcc -o modbus_example modbus_example.c -lmodbus
Execution: ./modbus_example


​Search in our Blog

MODBUS with Industrial Shields Raspberry PLC
Boot & Work Corp. S.L., DAVID CORONADO TRAVASET April 29, 2024
Share this post

Looking for your ideal Programmable Logic Controller?

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

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


Industrial PLC comparison >>>