Ir al contenido

MODBUS con el Raspberry PLC de Industrial Shields

Ejemplos de uso del protocolo Modbus RTU y TCP con el Raspberry PLC como MAESTRO con diferentes lenguajes de programación
29 de abril de 2024 por
MODBUS con el Raspberry PLC de Industrial Shields
Boot & Work Corp. S.L, DAVID CORONADO TRAVASET

¿Qué encontraremos en este blog?

En este blog veremos cómo usar las funciones Modbus más utilizadas y encontraremos ejemplos de uso de los protocolos Modbus RTU y Modbus TCP en diferentes lenguajes de programación con un Raspberry PLC de Industrial Shields.


Requisitos


Hardware

- M-DUINO 21+ (Esclavo)

- Raspberry PLC 21+ (Maestro)


Software

+ M-DUINO 21+


+ Raspberry PLC 21+


  • Modpoll
    • Para descargar el programa, podemos hacerlo con: wget https://www.modbusdriver.com/downloads/modpoll.tgz
    • Después debemos descomprimirlo: tar xzf modpoll.tgz
    • Y podemos ejecutar el ejecutable que hay dentro de la carpeta que acabamos de descomprimir o añadirlo al $PATH de esta manera:
    • Abrimos el archivo .bashrc: nano ~/.bashrc
    • Añadimos la siguiente línea al final del archivo: export PATH=$PWD/modpoll/armv6-rpi-linux-gnueabihf:$PATH
    • Guardamos y salimos con Ctrl + S (guardar) y Ctrl + X (salir) y ejecutamos: source ~/.bashrc
    • En este punto, tendremos listo para usar nuestro probador de maestro Modbus.


  • Python
    • Biblioteca PyModbus: pip install pymodbus


  • Biblioteca para C++ y C
    • libmodbus: sudo apt install libmodbus-dev



Funciones Modbus usadas en este blog


LECTURA

ESCRITURA

FC1: Read Coil Status (lectura de 5 bobinas o salidas digitales)

FC2: Read Input Status (lectura de 7 entradas digitales)

FC3: Read Holding Registers (lectura de 3 registros o salidas analógicas)

FC4: Read Input Registers (lectura de 6 entradas analógicas)

FC5: Write Single Coil (escritura de un valor digital en una salida digital)

FC6: Write Single Register (escritura de un valor analógico en una salida analógica)

FC15: Write Multiple (escritura de varios valores digitales en varias salidas digitales)

FC16: Write Multiple Registers (escritura de varios valores analógicos en varias salidas analógicas)



ÍNDICE DE CÓDIGOS


NODE-RED

node red


BASH + MODPOLL

bash


PYTHON

pythyon

C++

ISO C%2B%2B Logo.svg

C

C Logo

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


Conceptos de cada protocolo

En estos ejemplos se ha usado un M-Duino 21+ como ESCLAVO (con los códigos de ejemplo de la biblioteca Modbus de Industrial Shields, tanto para ESCLAVO RTU como para ESCLAVO TCP) y un Raspberry PLC 21+ como MAESTRO, es decir, el maestro envía los comandos al esclavo y este responde con las acciones o los datos solicitados.


Modbus RTU

Hemos usado el protocolo Modbus RTU sobre la interfaz de conexión RS485, lo que significa usar dos cables conectados a los pines A+ y B- de ambos dispositivos.

En estos ejemplos hemos usado /dev/ttySC0 como puerto de salida del Raspberry PLC. La dirección del esclavo es 31 y hemos configurado la conexión con una velocidad de 38400 baudios, 8 bits de datos, paridad par y 1 bit de parada.


Estos datos son muy importantes para el uso de este protocolo, ya que son los que hemos definido en los ejemplos de la biblioteca MODBUS y, si son diferentes, no funcionará con los ejemplos realizados


Modbus TCP

Hemos usado el protocolo TCP sobre la interfaz de conexión ETHERNET, lo que significa usar los conectores Ethernet de ambos dispositivos.

En este caso solo tenemos que tener en cuenta la IP del esclavo, que es 10.10.10.4


Código fuente

NODE-RED

Tras ejecutar node-red-start, copia e importa este código JSON:


Se importará algo como esto:

NODE-RED

Después, despliega el flujo y, con los botones de inserción, podrás probar este protocolo.

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

Código:
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}")


Ejecución: python3 modbus_example.py

C++

Código:
#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;

}


Compilación: g++ -o modbus_example modbus_example.cpp -lmodbus
Ejecución: ./modbus_example

C

Código:

#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;

}


Compilación: gcc -o modbus_example modbus_example.c -lmodbus
Ejecución: ./modbus_example

NODE-RED

Tras ejecutar node-red-start, copia e importa este código JSON: 


Se importará algo como esto:

NODE-RED

Después, despliega el flujo y, con los botones de inserción, podrás probar este protocolo.

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

Código:

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}")


Ejecución: python exemple_modbus.py

C++

Código:

#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;

}


Compilación: g++ -o modbus_example modbus_example.cpp -lmodbus
Ejecución: ./modbus_example

C

Código:

#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;

}

Compilación: gcc -o modbus_example modbus_example.c -lmodbus
Ejecución: ./modbus_example


Buscar en nuestro blog

MODBUS con el Raspberry PLC de Industrial Shields
Boot & Work Corp. S.L, DAVID CORONADO TRAVASET 29 de abril de 2024
Compartir esta publicación
Etiquetas

¿Estás buscando tu Controlador Lógico Programable ideal?

Echa un vistazo a esta comparativa de producto de varios controladores industriales basados en Arduino.

Comparamos entradas, salidas, comunicaciones y otras especificaciones con las de los equipos de otras marcas destacadas.

Comparativa de PLCs