Проблема со связью по Modbus между двумя Arduino при записи более 27 регистров.

У меня следующая проблема: Я хочу отправить 200 регистров с ведущего устройства Modbus на ведомое устройство. Оба ардуино. Я не могу отправить более 27 регистров. Когда я отправляю больше, я получаю код ошибки 255, что означает тайм-аут. Я знаю, что сообщение Modbus ограничено 253 байтами (256 байт - адрес сервера (1 байт) - CRC (2 байта)). Перечислено здесь: СТР. СПЕЦИФИКАЦИЯ ПРОТОКОЛА ПРИЛОЖЕНИЯ MODBUS.5

Мои настройки:

  • Я использую два Arduino Mega 2560. Один в качестве ведущего, другой в качестве ведомого. Если это сработает, я хочу использовать более одного подчиненного устройства. Они подключены через последовательный порт 1, ведущий TX1 (контакт 18) к ведомому RX1 (контакт 19) и ведущий RX1 (контакт 19) к ведомому TX1 (контакт 18).

  • Я использую библиотеку Modbus — ModbusRtu.h от smarmengol.

  • Поскольку я хочу в конечном итоге обмениваться данными с несколькими подчиненными устройствами, я использую RS-485. Отправить сообщение в широковещательном формате, но сейчас это не актуально, потому что сначала я хочу отправить сообщение одному подчиненному устройству, чтобы проверить его.

Я знаю, что массив намного больше регистров, которые я хочу отправить. Это потому, что я хотел знать, когда наступит тайм-аут. Отправка 27 регистров работает нормально, и ведомое устройство получает все 27. Но при отправке более 27 регистров я получаю тайм-аут, и ничего не будет отправлено.

Главный код

#define SERIAL_BUFFER_SIZE 256
#include "ModbusRtu.h"

#define Timeout 150
#define QUERYINTERVALL 50

/* Defined the buffersize as stated in 
 * C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino\USBAPI.h
*/

modbus_t telegram;

// Тестируем отправку большого массива
uint16_t sendLargeArray[200] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
                                18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
                                33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
                                48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
                                63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
                                78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
                                93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105,
                                106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
                                118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
                                130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
                                142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153,
                                154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165,
                                166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177,
                                178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
                                190, 191, 192, 193, 194, 195, 196, 197, 198, 199};

Modbus master;

void dataSend();

void setup()
{

 /**
 *  Modbus object declaration
 *  u8id : node id = 0 for master, = 1..247 for slave
 *  u8serno : serial port (use 0 for Serial)
 *  u8txenpin : 0 for RS-232 and USB-FTDI 
 *               or any pin number > 1 for RS-485
 */
    master = Modbus(0, 1, 8); // это мастер с конфигурацией RS-485
    master.begin(9600, SERIAL_8N2);
    master.setTimeOut(Timeout);
    Serial.begin(9600); // настройка последовательного порта для отладки по USB
}

void loop()
{
    uint8_t error = master.getLastError(); //получим код ошибки
    uint8_t state = master.getState();     // получаем состояние от мастера 0 = простой 1 = ожидание

    dataSend(); // функция отправки массива

    // Код ошибки
    Serial.print("Error code: ");
    Serial.print(error);
    Serial.println();

    // Печать основного состояния
    Serial.print("Master State: ");
    Serial.print(state);
    Serial.println();
}

void dataSend()
{
    uint8_t slaveId;
    uint8_t u8state;
    unsigned long u32wait;
    slaveId = 1;
    u32wait = millis() + QUERYINTERVALL;
    bool staywhile = true;

    // телеграмма для отправки sendLargeArray
    telegram.u8id = 1;
    telegram.u8fct = 16;
    telegram.u16RegAdd = 0;
    telegram.u16CoilsNo = 28; // 27 или меньше работает нормально
    telegram.au16reg = sendLargeArray;
    u8state = 0;

    // Мастер передает данные
    while (staywhile)
    {
        switch (u8state)
        {
        case 0:
            if (millis() > u32wait)
                u8state++; // состояние ожидания
            break;
        case 1:
            master.query(telegram); // отправляем запрос (только один раз)
            u8state++;
        case 2:
            master.poll(); //проверяем входящие сообщения
            if (master.getState() == COM_IDLE)
            {
                u8state = 0;
                u32wait = millis() + QUERYINTERVALL;
                staywhile = false;
            }
            break;
        }
    }
}

Подчиненный код

#define SERIAL_BUFFER_SIZE 256
#include "ModbusRtu.h"

/* Определяем размер буфера, как указано в
     * C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino\USBAPI.h
    */

// массив данных для совместного использования сети Modbus

