You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32通过Modbus RTU读取多数据类型的技术问题求助

问题:ESP32通过RS485 Modbus RTU读取多字节数据类型失败

当前在ESP32上通过RS485运行Modbus RTU,从Modbus Slave模拟器读取数据。使用调整后的ArduinoModbus库(原库不支持ESP32)可读写二进制和int类型数据,但无法处理float、long、double等多字节数据类型,开发环境为VSCode+PlatformIO。

修改后的read()函数

long ModbusClient::read()
{
  if (_available <= 0) {
    return -1;
  }

  long result = -1;

  switch (_type) {
    case COILS:
    case DISCRETE_INPUTS:
      result = ((uint8_t*)_values)[_read];
      if (result != -1) {
      _available--;
      _read++;
      }
      break;

    case HOLDING_REGISTERS:
    case INPUT_REGISTERS:
      if (_available >= 2) {
        result = ((uint16_t*)_values)[_read];
        result = (result << 16) | ((uint16_t*)_values)[_read + 1];
        if (result != -1) {
          _available -= 2;
          _read += 2;
        }
      }
      break;

    default:
      break; 
  }
  return result;
}

备选研究函数holdingRegisterRead()

long ModbusClient::holdingRegisterRead(int id, int address)
{
  uint16_t value;

  modbus_set_slave(_mb, id);
  
  if (modbus_read_registers(_mb, address, 1, &value) < 0) {
    return -1;
  }

  return value;
}

主循环代码

void loop() {
  readHoldingRegisterValues();

  delay(5000);
  Serial.println();
}

void readHoldingRegisterValues() {
  Serial.print("Reading Input Register values ... ");

  // read 10 Input Register values from (slave) id 1, address 0x00
  if (!ModbusRTUClient.requestFrom(1, HOLDING_REGISTERS, 0x00, 10)) {
    Serial.print("failed! ");
    Serial.println(ModbusRTUClient.lastError());
  } else {
    Serial.println("success");

    while (ModbusRTUClient.available()) {
      Serial.print(ModbusRTUClient.read());
      Serial.print(' ');
    }
    Serial.println();
  }
}

当前输出结果

1111170744 0 0 0 0

已知Modbus寄存器为16位,float(32位)、double(64位)等类型需要组合多个寄存器读取,求解决方法。


解决方案

核心思路

Modbus多字节数据的解析依赖字节序(大端/小端),需先明确Slave模拟器的字节存储规则,再通过读取连续寄存器后重组数据。

1. 新增原始寄存器读取方法

在ModbusClient类中添加读取单个16位寄存器的函数,方便后续灵活组合多字节数据:

uint16_t ModbusClient::readRegister()
{
  // 校验寄存器类型和可用数量
  if (_available <= 0 || (_type != HOLDING_REGISTERS && _type != INPUT_REGISTERS)) {
    return 0xFFFF; // 返回无效值标记
  }
  uint16_t result = ((uint16_t*)_values)[_read];
  _available--;
  _read++;
  return result;
}

2. 应用层解析多字节数据示例

以读取float类型为例(占2个16位寄存器),假设Slave采用大端序存储(高字节在前):

void readFloatValue() {
  Serial.print("Reading float from address 0 ... ");
  // 读取2个连续寄存器
  if (!ModbusRTUClient.requestFrom(1, HOLDING_REGISTERS, 0x00, 2)) {
    Serial.print("failed! ");
    Serial.println(ModbusRTUClient.lastError());
  } else {
    Serial.println("success");
    if(ModbusRTUClient.available() >=2){
      uint16_t regHigh = ModbusRTUClient.readRegister();
      uint16_t regLow = ModbusRTUClient.readRegister();
      
      // 组合成32位原始二进制数据
      uint32_t rawData = ((uint32_t)regHigh) << 16 | regLow;
      // 转换为float类型
      float floatValue;
      memcpy(&floatValue, &rawData, sizeof(floatValue));
      
      Serial.print("Parsed float value: ");
      Serial.println(floatValue);
    }
  }
}

3. 扩展支持double类型

double占4个16位寄存器,解析逻辑类似:

void readDoubleValue() {
  Serial.print("Reading double from address 2 ... ");
  if (!ModbusRTUClient.requestFrom(1, HOLDING_REGISTERS, 0x02, 4)) {
    Serial.print("failed! ");
    Serial.println(ModbusRTUClient.lastError());
  } else {
    Serial.println("success");
    if(ModbusRTUClient.available() >=4){
      uint64_t rawData = 0;
      // 按大端序拼接4个寄存器
      for(int i=0;i<4;i++){
        rawData = (rawData << 16) | ModbusRTUClient.readRegister();
      }
      double doubleValue;
      memcpy(&doubleValue, &rawData, sizeof(doubleValue));
      
      Serial.print("Parsed double value: ");
      Serial.println(doubleValue);
    }
  }
}

关键注意事项

  • 字节序校验:若解析结果异常,交换寄存器顺序测试(比如大端序改regLow在前regHigh在后),匹配Slave的实际存储规则。
  • 寄存器数量匹配:float需2个寄存器,double需4个,requestFrom的数量必须对应。
  • 安全转换:使用memcpy进行二进制数据转换,避免直接强制类型转换导致的字节序错误。

内容的提问来源于stack exchange,提问作者Chung Phạm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 07:02:03