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+
- Industrial Shields RPI PLC Image (How to install)
- NODE-RED (Installed with image)
- Modbus Pack (Information)
- 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
MODBUS with Industrial Shields Raspberry PLC