uint16_t recieveLargeArray[200] = {};

 /**
* Объявление объекта Modbus
* u8id: идентификатор узла = 0 для ведущего, = 1..247 для ведомого.
* u8serno : последовательный порт (используйте 0 для последовательного порта)
* u8txenpin: 0 для RS-232 и USB-FTDI.
* или любой номер контакта > 1 для RS-485
 */
Modbus slave(1, 1, 8); // это ведомое устройство @1 и RS-485

void setup()
{
  Serial.begin(9600);
  slave.begin(9600, SERIAL_8N2); // скорость передачи данных 9600
}

void loop()
{
  uint8_t error = slave.getLastError();
  slave.poll(recieveLargeArray, 28); // получение 27 или меньше регистров работает нормально

  // печатаем каждый пятый элемент полученного массива
  // таким образом никакой спам-консоли
  Serial.print("Recieve: ");
  for (int i = 0; i < 200; i += 5)
  {
    Serial.print(recieveLargeArray[i]);
    Serial.print(",");
  }
  // Код ошибки
  Serial.println();
  Serial.print("Error code: ");
  Serial.print(error);
  Serial.println();

  memset(recieveLargeArray, 0, 200 * sizeof(uint16_t)); // получаемLargeArray = {}

}

Вопросы

  • Кто-нибудь знает, почему я не могу отправить более 27 регистров?
  • Кто-нибудь делал подобный проект и может поделиться кодом?
  • Кто-нибудь это исправил?

Помощь очень ценится.

С уважением, ueberBrot!

Ссылка на страницу проблемы на ModbusRTU.h GitHub

Изменить

  • Забыл упомянуть, что я также увеличил размер буфера внутри библиотеки ModbusRTU.h. Я сделал это так, #define MAX_BUFFER 256, как указано в комментарии Юрая

  • Изменено расположение определения #define SERIAL_BUFFER_SIZE 256 в обоих эскизах вверх.

, 👍0


2 ответа


Лучший ответ:

0

Я изменил MAX_BUFFER внутри ModbusRTU.h с 64 на 256. Как вы уже говорили ранее, это только размер используемого массива. Еще я переместил #define SERIAL_BUFFER_SIZE 256 внутри обоих моих эскизов наверх. Это ничего не дало. После этого я нашел способ увеличить размер буфера RX и TX с помощью этот пост. Я изменил его с 64 на 256. Может быть, я мог бы также изменить их с помощью #define в своих эскизах?.

Теперь я могу одновременно отправить максимум 59 регистров. Я не уверен, почему я не могу отправить больше, потому что максимальное количество регистров должно быть 123 одновременно, а размер буфера - 256 байт, поэтому 123 регистра x 2 байта = 246 достаточно места в буфере.

,

1

В ModbusRtu.h:

#define MAX_BUFFER 64 //!< максимальный размер буфера связи в байтах

27*2=54 байта для регистров и 10 для заголовка и crc.

Измените определение MAX_BUFFER. На Меге у вас достаточно оперативной памяти.

Кстати: RS485 не предполагает обязательного использования Modbus. Вы можете использовать свой собственный протокол.

,

Спасибо за ответ @Juraj. Ой, извини, забыл упомянуть об этом в исходном посте. После того, как я увеличил размер буфера Arduino до 256 байт, я сделал то же самое в библиотеке ModbusRTU.h #define MAX_BUFFER 256 . Так что проблема не в этом. Используя мой собственный протокол, что вы имеете в виду? Я понятия не имею, как это сделать, поэтому думаю, что это либо не в моих силах, либо я просто не знаю, с чего начать. Можете ли вы объяснить или указать мне на пример? Что я мог бы использовать для своей конечной цели хозяина со множеством рабов? Ура, ueberBrot, @ueberBrot

если разрешено только 27 регистров, то это неприменимо. что за «буфер Ардуино»?, @Juraj

В файле ***\Arduino\hardware\arduino\avr\cores\arduino\USBAPI.h SERIAL BUFFER SIZE (буфер Arduino) определяется в строках с 77 по 86. Если буфер не определен, как я в моих эскизах #define SERIAL_BUFFER_SIZE 256 он имеет два значения по умолчанию: 16 или 64 байта, в зависимости от оперативной памяти Arduino. Или это неправильно?, @ueberBrot

не неправильно, но и не нужно. Последовательный буфер на самом деле является «буфером». Если он заполнен, write() немного ждет, пока не освободится место (байты отправляются непрерывно). Буфер в ModbusRtu.h не является настоящим буфером, это массив для построения полного сообщения., @Juraj

Ах, ок, подумал, что это может быть связано с моей проблемой, поэтому я увеличил это значение. Если изменение, которое я внес в библиотеку, не применилось, как это происходит? У вас есть подсказка?, @ueberBrot

вы изменили определение внутри ModbusRtu.h? в твоем эскизе уже поздно., @Juraj