Modbus寄存器超过255无法访问 SimpleModbus

3

我是一名法国学生,已经使用SimpleModbus玩了一个星期,一切都很顺利......直到我试图实现一个需要大量寄存器(1000个)的从机。使用从机1时无法访问255号以后的寄存器。无论我做什么,只要读取的寄存器超过255,就会出现超时错误:

control.modbus.CommunicationException: While reading holding registers 255 on slave 1

文档中没有提到这种限制。阅读SimpleModbusSlave.cpp也没有帮助……也许我需要在“modbus更新”函数中更改起始地址,但我太菜了,无法理解……

unsigned int modbus_update() {
  if (*(ModbusPort).available())
  {
    unsigned char buffer = 0;
    unsigned char overflow = 0;

    while ((*ModbusPort).available())
    {
      // The maximum number of bytes is limited to the serial buffer size of 128 bytes
      // If more bytes is received than the BUFFER_SIZE the overflow flag will be set and the
      // serial buffer will be red untill all the data is cleared from the receive buffer.
      if (overflow)
        (*ModbusPort).read();
      else
      {
        if (buffer == BUFFER_SIZE)
          overflow = 1;
        frame[buffer] = (*ModbusPort).read();
        buffer++;
      }
      delayMicroseconds(T1_5); // inter character time out
    }

    // If an overflow occurred increment the errorCount
    // variable and return to the main sketch without
    // responding to the request i.e. force a timeout
    if (overflow)
      return errorCount++;

    // The minimum request packet is 8 bytes for function 3 & 16
    if (buffer > 7)
    {
      unsigned char id = frame[0];

      broadcastFlag = 0;

      if (id == 0)
        broadcastFlag = 1;

      if (id == slaveID || broadcastFlag) // if the recieved ID matches the slaveID or broadcasting id (0), continue
      {
        unsigned int crc = ((frame[buffer - 2] << 8) | frame[buffer - 1]); // combine the crc Low & High bytes
        if (calculateCRC(buffer - 2) == crc) // if the calculated crc matches the recieved crc continue
        {
          function = frame[1];
          unsigned int startingAddress = ((frame[2] << 8) | frame[3]); // combine the starting address bytes
          unsigned int no_of_registers = ((frame[4] << 8) | frame[5]); // combine the number of register bytes
          unsigned int maxData = startingAddress + no_of_registers;
          unsigned char index;
          unsigned char address;
          unsigned int crc16;

          // broadcasting is not supported for function 3
          if (!broadcastFlag && (function == 3))
          {
            if (startingAddress < holdingRegsSize) // check exception 2 ILLEGAL DATA ADDRESS
            {
              if (maxData <= holdingRegsSize) // check exception 3 ILLEGAL DATA VALUE
              {
                unsigned char noOfBytes = no_of_registers * 2;
                // ID, function, noOfBytes, (dataLo + dataHi)*number of registers,
                //  crcLo, crcHi
                unsigned char responseFrameSize = 5 + noOfBytes;
                frame[0] = slaveID;
                frame[1] = function;
                frame[2] = noOfBytes;
                address = 3; // PDU starts at the 4th byte
                unsigned int temp;

                for (index = startingAddress; index < maxData; index++)
                {
                  temp = regs[index];
                  frame[address] = temp >> 8; // split the register into 2 bytes
                  address++;
                  frame[address] = temp & 0xFF;
                  address++;
                }

                crc16 = calculateCRC(responseFrameSize - 2);
                frame[responseFrameSize - 2] = crc16 >> 8; // split crc into 2 bytes
                frame[responseFrameSize - 1] = crc16 & 0xFF;
                sendPacket(responseFrameSize);
              }
              else
                exceptionResponse(3); // exception 3 ILLEGAL DATA VALUE
            }
            else
              exceptionResponse(2); // exception 2 ILLEGAL DATA ADDRESS
          }
          else if (function == 16)
          {
            // Check if the recieved number of bytes matches the calculated bytes
            // minus the request bytes.
            // id + function + (2 * address bytes) + (2 * no of register bytes) +
            // byte count + (2 * CRC bytes) = 9 bytes
            if (frame[6] == (buffer - 9))
            {
              if (startingAddress < holdingRegsSize) // check exception 2 ILLEGAL DATA ADDRESS
              {
                if (maxData <= holdingRegsSize) // check exception 3 ILLEGAL DATA VALUE
                {
                  address = 7; // start at the 8th byte in the frame

                  for (index = startingAddress; index < maxData; index++)
                  {
                    regs[index] = ((frame[address] << 8) | frame[address + 1]);
                    address += 2;
                  }

                  // only the first 6 bytes are used for CRC calculation
                  crc16 = calculateCRC(6);
                  frame[6] = crc16 >> 8; // split crc into 2 bytes
                  frame[7] = crc16 & 0xFF;

                  // a function 16 response is an echo of the first 6 bytes from
                  // the request + 2 crc bytes
                  if (!broadcastFlag) // don't respond if it's a broadcast message
                    sendPacket(8);
                }
                else
                  exceptionResponse(3); // exception 3 ILLEGAL DATA VALUE
              }
              else
                exceptionResponse(2); // exception 2 ILLEGAL DATA ADDRESS
            }
            else
              errorCount++; // corrupted packet
          }
          else
            exceptionResponse(1); // exception 1 ILLEGAL FUNCTION
        }
        else // checksum failed
          errorCount++;
      } // incorrect id
    }
    else if (buffer > 0 && buffer < 8)
      errorCount++; // corrupted packet
  }
  return errorCount;
}

从Slave这个角度来看:SimpleModbusSlave,你有什么想法吗?

编辑:我认为有人遇到了同样的问题,但我真的不理解他改变了什么:这里

提前感谢那些能给我启示的人!


谢谢你的回复!这边没问题,我使用的是这个库的旧版本:https://github.com/pepsilla/Arduino/tree/master/MODBUS/ASCII/libraries/SimpleModbusSlave - Gabriel
我还看到一条评论:“最大字节数限制为128字节的串行缓冲区大小”。最大的Modbus ADU大小(RTU)为256字节。如果您一次只读取几个寄存器,您可能永远不会达到此限制。您一次尝试读取多少个寄存器?看到您所有的代码将会很有帮助。 - Marker
我觉得我需要在这里做出一些改变:地址仅存储在8位上,所以在255之后...但我完全不知道,有点迷失... unsigned int startingAddress = ((frame [2] << 8) | frame [3]); //组合起始地址字节 unsigned int no_of_registers = ((frame [4] << 8) | frame [5]); //组合寄存器数量字节(我使用RTU主机) - Gabriel
我查看了从机代码。它不是特别健壮,有点难以理解,但看起来应该能够工作。我也查看了主机代码,我认为我理解了它,但我希望看到它发送的数据包是什么样子的。我建议您使用CAS Modbus Scanner(免费)或Modbus Poll(免费试用版)测试您的从机。这两个都是我知道可行的Modbus主机工具。如果您的从机代码可以与这些工具一起使用,则问题在于主机代码;如果不能与它们一起使用,则问题在于从机代码。 - Marker
非常感谢!我会尝试的 :) - Gabriel
显示剩余5条评论
1个回答

0
非常感谢@Marker,现在它可以工作了!我更改了从设备的库:github.com/smarmengol/Modbus-Master-Slave-for-Arduino。

1
太好了,很高兴能帮助到你! - Marker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接