Тайм-аут последовательной связи при длительном отключении кабеля

У меня есть приложение, которое считывает различные аппаратные средства через rs232. Он был протестирован, и он работал отлично. Для окончательного применения мне понадобилось ввести несколько кабелей длиной hunder m, что означает, что у меня есть преобразователи rs485.

Когда я запускаю свое приложение для чтения аппаратного обеспечения, я получаю ошибку таймаута для System.IO.Ports.SerialStream.Read. Я увеличил тайм-аут до 20 секунд, к сожалению, он не разрешил проблему.

Я пробовал разные приложения для чтения аппаратного обеспечения, и они работали даже с частотой чтения 1сек.

Коммуникация использует протокол Modbus, который находится на текущем этапе, я предполагаю, что это не имеет значения, поскольку я не добираюсь до стадии, чтобы получить что-либо.

Мой код выглядит так: Сначала открытие и инициализация последовательного порта:

//get the right modbus data structure element
ModBus MB = (ModBus)s[0].sensorData;

//set up the serial port regarding the data structure data
SerialPort sp = new SerialPort();
sp.PortName = MB.portName;
sp.BaudRate = Convert.ToInt32(MB.baudRate);
sp.DataBits = MB.dataBits;
sp.Parity = MB.parity;
sp.StopBits = MB.stopBits;
//Set time outs 20 sec for now
sp.ReadTimeout = 20000;
sp.WriteTimeout = 20000;

//добавьте порт в список, доступ к которому может получить читатель   portList.Add(SP);   sp.Open();

Считывание аппаратного обеспечения:

//get the right port for com
SerialPort sp = getRightPort();
ModBus MB = getRightModBusStructureelement();
try
   {
     //Clear in/out buffers:
     sp.DiscardOutBuffer();
     sp.DiscardInBuffer();

     //create modbus read message
     byte[] message = createReadModBusMessage();

     try
        {
         sp.Write(message, 0, message.Length);

         // FM.writeErrorLog output included for easier debug
         FM.writeErrorLog(DateTime.Now + ": ModBus Message Sent");
         FM.writeErrorLog(DateTime.Now + ": Read TimeOut = " + sp.ReadTimeout + " Write TimeOut = " + sp.WriteTimeout);

         int offset = 0, bytesRead;
         int bytesExpected = response.Length;

         FM.writeErrorLog(DateTime.Now + ": start read");

         while (bytesExpected > 0 && (bytesRead = sp.Read(response, offset, bytesExpected)) > 0)
            {
              FM.writeErrorLog(DateTime.Now + ": read - " + offset);
              offset += bytesRead;
              bytesExpected -= bytesRead;
            }
        }
        catch (Exception err)
        {
           Console.WriteLine("ERROR Modbus Message to serial port ModBus: " + err);
           FM.writeErrorLog(DateTime.Now + " - " + "ERROR Modbus Message to serial port ModBus: " + err);
         }

  }

После попытки приложения я получил следующий результат из файла ErroLog.txt:

14/01/2016 17:18:17: ModBus Message Sent
14/01/2016 17:18:17: Read TimeOut = 20000 Write TimeOut = 20000
14/01/2016 17:18:18: start read
14/01/2016 17:18:38 - ERROR Modbus Message to serial port ModBus: System.TimeoutException: The operation has timed out.
   at System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count, Int32 timeout)
   at System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count)
   at System.IO.Ports.SerialPort.Read(Byte[] buffer, Int32 offset, Int32 count)
   at ProbReader.SensorReader.modbusReading(List`1 mm, Int32 spCounter)
14/01/2016 17:18:38: 0
14/01/2016 17:18:38: 0

Я увеличил тайм-аут до 60 секунд на всякий случай, но такую ​​же ошибку:

15/01/2016 11:11:51: ModBus Message Sent
15/01/2016 11:11:51: Read TimeOut = 60000 Write TimeOut = 60000
15/01/2016 11:11:51: start read
15/01/2016 11:12:51 - ERROR Modbus Message to serial port ModBus: System.TimeoutException: The operation has timed out.
   at System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count, Int32 timeout)
   at System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count)
   at System.IO.Ports.SerialPort.Read(Byte[] buffer, Int32 offset, Int32 count)
   at ProbReader.SensorReader.modbusReading(List`1 mm, Int32 spCounter)
15/01/2016 11:12:51: 0
15/01/2016 11:12:51: 0

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

Я не включил остальную часть моего кода, поскольку он истекает раньше, и я думаю, что это не имеет значения.

Ответы

Ответ 1

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

Немного копаясь, дайте мне следующий код, увеличивая время записи и чтения. Он решил мою проблему:

                            sp.ReadTimeout = 60000;
                            sp.WriteTimeout = 60000;

                            sp.DtrEnable = true;
                            sp.RtsEnable = true;
                            sp.Handshake = Handshake.None;

Я надеюсь, что это поможет другим в будущем, и спасибо за помощь и усилия.

Ответ 2

