SoFunction
Updated on 2025-03-07

Detailed explanation of reading and sending of C# serial port connection

1. Open and close the serial port connection

The serial port, that is, the COM port, is operated in .NET using the SerialPort class. Serial port opening and closing are IO operations involving slow hardware. Frequent opening or closing will affect the overall processing speed and may even lead to failure to open or close the serial port. In non-special cases, after the serial port is opened at one time, just close the serial port when exiting the program. Before opening the serial port, you can set some commonly used parameters. Commonly used parameters are as follows:

(1) Acceptance/send timeout time of the serial port: ReadTimeout/WriteTimeout.

(2) The accept/send buffer size of the serial port: ReadBufferSize/WriteBufferSize.

The specific code is as follows:

// Open Com
   _serialPort = new SerialPort(com, baud);
   if (_serialPort.IsOpen) _serialPort.Close();

   // Set the read / write timeouts
   _serialPort.ReadTimeout = 500;
   _serialPort.WriteTimeout = 500;

   // Set read / write buffer Size,the default of value is 1MB
   _serialPort.ReadBufferSize = 1024 * 1024;
   _serialPort.WriteBufferSize = 1024 * 1024;

   _serialPort.Open();

   // Discard Buffer
   _serialPort.DiscardInBuffer();
   _serialPort.DiscardOutBuffer();

It should be noted that the part beyond the buffer will be discarded directly. Therefore, if a large file is needed to be transmitted using the serial port, both the receiver and the sender need to set their respective buffer areas large enough to be able to store the binary array of the large file at one time. If the condition limits and the buffer area cannot be set too large, it is necessary to sub-package the sending buffer size when sending large files. The receiver combines the array in order to form a binary array of the accepting files.

2. Serial port sending

SerialPort class sending supports binary sending and text sending. It should be noted that when text sending, you need to know the conversion rules. Generally, ASCII, UTF7, UTF-8, UNICODE, and UTF32 are commonly used. The specific code is as follows:

#region Send
    /// <summary>
    /// Send a message (byte array)    /// </summary>
    /// <param name="buffer"></param>
    /// <param name="offset"></param>
    /// <param name="count"></param>
    public void Send(byte[] buffer, int offset, int count)
    {
      lock (_mux)
      {
        _serialPort.Write(buffer, offset, count);
        _sendCount += (count - offset);
      }
    }

    /// <summary>
    /// Send a message (string)    /// </summary>
    /// <param name="encoding">String encoding method, see <see cref="Encoding"/></param>    /// &lt;param name="message"&gt;&lt;/param&gt;
    public void Send(Encoding encoding , string message)
    {
      lock (_mux)
      {
        var buffer = (message);
        _serialPort.Write(buffer, 0, );
        _sendCount += ;
      }
    }
    #endregion

3. Serial port acceptance

Pay attention to serial port acceptance, message acceptance and message processing must be separated. The process-processed code cannot be placed in the information acceptance location because the message processing will be more or less time-consuming, which will cause the recipient's acceptance buffer to cache multiple messages when the sender sends it too quickly. We can put the received message into the queue, and then try to take out the message and consume it in an external thread. Adopt the "production-consumption" model. The specific code is as follows:

#region Receive
    private void PushMessage()
    {
      _serialPort.DataReceived += (sender, e) =&gt;
      {
        lock (_mux)
        {
          if (_serialPort.IsOpen == false) return;
          int length = _serialPort.BytesToRead;
          byte[] buffer = new byte[length];
          _serialPort.Read(buffer, 0, length);
          _receiveCount += length;
          _messageQueue.Enqueue(buffer);
          _messageWaitHandle.Set();
        }
      };
    }

    /// &lt;summary&gt;
    /// Get the content received by the serial port    /// &lt;/summary&gt;
    /// <param name="millisecondsToTimeout">Timeout for fetching the message</param>    /// <returns>Return byte array</returns>    public byte[] TryMessage(int millisecondsToTimeout = -1)
    {
      if (_messageQueue.TryDequeue(out var message))
      {
        return message;
      }

      if (_messageWaitHandle.WaitOne(millisecondsToTimeout))
      {
        if (_messageQueue.TryDequeue(out message))
        {
          return message;
        }
      }
      return default;
    }
    #endregion

4. Complete code and test results

The complete code of the serial port tool class is as follows:

using System;
using ;
using ;
using ;
using ;
using ;
using ;
using ;
using ;

namespace SerialportDemo
{
  public class SSerialPort
  {
    private SerialPort _serialPort;
    private readonly ConcurrentQueue&lt;byte[]&gt; _messageQueue;
    private readonly EventWaitHandle _messageWaitHandle;
    private int _receiveCount, _sendCount;
    private readonly object _mux;
    public int ReceiveCount
    {
      get =&gt; _receiveCount;
    }
    public  int SendCount
    {
      get =&gt; _sendCount;
    }
    public SSerialPort(string com, int baud )
    {
      // initialized
      _mux=new object();
      _receiveCount = 0;
      _sendCount = 0;
      _messageQueue = new ConcurrentQueue&lt;byte[]&gt;();
      _messageWaitHandle = new EventWaitHandle(false, );

      // Open Com
      OpenCom((),baud);

      // Receive byte
      PushMessage();
    }

