Подтвердить что ты не робот

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

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

Можно ли написать подробную информацию о прочитать данные из последовательного порта?

4b9b3361

Ответ 1

SerialPort (последовательный COM-порт RS-232) в С#.NET
В этой статье объясняется, как использовать класс SerialPort в .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 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 buffer
      Console.WriteLine(port.ReadExisting());
    }
  }
}

Ответ 2

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

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

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

    • в одной руке у него нет времени для каких-либо данных и TimeoutException.
    • С другой стороны, когда какие-либо данные получили,
      • он получает данные либо до байтов maxLen
      • или короткий тайм-аут (теоретический 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

Ответ 3

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

Более того, вы можете использовать свойство SerialPort.BaseStream для извлечения базового экземпляра Stream. Преимущество использования 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.

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