Если вы используете сотни метров последовательного кабеля (который сам по себе является проблемой аппаратного обеспечения), я настоятельно рекомендую иметь надлежащий трансивер на обоих концах кабеля. Сам кабель должен быть экранированным и высококачественным. Длинные неэкранированные кабели могут стать жертвами наведенных колебаний напряжения, которые могут повредить оборудование, которое не предназначено для длительных проводов кабелей.

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

Ответ 3

Предполагая, что это проблема с оборудованием (и, как мне кажется, мне тоже пришлось решить аналогичную проблему), я бы рекомендовал заменить сотни метров последовательного кабеля сервером устройств (через ethernet) рядом с последовательным устройство. Сервер устройства может эмулировать COM-порт на вашем ПК и, следовательно, короткое замыкание последовательного кабеля.

К сожалению, эти серверы немного дороже, чем несколько метров кабеля.

Ответ 4

Обратите внимание, что разница между RS232 и RS485 заключается в том, что RS232 является полнодуплексным, а RS485 - только полудуплексным. Поскольку modbus - это протокол типа ответа на запрос, это не ваша проблема, но важно знать.

Из-за этого RS232 ↔ RS485 должен знать, когда включить передатчик RS485. Это можно сделать по-разному на разных преобразователях, а также можно настроить. Это может быть сделано с дополнительными линиями управления, которые RS232 имеет, но RS485 не хватает. RTS/CTS. Если неверно настроена, ответная сторона (которая ждет ответа на запрос) может быть включена, а затем ничего не может получить.

Пример в руководстве http://ftc.beijer.se/files/C125728B003AF839/992C59EC02C66E00C12579C60051484E/westermo_ug_6617-2203_mdw-45.pdf Это популярная модель в Швеции, которая имеет три режима работы. Он может включать/выключать передатчик только входящими данными, управляемыми выводом RTS на разъеме DB9-RS232 или всегда включать передатчик (для RS422, которые имеют отдельные провода в каждом направлении) http://screencast.com/t/KrkEw13J8

Это сложно, потому что некоторые производители не распечатывают, как это работает. Это также очень легко получить неправильную проводку, потому что не понятно, какие DCE и DTE.

Ответ 5

Предполагая, что это не проблема с аппаратным/длинным кабелем, вы можете сделать что-то в своем коде для обработки ошибки:

Вам нужно создать "правильный" обработчик ошибок столько, сколько вы создаете getRightPort:

SerialPort sp = getRightPort();

Предполагая, что внутри объекта последовательного порта есть Collection, и вы возвращаете правильный, в случае возникновения этой ошибки SerialPort убедитесь, что вы повторно создали ошибку SerialPort object с тем же параметры:

catch (Exception err)
{
   Console.WriteLine("ERROR Modbus Message to serial port ModBus: " + err);
   FM.writeErrorLog(DateTime.Now + " - " + "ERROR Modbus Message to serial port ModBus: " + err);
   reinitRightPort(sp); //add this
}

И метод reinitRightPort(); может выглядеть так, как вы начинаете, с небольшими различиями, например:

  • Вам больше не нужно добавлять это в List<SerialPort>
  • Вы не должны объявлять SerialPort в методе, вы получаете его из входного аргумента.
  • Лучше всего ввести некоторую проверку правильности ввода, чтобы избежать более поздних известных ошибок.
  • Возможно, вы можете закрыть предыдущее соединение, просто чтобы убедиться, что порт может использоваться новым SerialPort object.

Что-то вроде этого:

private void reinitRightPort(SerialPort sp){ //get SerialPort from outside of method
    //Add whatever necessary here, to close all the current connections
    //Plus all the error handlings
    if (sp == null) //Read 3.
        return;
    sp.Close(); //Read 4. close the current connections

    //get the right modbus data structure element
    ModBus MB = (ModBus)s[0].sensorData;

    //set up the serial port regarding the data structure data
    sp = new SerialPort(); //Read 2. sp is from outside the method, but use new keyword still
    sp.PortName = MB.portName;
    sp.BaudRate = Convert.ToInt32(MB.baudRate);
    sp.DataBits = MB.dataBits;
    sp.Parity = MB.parity;
    sp.StopBits = MB.stopBits;
    //Set time outs 20 sec for now
    sp.ReadTimeout = 20000;
    sp.WriteTimeout = 20000;

    //portList.Add(sp); Read 1. no need to add this! It is already there!
    sp.Open();
}

Примечание: после этого и убедитесь, что ваш порт работает хорошо, по возможности вы также можете объединить метод reinitRightPort выше с вашей реальной инициализацией с небольшими изменениями. Но первое, что вы можете сделать, это заставить ваш последовательный порт работать под ошибкой.

Но если источник ошибок исходит из проблемы аппаратного/длинного кабеля (например, размещение кабеля в RS232 или RS485 или падение напряжения из-за длительного кабель или несовместимое оборудование: это, короче говоря, не имеет ничего общего с кодирование вообще), то, к сожалению, решение не может исходить из кода также. Вы должны найти реальную проблему с оборудованием.