uso de libmodbus

libmodbus es una biblioteca de controladores modbus basada en lenguaje C, que admite sistemas operativos como Linux, , Mac OS X, Win32etc.

Se admiten las siguientes funciones:

  • apoyo Modbus-RTU_
  • apoyo Modbus-TCP_
  • Admite códigos de función comunes (01/02/03/04/05/06/07/0F/10/11/16/17).
  • Admite lectura y escritura de tipo de bobina, lectura y escritura de registro, lectura discreta, etc.
  • Admite dirección de transmisión 0, dirección esclava 1-247.
  • Admite conversión de datos enteros y de punto flotante, endian grande y pequeño y otros modos.

1 Obtener el código fuente

La última versión del sitio web oficial: libmodbus-3.1.7.tar.gz

Dirección de almacén de código abierto: https://github.com/stephane/libmodbus/

2 Genere el archivo de configuración config.h

Ejecute el siguiente comando en la terminal de Linux para completar la descompresión:

sudo tar zxvf libmodbus-3.1.7.tar.gz

La estructura del directorio libmodbus-3.1.7 descomprimido es la siguiente:

.
├── acinclude.m4
├── aclocal.m4
├── AUTHORS
├── build-aux/
├── config.h.in
├── configure*
├── configure.ac
├── COPYING.LESSER
├── doc/
├── libmodbus.pc.in
├── m4/
├── Makefile.am
├── Makefile.in
├── MIGRATION
├── NEWS
├── README.md
├── src/
└── tests/

Ejecute el siguiente comando en la terminal de Linux para generar el archivo de configuración config.h:

./configure

Después de la generación, el indicador es el siguiente:

		libmodbus 3.1.7
        ===============

        prefix:                 /usr/local
        sysconfdir:             ${prefix}/etc
        libdir:                 ${exec_prefix}/lib
        includedir:             ${prefix}/include

        compiler:               gcc
        cflags:                 -g -O2
        ldflags:                

        documentation:          no
        tests:                  yes

3 uso

3.1 Maestro Modbus

3.1.1 Sondeo-Modbus-TCP

Use Modbus Slave para simular el dispositivo esclavo, libmodbus como maestro para leer y escribir el registro de retención esclavo.

(1) Configuración de conexión Modbus Esclavo

Haga clic en Conexión, seleccione Conectar, aparecerá el cuadro de diálogo Configuración de la conexión, seleccione Conexión Modbus TCP/IP, complete la Dirección IP como 192.168.3.100(dirección local de la computadora) y complete el Puerto como 502.

imagen-20220823084931218

(2) Configuración de esclavo esclavo Modbus

Haga clic en Configuración, seleccione Definición de esclavo, complete ID de esclavo como 1, Función como 03 Holding Register(4x), Dirección como 0y Cantidad como 10.

imagen-20220823085256273

(3) rutinas de lectura y escritura poll_wr_regs_demo

