尽管从站 ID 正确,但从所需寄存器检索的数据不正确

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

环境:

  • 上:树莓派4B
  • 操作系统:Ubuntu 22.04.4 Jammy
  • libmodbus版本:3.1.10
  • RS485 Pi 2.0 USB UART
  • Modbus 设备连接到: /dev/ttyUSB0 端口。
  • 从设备ID: 33
  • 寄存器: 30001、30002、30003、30004。
  • 由于有从设备:需要轮询才能读取数据。

说明:

  • 该代码旨在建立与特定Modbus设备的连接并从特定寄存器读取数据。下面是从 Windows 中通过应用程序轮询获取的精确连接示例。 Connection Example
  • 代码的输出是建立连接并读取某些寄存器后收到的调试输出。
  • 然而,得到的不是预期的数据,而是意外的结果(参见下面的输出部分)。 Debug Output

C++代码:

#include <stdio.h>
#include <modbus.h>
#include <cerrno>
#include <iostream>

int main() {

    // The ID of the device being queried
    const int REMOTE_ID = 33;
    modbus_t *ctx;
    uint16_t tab_reg[4];

    // Creating a Modbus connection
    ctx = modbus_new_rtu("/dev/ttyUSB0", 9600, 'O', 8, 1);
    modbus_set_slave(ctx, 33);  // Setting the Slave ID
    modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485);
    modbus_rtu_set_rts(ctx, MODBUS_RTU_RTS_UP);
    modbus_rtu_set_rts_delay(ctx, 3);
    modbus_set_debug(ctx, 1);  // Enabling debugging
    if (ctx == NULL) {
        fprintf(stderr, "Unable to create the libmodbus context\n");
        return -1;
    }

    // Establishing the connection
    if (modbus_connect(ctx) == -1) {
        fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        return -1;
    }
    
    // Reading the registers
    int rc = modbus_read_registers(ctx, 0, 3, tab_reg);
    if (rc == -1) {
        fprintf(stderr, "%s\n", modbus_strerror(errno));
        std::cout << "Reading register error";
        return -1;
    }
    
    // Printing the read data
    for (int i = 0; i < sizeof(tab_reg) / sizeof(tab_reg[0]); i++) {
        printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
    }
    
    // Closing the connection and freeing memory
    modbus_close(ctx);
    modbus_free(ctx);
}

调试输出:

Opening /dev/ttyUSB0 at 9600 bauds (O, 8, 1)
[21][03][00][00][00][03][02][AB]
Sending request using RTS signal
Waiting for a confirmation...
<21><03><06><00><00><00><00><00><21><78><AC>
reg[0]=0 (0x0)
reg[1]=0 (0x0)
reg[2]=33 (0x21)
reg[3]=0 (0x0)

更多信息: 

  • 通常,我们在这里将起始值设置为30001:
    int rc = modbus_read_registers(ctx, 30001, 3, tab_reg);
  • 但是,出现了“无效 CRC”错误。
  • 根据一位 libmodbus 用户的说法:

欢迎来到Modbus的精彩世界。 “30000”仅表示“寄存器”,20000 和 40000 仅表示“输入寄存器”和“线圈”。

有点像“modbus_operation(3000x)”会自动执行“read_registers(x)”,而“modbus_operation(4000x)”会自动执行“read_holding_registers(x)”。

libmodbus 不支持 30000 样式,仅支持“完整”样式。

  • 因此,我从 0 开始,而不是 30001。
c++ serial-port modbus rs485 libmodbus
1个回答
0
投票

您正在使用

modbus_read_registers(ctx, 0, 3, tab_reg)
;这个函数可能应该被称为
modbus_read_holding_registers
,因为这就是它的作用(发送命令
03
-“读取保持寄存器”)。

根据屏幕截图,您真正想要的是“输入寄存器”(使用命令

04
读取)。这是两组不同的寄存器(输入寄存器是只读的,而您可以更改保持寄存器的值)。尝试一下
modbus_read_input_registers
,我相信你会得到你期望的数据。

欢迎来到 Modbus 的精彩世界! (推荐本文中的“Modbus:当40001真正意味着1,或0真正意味着1”部分)

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