Как отправить байты на последовательное устройство в C #? - PullRequest
4 голосов
/ 31 марта 2011

У меня есть устройство, которое использует последовательный интерфейс (через USB-адаптер) для взаимодействия с моим ПК.У меня есть реальная проблема, чтобы заставить его хорошо играть в C #.Я знаю, что это работает должным образом, потому что программное обеспечение, поставляемое поставщиком, ведет себя как ожидалось.Я также знаю, что могу получать данные, используя мой код, благодаря тестовому режиму, который неоднократно отправляет «ОК».

Вот мой код:

    private SerialPort port;

    public SerialConnection()
    {
        this.port = new SerialPort("COM3", 38400, Parity.None, 8, StopBits.One);
        this.port.WriteTimeout = 2000; port.ReadTimeout = 2000;

        this.port.Open();

        this.port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
    }

    public void SendCommand(byte[] command)
    {
        this.port.Write(command,0,command.Length);
        string chars = "";
        foreach (byte charbyte in command) chars += (char)charbyte;
        Console.WriteLine(" -> " + chars);
    }

    void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        string data = this.port.ReadLine();
        Console.WriteLine(" <- " + data);
    }

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

byte[] {
    0x50,
    0x69,
    0x6E,
    0x67
}

Но, похоже, ничего не отправляется обратно.

Я понятия не имею, что делать дальше.Кто-нибудь получил какие-либо предложения?


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

  1. Программное обеспечение поставщиков - со всеми отфильтрованными IOCTL_SERIAL_GET_COMMSTATUS записями
  2. Моя попытка подняться

Ответы [ 4 ]

3 голосов
/ 11 апреля 2011

Каждое устройство RS-232 должно использовать какой-то механизм управления потоком , чтобы уведомить противоположную часть о продолжающейся связи.Существует три основных механизма:

  • аппаратный RTS / CTS по двум выделенным проводам, обычно используемый для управления отправкой отдельных фрагментов данных
  • аппаратный DTR / DSR по двум выделенным проводам, обычно используется для управления всем сеансом связи
  • на основе softwa XON / XOFF через пару выделенных символов (обратите внимание, чтов этом случае данные должны быть закодированы для предотвращения конфликтов с управляющими символами)

(запуск обновления)

Начальная длина очереди и время ожидания в устаревшем приложении:

1  IOCTL_SERIAL_SET_QUEUE_SIZE  InSize: 1024 OutSize: 1024
2  IOCTL_SERIAL_SET_TIMEOUT  RI:2000 RM:0 RC:2000 WM:0 WC:2000

пока вы их не установите.Попробуйте установить размеры очереди, используя SerialPort.WriteBufferSize и SerialPort.ReadBufferSize.Аналогичным образом установите время ожидания с помощью SerialPort.ReadTimeout и SerialPort.WriteTimeout.

(окончание обновления)

В вашем случаеУстаревшее приложение выполняет:

12  IOCTL_SERIAL_CLR_RTS
13  IOCTL_SERIAL_SET_DTR

, а вы:

12  IOCTL_SERIAL_CLR_RTS
13  IOCTL_SERIAL_CLR_DTR

Вы не устанавливаете сигнал DTR (Data Terminal Ready) и, следовательно, устройство не ожидает никаких данных или командна серийной линии.Следовательно, установите SerialPort.DtrEnable на true.

Вторая проблема - вы не включаете рукопожатие.Устаревшее приложение:

16  IOCTL_SERIAL_SET_HANDFLOW  Shake:1 Replace:0 XonLimit:0 XoffLimit:0
18  IOCTL_SERIAL_SET_RTS
…
21  IOCTL_SERIAL_CLR_RTS

, а вы:

16  IOCTL_SERIAL_SET_HANDFLOW  Shake:0 Replace:0 XonLimit:4096 XoffLimit:4096

Включите его, установив SerialPort.Handshake в Handshake.RequestToSend.

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

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

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

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


ОБНОВЛЕНИЕ: Отправка и получение данных.

Вы написали, что отправили команду 'Ping' (как расшифровано из шестнадцатеричного в ASCII).Однако вы не упоминаете последовательность отправки и завершения команды. Обычно последовательные устройства ожидают последовательность конца строки (обычно CR LF) в качестве завершения команды.До того как устройство получит команду complete , включая конец строки, оно не сможет ответить.

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

Хорошая идея - создать класс-обертку, который будет обеспечивать индивидуальные функции отправки, получения, ответа, отправки и получения данных.Оболочка должна будет работать асинхронно внутри по отношению к остальной части вашего кода.Таким образом, у вас будет удобный пользовательский API и хорошо управляемая обработка последовательного порта.

Обратите внимание, что свойство SerialPort.NewLine служит для указания того, как выглядит последовательность конца строки.(В другом своем вопросе вы упомянули, что пытались установить для него набор специальных символов. Это действительно было неправильно.)


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

Последнее, но не менее важное, некоторыеобщая терминология:

  • DTE - оконечное оборудование данных = ваш абонент
  • DCE - аппаратура передачи данных = ваше устройство, например модем
2 голосов
/ 31 марта 2011

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

1 голос
/ 31 марта 2011

Вам следует включить свойства RtsEnable или DtrEnable, устройство будет игнорировать все, что вы отправляете, и ничего не отправлять обратно, когда оно не обнаружит вас в сети по этим сигналам.Установка свойства Handshake для RTS должна была сделать это.

Остерегайтесь того, что метод ReadLine () будет блокироваться, пока не получит символ NewLine.Вы не отправляете один, поэтому вы не получите его обратно.Использование Read () было бы лучшим тестом.

Сначала выполните некоторые базовые действия по устранению неполадок с помощью известной в работе программы, устраняя проблемы с проводкой, неправильную скорость передачи данных или просто не возвращая устройство.Используйте HyperTerminal или Putty.

0 голосов
/ 12 апреля 2011

Том,

У меня были похожие проблемы,

Я собираюсь сделать ставку на тот факт, что ReadLine () возвращается только после получения\ r \ n или то, что, по мнению .NET, является новой строкой.

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

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

Так что дайте SerialPort.Readпопробуйте, прочитав 1 байт для начинающих,

public int Read (
byte[] buffer,
int offset,
int count

)

Если это не помогает, вы можете рассмотреть следующее

Некоторые изМои проблемы были исправлены с добавлением нескольких Thread.Sleep (), потому что я понял, что UART компьютера недостаточно быстрые, чтобы правильно передавать данные через порты RS232 / RS485, а также подождать несколько миллисекунд после открытия порта.

Я бы тоже советовал раСоздайте отдельный поток для обработки последовательных коммуникаций, вместо использования SerialDataReceivedEventHandler, создайте буфер отправки, который отправляется с правильными приращениями, не блокируя ваше приложение, также считывайте данные и добавляйте полученные байты в буфер, пока вы не получите достаточно данных.

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

Чтобы выявить проблему рукопожатия, протестируйте только с помощью PIN-кода.2,3 + PIN 5 (GND) подключен.

Надеюсь, это поможет

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