/**
 * @file poll_wr_regs_demo.c
 * @author 李云亮 ([email protected])
 * @brief modbus主站读写多个保持寄存器
 * @version 1.0.0
 * @date 2022-08-19
 * 
 * @copyright Copyright (c) 2022
 * 
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "modbus.h"

#define MODBUS_TCP_SERVER_IP    "192.168.3.100"                         // TCP IP地址
#define MODBUS_TCP_SERVER_PORT  502                                     // TCP 端口号

#define REG_ADDR_START          0                                       // 寄存器起始地址
#define REG_ADDR_END            9                                       // 寄存器结束地址
#define REG_NUM                 ((REG_ADDR_END) - (REG_ADDR_START) + 1) // 寄存器个数

int main(int argc, char const *argv[])
{
    
    
    /* code */
    int i = 0;
    int ret = 0;
    modbus_t* ctx = NULL;
    uint16_t* sendBuf = NULL;
    uint16_t* recvBuf = NULL;

    // 1.创建TCP
    ctx = modbus_new_tcp(MODBUS_TCP_SERVER_IP, MODBUS_TCP_SERVER_PORT);
    if (NULL == ctx)
    {
    
    
        printf("Set modbus TCP failed!\n");
        return -1;
    }

    // 2.设置调试模式
    ret = modbus_set_debug(ctx, TRUE);
    if (-1 == ret)
    {
    
    
        printf("Set modbus debug mode failed!\n");
    }

    // 3.连接Server
    ret = modbus_connect(ctx);
    if (-1 == ret)
    {
    
    
        printf("Connect modbus server failed!\n");
        modbus_free(ctx);
        return -1;
    }

    // 4.设置从机地址
    ret = modbus_set_slave(ctx, 1);

    // 5.申请内存
    sendBuf = (uint16_t*)malloc(REG_NUM * (sizeof(uint16_t)));
    if (NULL == sendBuf)
    {
    
    
        printf("modbus sendBuf malloc failed!\n");
        free(sendBuf);
        return -1;
    }
    recvBuf = (uint16_t*)malloc(REG_NUM * (sizeof(uint16_t)));
    if (NULL == recvBuf)
    {
    
    
        printf("modbus recvBuf malloc failed!\n");
        free(recvBuf);
        return -1;
    }
    memset(sendBuf, 0, REG_NUM);
    memset(recvBuf, 0, REG_NUM);
    
    // 6.写入多个保持寄存器
    for (i = 0; i < REG_NUM; i++)
    {
    
    
        sendBuf[i] = i;
    }
    ret = modbus_write_registers(ctx, REG_ADDR_START, REG_NUM, sendBuf);
    if (REG_NUM != ret)
    {
    
    
        printf("modbus write regs failed!\n");
        return -1;
    }
    else
    {
    
    
        // 7.读多个保持寄存器
        ret = modbus_read_registers(ctx, REG_ADDR_START, REG_NUM, recvBuf);
        if (REG_NUM != ret)
        {
    
    
            printf("modbus read regs failed!\n");
            return -1;
        }
        else
        {
    
    
            printf("result data:\n");
            for (i = 0; i < REG_NUM; i++)
            {
    
    
                printf("%d ", recvBuf[i]);
            }
            printf("\n");
        }
    }

    // 8.释放内存
    free(sendBuf);
    free(recvBuf);

    // 9.断开连接
    modbus_close(ctx);
    modbus_free(ctx);

    return 0;
}

(4) Compilar y ejecutar

lyl@ubuntu18:~/Desktop/gitee/libmodbus-demo/libmodbusUse$ make
+ Linking output/demo/poll_wr_regs_demo ...
lyl@ubuntu18:~/Desktop/gitee/libmodbus-demo/libmodbusUse$ ./output/demo/poll_wr_regs_demo 
Connecting to 192.168.3.100:502
[00][01][00][00][00][1B][01][10][00][00][00][0A][14][00][00][00][01][00][02][00][03][00][04][00][05][00][06][00][07][00][08][00][09]
Waiting for a confirmation...
<00><01><00><00><00><06><01><10><00><00><00><0A>
[00][02][00][00][00][06][01][03][00][00][00][0A]
Waiting for a confirmation...
<00><02><00><00><00><17><01><03><14><00><00><00><01><00><02><00><03><00><04><00><05><00><06><00><07><00><08><00><09>
result data:
0 1 2 3 4 5 6 7 8 9 

imagen-20220823090116717

(5) Análisis del marco de datos

  • Análisis de registro de escritura maestra

    # 主站写多个寄存器
    [00][01][00][00][00][1B][01][10][00][00][00][0A][14][00][00][00][01][00][02][00][03][00][04][00][05][00][06][00][07][00][08][00][09]
    
    identificador de comunicación identificador de protocolo Longitud de datos dirección esclava Código de función dirección inicial Número de registros Longitud de datos datos
    00 01 00 00 00 1B 01 0x10(16) 00 00 00 0A(10) 0x14(20) 0-9
    # 从站返回写结果
    <00><01><00><00><00><06><01><10><00><00><00><0A>
    
    identificador de comunicación identificador de protocolo Longitud de datos dirección esclava Código de función dirección inicial Número de registros
    00 01 00 00 00 06 01 0x10(16) 00 00 00 0A(10)
  • Análisis de registro de lectura maestro

    # 主站读多个寄存器
    [00][02][00][00][00][06][01][03][00][00][00][0A]
    
    identificador de comunicación identificador de protocolo Longitud de datos dirección esclava Código de función dirección inicial Número de registros
    00 02 00 00 00 06 01 03 00 00 00 0A(10)
    # 从站返回读结果
    <00><02><00><00><00><17><01><03><14><00><00><00><01><00><02><00><03><00><04><00><05><00><06><00><07><00><08><00><09>
    
    identificador de comunicación identificador de protocolo Longitud de datos dirección esclava Código de función Longitud de datos datos
    00 02 00 00 00 17(23) 01 03 0x14(20) 0-9

