Что может повлиять На Значения, возвращаемые Serialport.Read()
-
02-07-2019 - |
Вопрос
Я написал простое приложение на C # 2.0, используя класс Serialport .Net Framework 2.0 для связи с платой контроллера через COM1.
Недавно возникла проблема, заключавшаяся в том, что байты, возвращаемые методом чтения, неверны.Он вернул нужное количество байт, только значения были неверными.Однако аналогичное приложение, написанное на Delphi, по-прежнему возвращало правильные значения.
Я использовал Портмон чтобы зарегистрировать активность на последовательном порту обоих приложений, сравнил два журнала и там, где были некоторые (по-видимому) незначительные различия в настройках, и я попытался максимально точно имитировать приложение Delphi, но безрезультатно.
Итак, что может повлиять на значения байтов, возвращаемые методом Read ?
Большинство настроек между двумя приложениями идентичны.
Вот список строк, которые отличались в журнале Portmon :
Приложение Delphi :
УСПЕХ IOCTL_SERIAL_SET_CHAR Serial0 EOF: постоянный ток ОШИБКА: 0 BRK:0 EVT:0 Начало:11 НАЧАЛО:13
IOCTL_SERIAL_SET_HANDFLOW Serial0 УСПЕШНОЕ изменение: 0 Замена: 0 XonLimit:256 XoffLimit:256 IOCTL_SERIAL_SET_TIMEOUTS Сериал0 RI УСПЕХА:-1 RM:100 RC:1000 WM: 100 WC: 1000 Маска УСПЕХА IOCTL_SERIAL_SET_WAIT_MASK Serial0:RXCHAR RXFLAG TXПУСТОЙ CTS DSR RLSD КОЛЬЦО ОШИБКИ BRK RX80ПОЛНЫЙ
Приложение на C # :
УСПЕХ IOCTL_SERIAL_SET_CHAR Serial0 EOF:1a ОШИБКА: 0 BRK:0 EVT: 1a XON: 11 XOFF: 13 IOCTL_SERIAL_SET_HANDFLOW Serial0 УСПЕШНОЕ изменение: 0 Замена: 0 XonLimit: 1024 XoffLimit:1024 IOCTL_SERIAL_SET_TIMEOUTS Сериал0 RI УСПЕХА:-1 RM:-1 RC:1000 WM:0 WC: 1000 Маска УСПЕХА IOCTL_SERIAL_SET_WAIT_MASK Serial0:RXCHAR RXFLAG CTS DSR RLSD BRK ОШИБКА КОЛЬЦО
Обновить:
Правильными возвращенными байтами были :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, по - видимому, этого не делает?
Решение
Что ж, похоже, проблема решена (по крайней мере, на данный момент).
По-видимому, ошибка кадрирования привела к возврату неверных значений.Я написал приложение VB6, используя элемент управления MSComm, который работал нормально, и сравнил файлы журналов, сгенерированные Portmon.
Я заметил следующие отличия
Приложение VB6 :
IOCTL_SERIAL_SET_HANDFLOW Сериал0 УСПЕХ Встряхивание: 1 Заменить: 0 XonLimit: 256 XoffLimit: 256
Приложение на C # :
IOCTL_SERIAL_SET_HANDFLOW Сериал0 УСПЕХ Встряхивание: 0 Заменить: 0 XonLimit: 1024 XoffLimit: 1024
Поиграв с настройками, я обнаружил, что если я установлю
_serialPort.DtrEnable = true
приложение C # генерирует следующую запись в журнале :
IOCTL_SERIAL_SET_HANDFLOW Сериал0 УСПЕХ Встряхивание: 1 Заменить: 0 XonLimit: 1024 XoffLimit: 1024
Это, казалось, предотвратило ошибку кадрирования, и приложение, похоже, работает нормально.
Другие советы
Вы проверили настройки количества битов данных, стоп-битов и четности?
Бит четности - это своего рода механизм обнаружения ошибок.Например:Если вы отправляете, используя 7 битов данных и один бит четности, восьмой бит будет использоваться для обнаружения ошибок инверсии битов.Если получатель ожидает 8 битов данных и никаких битов четности, результат будет искажен.
К сожалению, вы не упомянули точно, какой тип различий вы получаете.Это случайный символ , который отличается или все ваши входящие данные искажены ?Обратите внимание, что символы, считываемые с помощью функции SerialPort.Read, могут быть изменены системой из-за настройки SerialPort.Кодировка собственность.Этот параметр влияет на интерпретацию входящего текста, поскольку это был текст в ASCII, Unicode, UTF8 или любой другой схеме кодирования, используемой Windows для преобразования "необработанных байтов" в "читаемый текст".
Если вы считываете данные в массив байтов (например:SerialPort.Read) вы должны получить именно те байты, которые вы видите в PortMon.
Если вы преобразуете в символы (SerialPort.ReadLine или SerialPort.readChar), то данные будут закодированы с использованием текущей кодировки (свойство SerialPort.Encoding), что объясняет различия, которые вы видите.
Если вы хотите видеть символы с теми же двоичными значениями, что и байты в проводе, хорошей кодировкой для использования является Latin-1, как описано в этот пост.
Пример:
SerialPort.Encoding = Encoding.GetEncoding("Latin1")