Задержка связи Arduino MODBUS RTU?

#c #arduino #modbus #rs485

#c #arduino #modbus #rs485

Вопрос:

Существует проблема при написании кода MODBUS RTU с использованием Arduino.

Во-первых, связь прошла успешно. Однако обмен данными выполняется в порядке запрос -> запрос -> ответ -> запрос -> запрос -> ответ.

Пожалуйста, обратитесь к видео ниже. https://youtu.be/Z8tkmY7l-oo

Я не знаю, что не так с моим кодом.

помогите мне..

мой код…

 #include <Crc16.h>
Crc16 crc;

#define EN0 2

uint8_t n8ID = 1;
uint8_t FunctionCode = 3;

const int DIP_1 = 6;
const int DIP_2 = 7;
const int DIP_3 = 8;
const int DIP_4 = 9;

uint8_t MODBUS_Request[10];

uint8_t Data[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

void setup() 
{
  pinMode(EN0, OUTPUT);

  pinMode(DIP_1, INPUT_PULLUP);
  pinMode(DIP_2, INPUT_PULLUP);
  pinMode(DIP_3, INPUT_PULLUP);
  pinMode(DIP_4, INPUT_PULLUP);
  
  digitalWrite(EN0, LOW);
  
  Serial.begin(9600);

}

void loop() 
{
  digitalWrite(EN0, LOW);

  n8ID = 0;
  n8ID  = (!digitalRead(DIP_1)) << 0;
  n8ID  = (!digitalRead(DIP_2)) << 1;
  n8ID  = (!digitalRead(DIP_3)) << 2;
  n8ID  = (!digitalRead(DIP_4)) << 3;

  if (Serial.available())
  {
    uint8_t leng = Serial.readBytes(MODBUS_Request, 8);    
    
    if(MODBUS_Request[0] == n8ID amp;amp; MODBUS_Request[1] == FunctionCode amp;amp; MODBUS_Request[2] == 0 amp;amp; MODBUS_Request[3] == 0)
    {
      uint8_t Request_dataBuff[6];

      for (int i = 0; i < 6; i  )
      {
        Request_dataBuff[i] = MODBUS_Request[i];
      }
      
      unsigned short RequestCRC = (unsigned short)(MODBUS_Request[7] << 8 | MODBUS_Request[6]);
      crc.clearCrc();

      for (uint8_t i = 0; i < 6; i  )
        crc.updateCrc(Request_dataBuff[i]);

      unsigned short CRC_Check = crc.getCrc();
      CRC_Check = crc.Modbus(Request_dataBuff, 0, 6);

      if(RequestCRC == CRC_Check)
      {
        uint8_t send_dataBuff[15] = {n8ID, FunctionCode, 12, Data[0], Data[1], Data[2], Data[3], Data[4], Data[5], Data[6], Data[7], Data[8], Data[9], Data[10], Data[11]};

        crc.clearCrc();
        
        for (uint8_t i = 0; i < 15; i  )
          crc.updateCrc(send_dataBuff[i]);

        unsigned short ResponseCRC = crc.getCrc();
        ResponseCRC = crc.Modbus(send_dataBuff, 0, 15);

        uint8_t Response_CRC_H = ResponseCRC >> 8;
        uint8_t Response_CRC_L = ResponseCRC amp; 0xFF;

        uint8_t MODBUS_Response[17] = {n8ID, FunctionCode, 12, Data[0], Data[1], Data[2], Data[3], Data[4], Data[5], Data[6], Data[7], Data[8], Data[9], Data[10], Data[11], Response_CRC_L, Response_CRC_H};
        
        digitalWrite(EN0, HIGH);
        
        for(int i = 0; i < 17; i  )
        {
          Serial.write(MODBUS_Response[i]);
          Serial.flush();
        }
        digitalWrite(EN0, LOW);
      }
    }
  }
}
 

Ответ №1:

Ваш код добавляет большую часть задержки. Вы вводите огромные накладные расходы, записывая в порт по одному байту за раз.

Может быть, вы можете попробовать заменить эту часть:

 for(int i = 0; i < 17; i  )
    {
      Serial.write(MODBUS_Response[i]);
      Serial.flush();
    }
 

С чем-то более простым:

 Serial.write(MODBUS_Response,17);
Serial.flush();
 

который просто записывает весь кадр Modbus за один раз.

Если это изменение само по себе не устраняет ваши проблемы, вам может потребоваться предоставить более подробную информацию по вашему вопросу о другой стороне ссылки.

Комментарии:

1. Спасибо за ваши ответы. Однако, даже если вы измените его, как вы сказали, симптомы те же. В настоящее время подключение моего устройства — Master: 1, Slave: 1, а программное обеспечение ПК выступает в качестве ведущего. Программное обеспечение для ПК — это симулятор, который может служить в качестве ведущего устройства MODBUS RTU. Если вы выполните поиск по запросу «MODSCAN64» в Google, вы сможете получить информацию о программном обеспечении. Так что где-то должна быть проблема с моим кодом.

Ответ №2:

Вы не можете отправить два запроса подряд.

Что произойдет, если вы отправите два запроса двум подчиненным устройствам, и они оба ответят одновременно?

Последовательная связь не имеет никакого механизма, позволяющего избежать столкновений.

Это должен быть мастер, который синхронизируется в строгом порядке: запрос -> ответ -> запрос -> ответ … и т.д.

Вы не можете отправить новый запрос, пока не получите ответ от предыдущего.

Комментарии:

1. Я не понимаю, что есть два запроса. В настоящее время подключение моего устройства — Master: 1, Slave: 1, а программное обеспечение ПК выступает в качестве ведущего. Программное обеспечение для ПК — это симулятор, который может служить в качестве ведущего устройства MODBUS RTU. Если вы выполните поиск «MODSCAN64» в Google, вы сможете получить информацию о программном обеспечении.

Ответ №3:

Причина, похоже, найдена, но, похоже, это не фундаментальное решение.

значение тайм-аута arduino по умолчанию составляет 1000 мс, и ведущий запрашивал данные у ведомого устройства каждые 1000 мс.

Я думал, что перейду к следующему коду, когда из приведенного ниже кода поступит буфер приема объемом 8 байт, но, думаю, я жду тайм-аута. Serial.readBytes(MODBUS_Request, 8);

я использовал Serial.setTimeout() функцию в качестве решения для сокращения времени ожидания, но это, похоже, не является фундаментальным решением.

даже если вы используете эту функцию, код будет останавливаться до тех пор, пока я его установлю. Я хочу использовать Serial.readBytesUntil() функцию, но последними получаемыми данными являются CRC, поэтому последние данные не могут быть предсказаны.

Когда данные получены, как я могу перейти к следующему коду?

Ответ №4:

Первый

Попробуйте добавить небольшую задержку, прежде чем линия TXEN опустится,

         digitalWrite(EN0, HIGH);
        
        for(int i = 0; i < 17; i  )
        {
          Serial.write(MODBUS_Response[i]);
          Serial.flush();
        }
        delay(1)  # <-- add a little delay to allow transmission finish 
        digitalWrite(EN0, LOW);
 

Возможно, потребуется увеличить задержку, если скорость передачи данных действительно низкая.

Второй

Могут быть некоторые значения «0» или случайные / шумовые значения, предшествующие фактическим байтам запроса, полученным вашим кодом, поэтому вы не можете просто прочитать 8 байт в одном пакете и принять его за фактический запрос. Вместо этого вам, возможно, придется читать один за другим и выяснять, где находится начальный байт запроса.

Смотрите следующий пример,

 0 0 0 0 0 1 3 x x x x c c   ...   1 3 x x x x c c
^ first read  ^ ^ second read     ^ third read  ^  
| (discard)   | | (timeout)       | (success)   |

 

Комментарии:

1. То же самое касается добавления «задержки». Изменение скорости передачи данных на 115200 не решает проблему….