Как читать и писать из последовательного порта

Я только начал изучать, как отправлять и получать данные от моего оборудования через графический интерфейс C #.

Кто-нибудь может написать подробно, как читать данные из последовательного порта?


person Community    schedule 07.08.2009    source источник
comment
возможный дубликат Управление последовательными портами в C #   -  person Peter O.    schedule 06.04.2013
comment
Наоборот: связанный пост является копией этого. Пожалуйста, используйте этот вопрос как канонический дубликат.   -  person Lundin    schedule 01.12.2015


Ответы (3)


SerialPort (последовательный COM-порт RS-232) в C # .NET
В этой статье объясняется, как использовать _ 1_ класс в .NET для чтения и записи данных, определить, какие последовательные порты доступны на вашем компьютере и как отправлять файлы. Он даже охватывает назначение контактов на самом порту.

Пример кода:

using System;
using System.IO.Ports;
using System.Windows.Forms;

namespace SerialPortExample
{
  class SerialPortProgram
  {
    // Create the serial port with basic settings
    private SerialPort port = new SerialPort("COM1",
      9600, Parity.None, 8, StopBits.One);

    [STAThread]
    static void Main(string[] args)
    { 
      // Instatiate this class
      new SerialPortProgram();
    }

    private SerialPortProgram()
    {
      Console.WriteLine("Incoming Data:");

      // Attach a method to be called when there
      // is data waiting in the port's buffer
      port.DataReceived += new 
        SerialDataReceivedEventHandler(port_DataReceived);

      // Begin communications
      port.Open();

      // Enter an application loop to keep this thread alive
      Application.Run();
    }

    private void port_DataReceived(object sender,
      SerialDataReceivedEventArgs e)
    {
      // Show all the incoming data in the port's buffer
      Console.WriteLine(port.ReadExisting());
    }
  }
}
person Robert Harvey    schedule 07.08.2009
comment
Привет, я пытаюсь сделать то же самое, но этот метод обработчика событий не вызывается! - person Prashant Pimpale; 01.03.2019
comment
@PrashantPimpale Удалось ли вам решить проблему? - person mrid; 29.08.2019
comment
@mrid Да! Я просто отключил устройство и выпил чашку чая, а затем начал! В противном случае проблема может быть в используемом коннекторе. - person Prashant Pimpale; 30.08.2019

Я потратил много времени на использование SerialPort и решил использовать SerialPort.BaseStream вместо этого. Вы можете увидеть исходный код: SerialPort -source и SerialPort. BaseStream-source для глубокого понимания. Я создал и использую код, показанный ниже.

  • Основная функция public int Recv(byte[] buffer, int maxLen) имеет имя и работает как recv() "хорошо известного" сокета.

  • Это означает, что

    • in one hand it has timeout for no any data and throws TimeoutException.
    • In other hand, when any data has received,
      • it receives data either until maxLen bytes
      • или короткий таймаут (теоретически 6 мс) в потоке данных UART

.

public class Uart : SerialPort

    {
        private int _receiveTimeout;

        public int ReceiveTimeout { get => _receiveTimeout; set => _receiveTimeout = value; }

        static private string ComPortName = "";

        /// <summary>
        /// It builds PortName using ComPortNum parameter and opens SerialPort.
        /// </summary>
        /// <param name="ComPortNum"></param>
        public Uart(int ComPortNum) : base()
        {
            base.BaudRate = 115200; // default value           
            _receiveTimeout = 2000;
            ComPortName = "COM" + ComPortNum;

            try
            {
                base.PortName = ComPortName;
                base.Open();
            }
            catch (UnauthorizedAccessException ex)
            {
                Console.WriteLine("Error: Port {0} is in use", ComPortName);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Uart exception: " + ex);
            }
        } //Uart()

        /// <summary>
        /// Private property returning positive only Environment.TickCount
        /// </summary>
        private int _tickCount { get => Environment.TickCount & Int32.MaxValue; }


        /// <summary>
        /// It uses SerialPort.BaseStream rather SerialPort functionality .
        /// It Receives up to maxLen number bytes of data, 
        /// Or throws TimeoutException if no any data arrived during ReceiveTimeout. 
        /// It works likes socket-recv routine (explanation in body).
        /// Returns:
        ///    totalReceived - bytes, 
        ///    TimeoutException,
        ///    -1 in non-ComPortNum Exception  
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="maxLen"></param>
        /// <returns></returns>
        public int Recv(byte[] buffer, int maxLen)
        {
            /// The routine works in "pseudo-blocking" mode. It cycles up to first 
            /// data received using BaseStream.ReadTimeout = TimeOutSpan (2 ms).
            /// If no any message received during ReceiveTimeout property, 
            /// the routine throws TimeoutException 
            /// In other hand, if any data has received, first no-data cycle
            /// causes to exit from routine.

            int TimeOutSpan = 2;
            // counts delay in TimeOutSpan-s after end of data to break receive
            int EndOfDataCnt;
            // pseudo-blocking timeout counter
            int TimeOutCnt = _tickCount + _receiveTimeout; 
            //number of currently received data bytes
            int justReceived = 0;
            //number of total received data bytes
            int totalReceived = 0;

            BaseStream.ReadTimeout = TimeOutSpan;
            //causes (2+1)*TimeOutSpan delay after end of data in UART stream
            EndOfDataCnt = 2;
            while (_tickCount < TimeOutCnt && EndOfDataCnt > 0)
            {
                try
                {
                    justReceived = 0; 
                    justReceived = base.BaseStream.Read(buffer, totalReceived, maxLen - totalReceived);
                    totalReceived += justReceived;

                    if (totalReceived >= maxLen)
                        break;
                }
                catch (TimeoutException)
                {
                    if (totalReceived > 0) 
                        EndOfDataCnt--;
                }
                catch (Exception ex)
                {                   
                    totalReceived = -1;
                    base.Close();
                    Console.WriteLine("Recv exception: " + ex);
                    break;
                }

            } //while
            if (totalReceived == 0)
            {              
                throw new TimeoutException();
            }
            else
            {               
                return totalReceived;
            }
        } // Recv()            
    } // Uart
person Yakov    schedule 08.01.2019
comment
Да, особенно ReadAsync намного удобнее. - person AyCe; 24.01.2020

Обратите внимание, что использование _ 1_ не является обязательным. Вы можете установить правильный тайм-аут с помощью SerialPort.ReadTimeout и непрерывно вызывать _ 3_ после того, как вы что-то написали в порт, пока не получите полный ответ.

Кроме того, вы можете использовать SerialPort.BaseStream для извлечения базового _ 5_ экземпляр. Преимущество использования Stream заключается в том, что вы можете легко использовать с ним различные декораторы:

var port = new SerialPort();
// LoggingStream inherits Stream, implements IDisposable, needen abstract methods and 
// overrides needen virtual methods. 
Stream portStream = new LoggingStream(port.BaseStream);
portStream.Write(...); // Logs write buffer.
portStream.Read(...); // Logs read buffer.

Для получения дополнительной информации проверьте:

person Leonid Vasilev    schedule 20.12.2018