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> /// <param name="message"></param> 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) => { 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(); } }; } /// <summary> /// Get the content received by the serial port /// </summary> /// <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<byte[]> _messageQueue; private readonly EventWaitHandle _messageWaitHandle; private int _receiveCount, _sendCount; private readonly object _mux; public int ReceiveCount { get => _receiveCount; } public int SendCount { get => _sendCount; } public SSerialPort(string com, int baud ) { // initialized _mux=new object(); _receiveCount = 0; _sendCount = 0; _messageQueue = new ConcurrentQueue<byte[]>(); _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 /// <summary> /// Get an array of serial port names of the current computer /// </summary> /// <returns></returns> public static string[] GetPortNames() { return (); } #endregion #region Receive private void PushMessage() { _serialPort.DataReceived += (sender, e) => { 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(); } }; } /// <summary> /// Get the content received by the serial port /// </summary> /// <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 /// <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> /// <param name="message"></param> public void Send(Encoding encoding , string message) { lock (_mux) { var buffer = (message); _serialPort.Write(buffer, 0, ); _sendCount += ; } } #endregion /// <summary> /// Clear the total number of acceptance/send /// </summary> public void ClearCount() { lock (_mux) { _sendCount = 0; _receiveCount = 0; } } /// <summary> /// Close the serial port /// </summary> 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!