Я написал простое приложение на C# 2.0, используя класс Serialport .Net Framework 2.0 для связи с картой контроллера через COM1.
Недавно возникла проблема: байты, возвращенные методом Read, неверны. Он вернул правильное количество байтов, только значения были неверными. Однако аналогичное приложение, написанное на Delphi, по-прежнему возвращало правильные значения.
Я использовал Портмон для регистрации активности на последовательном порту обоих приложений, сравнил два журнала и там, где были некоторые (очевидно) незначительные разные настройки, и я попытался имитировать приложение Delphi как можно точнее, но безрезультатно.
Итак, что может повлиять на байтовые значения, возвращаемые методом Read?
Большинство настроек между двумя приложениями идентичны.
Вот список строк, которые различались в журнале Portmon:
Приложение Delphi:
IOCTL_SERIAL_SET_CHAR Serial0 SUCCESS EOF:dc ERR:0 BRK:0 EVT:0 XON:11 XOFF:13
IOCTL_SERIAL_SET_HANDFLOW Serial0 SUCCESS Shake:0 Replace:0 XonLimit:256XoffLimit:256 IOCTL_SERIAL_SET_TIMEOUTS Serial0 SUCCESS RI:-1 RM:100 RC:1000 WM:100 WC:1000 IOCTL_SERIAL_SET_WAIT_MASK Serial0 SUCCESS Mask: RXCHAR RXFLAG TXEMPTY CTS DSR RLSD BRK ERR RING RX80FULL
Приложение C#:
IOCTL_SERIAL_SET_CHAR Serial0 SUCCESS EOF:1a ERR:0 BRK:0 EVT:1a XON:11 XOFF:13 IOCTL_SERIAL_SET_HANDFLOW Serial0 SUCCESS Shake:0 Replace:0 XonLimit:1024XoffLimit:1024 IOCTL_SERIAL_SET_TIMEOUTS Serial0 SUCCESS RI:-1 RM:-1 RC:1000 WM:0 WC:1000 IOCTL_SERIAL_SET_WAIT_MASK Serial0 SUCCESS Mask: RXCHAR RXFLAG CTS DSR RLSD BRK ERR RING
ОБНОВИТЬ:
Правильные возвращенные байты: 91, 1, 1, 3, 48, 48, 50, 69, 66, 51, 70, 55, 52, 93 (14 байтов). Последнее значение представляет собой простую контрольную сумму.
Возвращены неверные значения: 91, 241, 254, 252, 242, 146, 42, 201, 51, 70, 55, 52, 93 (13 байт).
Как видите, первые и последние пять возвращенных байтов соответствуют друг другу.
Событие ErrorReceived указывает, что произошла ошибка кадрирования, которая может объяснить неверные значения. Но возникает вопрос, почему SerialPort обнаруживает ошибку кадрирования, когда приложение Delphi, по-видимому, этого не делает?





Вы проверили настройки количества бит данных, стоповых битов и четности?
Бит четности - это своего рода механизм обнаружения ошибок. Например: если вы отправляете с использованием 7 бит данных и одного бита четности, восьмой бит будет использоваться для обнаружения ошибок инверсии битов. Если получатель ожидает 8 бит данных и не битов четности, результат будет искажен.
К сожалению, вы не указали, какие именно различия вы получите. Это случайный символ, который отличается, или все ваши входящие данные искажены? Обратите внимание, что символы, считываемые с помощью функции SerialPort.Read, могут быть изменены системой из-за установки свойства SerialPort.Encoding. Этот параметр влияет на интерпретацию входящего текста, поскольку это был текст в ASCII, Unicode, UTF8 или любой другой схеме кодирования, которую Windows использует для преобразования «сырых байтов» в «читаемый текст».
Я также подумал, что это может быть кодировка, поскольку настройки IOCTL_SERIAL_SET_CHAR немного отличались, и я предположил, что это может иметь какое-то отношение к кодировке. Но поскольку возвращаемые значения являются байтами, как на это может повлиять кодировка? Не могли бы вы привести пример?
Ах, извините, надо было проверить себя. Я вижу, что кодировка может повлиять на количество байтов, используемых для представления одного символа.
Если вы читаете массив байтов (например, SerialPort.Read), вы должны получить именно те байты, которые вы видите в PortMon.
Если вы конвертируете в символы (SerialPort.ReadLine или SerialPort.ReadChar), то данные будут закодированы с использованием текущей кодировки (свойство SerialPort.Encoding), что объясняет наблюдаемые вами различия.
Если вы хотите видеть символы с теми же двоичными значениями, что и байты в проводе, хорошей кодировкой является Latin-1, как описано в эта почта.
Пример:
SerialPort.Encoding = Encoding.GetEncoding("Latin1")
Я поигрался с кодировкой безрезультатно. Теперь я использую ReadByte (), чтобы избежать возможных проблем с кодировкой. В любом случае спасибо за интересное предложение.
Что ж, вроде бы проблема решена (по крайней мере, на время).
По-видимому, ошибка кадрирования вызвала возврат неверных значений. Я написал приложение VB6, используя элемент управления MSComm, который работал нормально, и сравнил файлы журналов, созданные Portmon.
Я подобрал следующие отличия
Приложение VB6:
IOCTL_SERIAL_SET_HANDFLOW Serial0 SUCCESS Shake:1 Replace:0 XonLimit:256 XoffLimit:256
Приложение C#:
IOCTL_SERIAL_SET_HANDFLOW Serial0 SUCCESS Shake:0 Replace:0 XonLimit:1024 XoffLimit:1024
Играя с настройками, я обнаружил, что если я установил
_serialPort.DtrEnable = true
приложение C# создает следующую запись журнала:
IOCTL_SERIAL_SET_HANDFLOW Serial0 SUCCESS Shake:1 Replace:0 XonLimit:1024 XoffLimit:1024
Похоже, это предотвратило ошибку кадрирования, и приложение, похоже, работает нормально.
Возможно, вы могли бы привести несколько примеров неверных данных, помимо правильных. Если бы мы могли увидеть, что было неправильно, мы могли бы догадаться о проблеме.