3.2 Esclavo Modbus

3.2.1 Esclavo-Modbus-TCP

Utilice Modbus Poll para simular un dispositivo maestro y libmodbus como esclavo.

(1) Configuración de conexión de sondeo Modbus

Haga clic en Conexión, seleccione Conectar, aparecerá el cuadro de diálogo Configuración de la conexión, seleccione Conexión Modbus TCP/IP, complete la Dirección IP como 192.168.3.102(dirección esclava de Ubuntu) y complete el Puerto como 1502.

imagen-20220825155352425

(2) Configuración de host esclavo Modbus

Haga clic en Configuración, seleccione Definición de lectura/escritura, complete ID de esclavo como 1, Función como 03 Holding Register(4x), Dirección como 0y Cantidad como 10.

imagen-20220825155549440

(3) Slave_wr_regs_demo rutinas de lectura y escritura

/**
 * @file slave_wr_regs_demo.c
 * @author 李云亮 ([email protected])
 * @brief modbus从站读写例程
 * @version 1.0.0
 * @date 2022-08-25
 * 
 * @copyright Copyright (c) 2022
 * 
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "modbus.h"

#define MODBUS_SLAVE_TCP_SERVER_IP      "192.168.3.102"
#define MODBUS_SLAVE_TCP_SERVER_PORT    1502
#define MAPPING_SIZE                    10
#define MODBUS_POLL_CONNECT_MAX         1

int main(int argc, char const *argv[])
{
    
    
    /* code */
    int socket = -1;
    modbus_t *ctx;
    modbus_mapping_t *mb_mapping;
    uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH] = {
    
    0};
    int rc = 0;
    int i = 0;

    // 1.创建从机TCP
    ctx = modbus_new_tcp(MODBUS_SLAVE_TCP_SERVER_IP, MODBUS_SLAVE_TCP_SERVER_PORT); //开发板ip自行修改
    if (NULL == ctx)
    {
    
    
        printf("Set modbus TCP failed!\n");
        return -1;
    }

    // 2.设置调试模式
    modbus_set_debug(ctx, TRUE);

    // 3.初始化寄存器
    mb_mapping = modbus_mapping_new(MAPPING_SIZE, MAPPING_SIZE, MAPPING_SIZE, MAPPING_SIZE);
    if (mb_mapping == NULL) {
    
    
        printf("Failed to allocate the mapping!\n");
        modbus_free(ctx);
        return -1;
    }
    for (i = 0; i < MAPPING_SIZE; i++)
    {
    
    
        mb_mapping->tab_registers[i] = i;
    }

    // 4.侦听主站连接
    socket = modbus_tcp_listen(ctx, MODBUS_POLL_CONNECT_MAX);
    if (-1 == socket)
    {
    
    
        printf("Unable to listen TCP!\n");
        modbus_free(ctx);
        return -1;
    }
    
    // 5.创建连接
    modbus_tcp_accept(ctx, &socket);

    while (1)
    {
    
    
        // 6.接收请求
        rc = modbus_receive(ctx, query);

        if (rc > 1) {
    
    
            // 7.发送响应
            modbus_reply(ctx, query, rc, mb_mapping);
            printf("In the loop \n");
        } 
        else 
        {
    
    
            // Connection closed by the client or error
            modbus_mapping_free(mb_mapping);
            modbus_close(ctx);
            modbus_free(ctx);
			modbus_tcp_accept(ctx, &socket);
            break;
        }
    }

    return 0;
}

imagen-20220825155751874

imagen-20220825155729401

Supongo que te gusta

Origin blog.csdn.net/qq_40531408/article/details/126689032
Recomendado
Clasificación