modbus_read_register - 错误连接超时

问题描述 投票:0回答:1

我们使用 libmodbus 库从支持 Modbus over RTU 的电能表 EM6400 读取寄存器值。我们面临以下两个问题。

1) 我们面临

modbus_read_registers
API 的问题,该 API 返回 -1,错误消息为:

错误连接超时:选择。

调试库后,我们发现此问题是由于响应消息中请求字节的回显造成的。

read()
_modbus_rtu_recv
中的 API 调用首先返回请求字节,然后返回响应字节。结果,
length_to_read
中的
compute_data_length_after_meta()
是根据请求字节而不是响应字节(包含读取的字节数)计算的,并且出现连接超时问题。 我们尝试使用 3.0.6 和 3.1.2 libmodbus 版本,但两个版本都出现相同的问题。

2)

modbus_rtu_set_serial_mode
(ctx, MODBUS_RTU_RS485) 返回“BAD 文件描述符”。

请确认是否有API调用缺失或参数设置不正确。

我们读取寄存器值的示例代码如下。

int main()
{

    modbus_t *ctx;
    uint16_t tab_reg[2] = {0,0};
    float avgVLL = -1;;
    int res = 0;
    int rc;
    int i;
    struct timeval response_timeout;
    uint32_t tv_sec = 0;
    uint32_t tv_usec = 0;
    response_timeout.tv_sec = 5;
    response_timeout.tv_usec = 0;

    ctx = modbus_new_rtu("/dev/ttyUSB0", 19200, 'E', 8, 1);
    if (NULL == ctx)
    {
                    printf("Unable to create libmodbus context\n");
                    res = 1;
    }
    else
    {
        printf("created libmodbus context\n");
        modbus_set_debug(ctx, TRUE);
        //modbus_set_error_recovery(ctx, MODBUS_ERROR_RECOVERY_LINK |MODBUS_ERROR_RECOVERY_PROTOCOL);
        rc = modbus_set_slave(ctx, 1);
        printf("modbus_set_slave return: %d\n",rc);
        if (rc != 0)
        {
                        printf("modbus_set_slave: %s \n",modbus_strerror(errno));
        }

        /* Commented - Giving 'Bad File Descriptor' issue
        rc = modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485);
        printf("modbus_rtu_set_serial_mode: %d \n",rc);

        if (rc != 0)
        {
                        printf("modbus_rtu_set_serial_mode: %s \n",modbus_strerror(errno));
        }
        */

        // This code is for version 3.0.6
        modbus_get_response_timeout(ctx, &response_timeout); 
        printf("Default response timeout:%ld sec %ld usec \n", response_timeout.tv_sec, response_timeout.tv_usec );

        response_timeout.tv_sec = 60;
        response_timeout.tv_usec = 0;

        modbus_set_response_timeout(ctx, &response_timeout); 
        modbus_get_response_timeout(ctx, &response_timeout); 
        printf("Set response timeout:%ld sec %ld usec \n", response_timeout.tv_sec, response_timeout.tv_usec );


        /* This code is for version 3.1.2
        modbus_get_response_timeout(ctx, &tv_sec, &tv_usec); 
        printf("Default response timeout:%d sec %d usec \n",tv_sec,tv_usec );

        tv_sec = 60;
        tv_usec = 0;

        modbus_set_response_timeout(ctx, tv_sec,tv_usec); 
        modbus_get_response_timeout(ctx, &tv_sec, &tv_usec); 
        printf("Set response timeout:%d sec %d usec \n",tv_sec,tv_usec );
        */

        rc = modbus_connect(ctx);
        printf("modbus_connect: %d \n",rc);

        if (rc == -1) {
                        printf("Connection failed: %s\n", modbus_strerror(errno));
            res = 1;
        }

        rc = modbus_read_registers(ctx, 3908, 2, tab_reg);
        printf("modbus_read_registers: %d \n",rc);

        if (rc == -1) {
                        printf("Read registers failed:  %s\n", modbus_strerror(errno));
            res = 1;
        }

        for (i=0; i < 2; i++) {
            printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
        }

        avgVLL = modbus_get_float(tab_reg);

        printf("Average Line to Line Voltage = %f\n", avgVLL);

        modbus_close(ctx);
        modbus_free(ctx);
    }
}

该样本的输出如下:

created libmodbus context
modbus_set_slave return: 0
modbus_rtu_set_serial_mode: -1 
modbus_rtu_set_serial_mode: Bad file descriptor 
Default response timeout:0 sec 500000 usec 
Set response timeout:60 sec 0 usec 
Opening /dev/ttyUSB0 at 19200 bauds (E, 8, 1)
modbus_connect: 0 
[01][03][0F][44][00][02][87][0A]
Waiting for a confirmation...
ERROR Connection timed out: select
<01><03><0F><44><00><02><87><0A><01><03><04><C4><5F><43><D4><C6><7E>modbus_read_registers: -1 
Read registers failed:  Connection timed out
reg[0]=0 (0x0)
reg[1]=0 (0x0)
Average Line to Line Voltage = 0.000000
modbus
1个回答
0
投票

问题 1) 可能是硬件问题,在 RS-485 适配器中启用了“本地回显”。本地回显有时用于确认总线上数据字节的发送。您需要禁用它,或者找到另一个 RS-485 适配器。

我已经在我的 MinimalModbus Python 库的文档中写到了这一点:Local Echo

它列出了在 RS-485 适配器中禁用本地回显的几种常见方法。

© www.soinside.com 2019 - 2024. All rights reserved.