    private void OpenCom(string com, int baud)
    {
      // Open Com
      _serialPort = new SerialPort(com, baud);
      if (_serialPort.IsOpen) _serialPort.Close();

      // Set the read / write timeouts
      _serialPort.ReadTimeout = 500;
      _serialPort.WriteTimeout = 500;

      // Set read / write buffer Size,the default of value is 1MB
      _serialPort.ReadBufferSize = 1024 * 1024;
      _serialPort.WriteBufferSize = 1024 * 1024;

      _serialPort.Open();

      // Discard Buffer
      _serialPort.DiscardInBuffer();
      _serialPort.DiscardOutBuffer();
    }


    #region Static
    /// &lt;summary&gt;
    /// Get an array of serial port names of the current computer    /// &lt;/summary&gt;
    /// &lt;returns&gt;&lt;/returns&gt;
    public static string[] GetPortNames()
    {
      return ();
    }
    #endregion

    #region Receive
    private void PushMessage()
    {
      _serialPort.DataReceived += (sender, e) =&gt;
      {
        lock (_mux)
        {
          if (_serialPort.IsOpen == false) return;
          int length = _serialPort.BytesToRead;
          byte[] buffer = new byte[length];
          _serialPort.Read(buffer, 0, length);
          _receiveCount += length;
          _messageQueue.Enqueue(buffer);
          _messageWaitHandle.Set();
        }
      };
    }

    /// &lt;summary&gt;
    /// Get the content received by the serial port    /// &lt;/summary&gt;
    /// <param name="millisecondsToTimeout">Timeout for fetching the message</param>    /// <returns>Return byte array</returns>    public byte[] TryMessage(int millisecondsToTimeout = -1)
    {
      if (_messageQueue.TryDequeue(out var message))
      {
        return message;
      }

      if (_messageWaitHandle.WaitOne(millisecondsToTimeout))
      {
        if (_messageQueue.TryDequeue(out message))
        {
          return message;
        }
      }
      return default;
    }
    #endregion


    #region Send
    /// &lt;summary&gt;
    /// Send a message (byte array)    /// &lt;/summary&gt;
    /// &lt;param name="buffer"&gt;&lt;/param&gt;
    /// &lt;param name="offset"&gt;&lt;/param&gt;
    /// &lt;param name="count"&gt;&lt;/param&gt;
    public void Send(byte[] buffer, int offset, int count)
    {
      lock (_mux)
      {
        _serialPort.Write(buffer, offset, count);
        _sendCount += (count - offset);
      }
    }

    /// &lt;summary&gt;
    /// Send a message (string)    /// &lt;/summary&gt;
    /// <param name="encoding">String encoding method, see <see cref="Encoding"/></param>    /// &lt;param name="message"&gt;&lt;/param&gt;
    public void Send(Encoding encoding , string message)
    {
      lock (_mux)
      {
        var buffer = (message);
        _serialPort.Write(buffer, 0, );
        _sendCount += ;
      }
    }
    #endregion

    /// &lt;summary&gt;
    /// Clear the total number of acceptance/send    /// &lt;/summary&gt;
    public void ClearCount()
    {
      lock (_mux)
      {
        _sendCount = 0;
        _receiveCount = 0;
      }
    }

    /// &lt;summary&gt;
    /// Close the serial port    /// &lt;/summary&gt;
    public void Close()
    {
      _serialPort.Close();
    }
  }
}

The test code is as follows:

class Program
  {
    static void Main(string[] args)
    {
      ($"List of serial ports that this computer can use:{(",", ())}");

      ("Please enter the serial port you need to open:");
      string port = ();
      SSerialPort com = new SSerialPort(port, 57600);
      ($"Serial port {port} Open successfully...");

      ("Please enter the message sent by the serial port you need to open:");
      string text = ();

      while (true)
      {
        (, text);
        ($"Sent in total {}");
        var message = ();
        if (message != null)
        {
          ($"{("HH:mm:ss fff")} {(message)}");

          //// TEST: From adding delay, it can be tested to accepting messages and processing messages must be processed by different threads.  Because the processing of messages requires more or less time, this can easily lead to untimely processing of messages.  After adding to the queue, we can take it out at any time to process it          //(100*1);
        }
        ($"Accepted in total {}");
      }


      ();
    }
  }

Tested using the serial port tool as follows, the acceptance of the serial port is as smooth as silky. When we add test delay to the message, we will find that when the serial port tool continues to send quickly for a period of time, it is found that after using the queue, no message from the sender is lost.

Summarize

This is the article about reading and sending C# serial port connection. For more related C# serial port connection reading and sending content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!