This tutorial demonstrates how to Implement Modbus TCP Master in C to read and write registers on any Modbus TCP Slave. Modbus protocol is a very popular protocol in industrial automation. It is a communication protocol of choice when it comes to integration, data acquisition and inter-device, inter process communication and synchronization because of the many advantages that come with it. The protocol has been adapted industry-wide and many industrial devices now support Modbus generically, so there is usually little to no extra effort required when implementing this protocol.
Embedded hardware that support application development in C can also implement Modbus for various application. This brings with enormous power to Industrial automation since embedded systems are an integral part and are at the heart of Industrial automation systems.
- Modbus Implementation on Embedded devices can be used to read sensor information and making this data available to other control devices through Modbus communication.
- Embedded systems can also be integrated to control remote actuators by receiving control commands from the main control devices via Modbus communication
- Embedded systems can also control subsystems and processes, and synchronize their operations with other devices and processes through Modbus communication
Implementation of Modbus TCP Master in C
This tutorial demonstrates how to implement a Modbus TCP Master in C programming to read input input registers from the slave and also write holding registers on the slave side.
Reading Input Registers
Step 1: Install libmodbus Library
- The Implementation uses the libmodbus library from https://libmodbus.org/ .
- You you must therefore first install the libmodbus Library from https://github.com/stephane/libmodbus.
Step 2 : Import header files
The main header file is the modbus.h that contains all the functions and types for implementing the Modbus TCP Master
#include <stdio.h>
#include <modbus/modbus.h>
#include <errno.h>
#include <unistd.h>
Step 3: declare support variables and reserve memory for Modbus context
modbus_t *ctx; // modbus context
int rc_read = 0 ;
int rc_write = 0 ;
int i;
uint16_t tab_dest[64];
uint16_t tab_src[10] = {1};
Step 4: Create Modbus context
Using the modbus_new_tcp() function, you should create a Modbus context, in this case TCP. The function takes in 2 arguments, that is, the remote slave ip-address and TCP communication port
// creating context
ctx = modbus_new_tcp("192.168.1.104", 502);
Step 5: Establish connection with remote slave
The modbus_connect() function attempts to establish connection with the slave. It takes one argument, the Modbus context that has been created. In case of an error, the errno is set and the error description related to the errno can be got by using the modbus_strerror() function
// try establishing connection
while(modbus_connect(ctx) == -1) {
fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
}
Step 6: Read input registers
To read slave input registers, we use the modbus_read_input_registers() function. The function takes in as its arguments, the context, the start address, the number of registers to read and the destination buffer to store the read data. Please note that the destination buffer must be of type uint_16 since input registers are 16 bits each, and its size must not be less that the number of registers being read.
The function returns a value greater or equal to 0 indicating the number of registers read, other wise it returns -1 indicating that no registers have been read.
// read from input registers
rc_read = modbus_read_input_registers(ctx, 0, 10, tab_dest);
Step 7: Display Fetched data
// print out read data
for (i=0; i < rc; i++) {
printf("reg[%d]=%d (0x%X)\n", i, tab_dest[i], tab_dest[i]);
}
Writing Holding Registers
Steps 1 to 5 remain the same for writing holding registers. Once communication has been established, you should use the modbus_write_registers() function which takes in as its arguments, the context, the start address, the number of registers to write and the source data buffer that contains data to be written to the slave.
The function returns a number equal or greater than 0 indicating the number of registers written, otherwise it returns -1, meaning that no registers have been written
// write to holding registers
rc_write = modbus_write_registers(ctx, 0, 10, tab_src);
You can find the full code at https://github.com/brightersidetech/C_modbus_tcp_master.git