Visual Studio C#: работа с последовательным портом
Добавил(а) microsin
Эта статья показывает, как записывать и читать данные от устройства, подключенного к последовательному порту (COM-порт) из приложения на языке C# в среде .NET. Мы будем читать и записывать данные через TextBox на форме, и будем работать с потоками.
В недалеком прошлом для работы с Serial Port в среде .Net 1.1, мы должны были использовать либо Windows API, либо использовать управление из сторонних библиотек. В среде .Net 2.0 (и в более поздних версиях .NET) компания Microsoft добавила поддержку последовательного порта включением класса SerialPort как части пространства имен System.IO.Ports. Реализация класса SerialPort сделана очень прямо и очевидно. Чтобы создать экземпляр класса SerialPort class, просто передайте опции SerialPort конструктору класса:
// Все опции для последовательного устройства// ---- могут быть отправлены через конструктор класса SerialPort// ---- PortName = "COM1", Baud Rate = 19200, Parity = None,// ---- Data Bits = 8, Stop Bits = One, Handshake = None
SerialPort _serialPort = new SerialPort("COM1",
19200,
Parity.None,
8,
StopBits.One);
_serialPort.Handshake = Handshake.None;
Для приема данных нам нужно создать обработчик события EventHandler для "SerialDataReceivedEventHandler":
// "sp_DataReceived" является вручную созданным методом (подпрограммой)
_serialPort.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
Вы можете также установить другие опции, такие как ReadTimeout и WriteTimeout (таймауты чтения и записи):
Как только Вы готовы использовать последовательный порт, Вам нужно открыть его:
// Открытие последовательного порта
_serialPort.Open();
Сейчас мы готовы принять данные. Однако чтобы записать эти данные в область ввода TextBox на форме, нам нужно создать так называемого делегата (delegate). Библиотеки .Net не позволяют межпотоковое взаимодействие (cross-thread action), так что нам нужно использовать делегат. Делегат используется для записи в поток пользовательского интерфейса (User Interface, UI) из другого потока (не UI).
// Делегат используется для записи в UI control из потока не-UIprivatedelegatevoidSetTextDeleg(string text);
Мы создадим теперь метод "sp_DataReceived", который будет выполнен при поступлении данных в последовательный порт:
voidsp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(500);
string data = _serialPort.ReadLine();
// Привлечение делегата на потоке UI, и отправка данных, которые// были приняты привлеченным методом.// ---- Метод "si_DataReceived" будет выполнен в потоке UI,// который позволит заполнить текстовое поле TextBox.this.BeginInvoke(new SetTextDeleg(si_DataReceived),
newobject[] { data });
}
Мы можем теперь принять данные из последовательного порта от устройства и отобразить их на форме. Некоторые устройства отправляют данные сами, без запроса. Однако некоторым устройствам нужно отправить определенные команды, чтобы они ответили на них какими-то своими данными. Для этих устройств Вы будете записывать данные в последовательный порт, и будете использовать предыдущий код, чтобы получить данные обратно. В этом примере будет происходить обмен со шкалой. Для отдельной шкалы отправка команды "SI\r\n" приведет к возврату веса, который имеется на шкале. Эта команда является специфической именно для этого устройства, в Вашем же случае нужно читать документацию по протоколу устройства, чтобы найти команды, принимаемые устройством. Для записи в последовательный порт создайте кнопку "Start" на форме, и добавьте код в событие клика на ней Click_Event:
privatevoidbtnStart_Click(object sender, EventArgs e)
{
// Перед попыткой записи убедимся, что порт открыт.try
{
if(!(_serialPort.IsOpen))
_serialPort.Open();
_serialPort.Write("SI\r\n");
}
catch (Exception ex)
{
MessageBox.Show("Error opening/writing to serial port :: "
+ ex.Message, "Error!");
}
}
Это все, что нужно Вам сделать. См. ссылку [1] для загрузки готового проекта Microsoft Visual C# 2010.
В случае, когда нужно реализовать обмен с устройством, рассчитанным на взамодействие с пользователем (управляющая консоль). Так как пользователь вводит символы команды медленно, устройство успевает принять все символы и обработать. Если передавать символы быстро (методом SerialPort.Write), по несколько байт, то есть риск потери данных. Во врезке ниже приведен пример класса COMdevice, где реализован метод Write, который передает символы через задержку.
[Как перекодировать символы ANSI в UTF8]
Очень часть устройства на микроконтроллерах передают русские символы в кодировке ANSI (Windows-1251). Однако среда разработки Visual Studio C# хранит и обрабатывает русскоязычный текст в кодировке UTF8, и при попытке отобразить принятый текст (методом ReadExisting) выводятся кракозябры.
Решить проблему можно, если организовать байтовый буфер, и перекодировать массив байт с помощью класса Encoding (методом GetEncoding(1251).GetString). Пример кода в классе COMdevice приведен во врезке ниже.
[quote name="Владимир"]Не очень шарю в С/С++/С#. При запуске этого приложения выдает ошибку в textbox "Порт 'COM1' не существует." Всё подключено в порт COM4. В Вашем приложении не предлагается выбор портов в ComboBox1, список пуст. Подскажите в чем может быть проблема.
Добавьте в класс frmMain в строку 33, следующий код: comm.PortName = cboPort.SelectedItem.ToString(); Странно, что сделали выпадающий список, и не обработали его выбор.
Не очень шарю в С/С++/С#. При запуске этого приложения выдает ошибку в textbox "Порт 'COM1' не существует." Всё подключено в порт COM4. В Вашем приложении не предлагается выбор портов в ComboBox1, список пуст. Подскажите в чем может быть проблема. Спасибо заранее!
microsin: чтобы выпадающий список выбора COM-портов был непуст, заполните его во время выполнения приложения путем сканирования доступных в системе имен COM-портов (определить наличие порта в системе можно при попытке его открыть), либо заполните список вручную. Пункты в выпадающий список добавляются методом CommBox->Items->Add, см. документацию по API стандартных компонентов Microsoft.
Для чего в методе sp_DataReceived остановка потока Thread.Sleep(500);? Я правильно понимаю, что 500 мс не будут поступать данные из порта? Если да, то что нужно сделать, что бы не пропустить эти данные?
microsin: задержка с помощью Sleep делается для того, чтобы уступить время выполнения другим потокам. Это стандартное действие, без которого остальные приложения будут работать медленно. В течение этой задержки данные будут поступать в буфер драйвера, и задержка подбирается под отсутствие переполнения буфера - чтобы программа успела выбрать все пришедшие данные.
Скажите а чем ограничена вообще скорость такого COM порта?
microsin: для обычного COM-порта максимальная скорость обычно ограничена аппаратно на 115200 бод. Для класса USB CDC (виртуальный COM-порт) скорость ограничена возможностями драйвера.
Комментарии
Добавьте в класс frmMain в строку 33, следующий код:
comm.PortName = cboPort.SelectedItem.ToString();
Странно, что сделали выпадающий список, и не обработали его выбор.
comm.PortName = "COM4";
где вместо COM4 может быть имя вашего порта... и всё.
microsin: чтобы выпадающий список выбора COM-портов был непуст, заполните его во время выполнения приложения путем сканирования доступных в системе имен COM-портов (определить наличие порта в системе можно при попытке его открыть), либо заполните список вручную. Пункты в выпадающий список добавляются методом CommBox->Items->Add, см. документацию по API стандартных компонентов Microsoft.
Я правильно понимаю, что 500 мс не будут поступать данные из порта? Если да, то что нужно сделать, что бы не пропустить эти данные?
microsin: задержка с помощью Sleep делается для того, чтобы уступить время выполнения другим потокам. Это стандартное действие, без которого остальные приложения будут работать медленно. В течение этой задержки данные будут поступать в буфер драйвера, и задержка подбирается под отсутствие переполнения буфера - чтобы программа успела выбрать все пришедшие данные.
microsin: да, конечно, все это можно. Прогуглите C# SerialPort CTS RTS, информация доступна даже на русском языке.
microsin: для обычного COM-порта максимальная скорость обычно ограничена аппаратно на 115200 бод. Для класса USB CDC (виртуальный COM-порт) скорость ограничена возможностями драйвера.
RSS лента комментариев этой записи