Serial Port Communication in C#

By FoxLearn 1/8/2025 1:42:16 AM   165
The SerialPort class in C# enables communication with a serial port in .NET. This article demonstrates how to send and receive data through a serial port, displaying the received data in a TextBox using threading.

What is serial communication?

Serial communication, also known as RS232 communication, allows a microcontroller to interact with other devices through the RS232 protocol. For instance, a microcontroller can establish a connection with another microcontroller or a PC to exchange data using this serial communication protocol.

Communicate with Serial Port in C#

Prior to .NET 2.0, serial communication required third-party controls or the Windows API, but with .NET 2.0 and later, the SerialPort class in the System.IO.Ports namespace simplifies the process, allowing easy creation and configuration of serial port instances.

How to connect serial port in C#?

Creating a SerialPort object with SerialPort ComPort = new SerialPort(); will instantiate a serial port named ComPort with the following default parameters: 9600 bps baud rate, no parity, one stop bit, and no flow control.

For example:

// Configure all serial device options through the SerialPort constructor
// PortName = "COM1", BaudRate = 19200, Parity = None,
// DataBits = 8, StopBits = One, Handshake = None
SerialPort _serialPort = new SerialPort("COM1", 19200, Parity.None, 8, StopBits.One);
_serialPort.Handshake = Handshake.None; // Set Handshake to None

To receive data, we need to define an EventHandler for the SerialDataReceivedEventHandler:

// "sp_DataReceived" is a custom method created for handling data reception
_serialPort.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);

You can configure additional options, such as ReadTimeout and WriteTimeout:

// Set timeout values in milliseconds
_serialPort.ReadTimeout = 500;
_serialPort.WriteTimeout = 500;

When you're ready to use the serial port, you'll need to open it:

// Open the serial port
_serialPort.Open();

Now that we're ready to receive data, we need to create a delegate to write this data to a TextBox on the form. Since .NET doesn't allow cross-thread operations, the delegate will allow us to update the UI thread from a non-UI thread:

// Delegate to write to a UI control from a non-UI thread
private delegate void Send(string text);

Next, we'll create the sp_DataReceived method, which will be triggered when data is received through the serial port:

void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    Thread.Sleep(500);
    string data = _serialPort.ReadLine();
    // Invoke the delegate on the UI thread, passing the received data to the invoked method.
    // The "si_DataReceived" method will run on the UI thread, allowing the TextBox to be updated.
    this.BeginInvoke(new Send(si_DataReceived), new object[] { data });
}

Now, we define the si_DataReceived method:

private void si_DataReceived(string data) 
{
    textBox1.Text = data.Trim();
}

We can now receive data from a serial port device and display it on a form. Some devices send data automatically, while others require specific commands to receive a response.

For devices that need a command, you can send data to the serial port and use the previous code to retrieve the response.

By sending the command "SI\r\n", the scale will return the weight of the object on it. This command is specific to the scale, so be sure to consult your device’s documentation for the correct commands.

To send data to the serial port, I created a "Start" button on the form and added the following code to its Click event:

private void btnStart_Click(object sender, EventArgs e)
{
    // Ensure the serial port is open before attempting to write
    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!");
    }
}

How to receive data from com port in C#?

Here is the complete application that demonstrates how to receive data from a COM port in C#:

using System;
using System.IO.Ports;
using System.Threading;

// c# serial communication
public class SerialPortExample
{
    static bool _continue;
    static SerialPort _serialPort;

    public static void Main()
    {
        string name;
        string message;

        // Initialize SerialPort object
        _serialPort = new SerialPort
        {
            PortName = SetPortValue("COM port", _serialPort.PortName, SerialPort.GetPortNames),
            BaudRate = SetPortValue("Baud Rate", _serialPort.BaudRate.ToString()),
            Parity = (Parity)Enum.Parse(typeof(Parity), SetPortValue("Parity", _serialPort.Parity.ToString(), Enum.GetNames(typeof(Parity)))),
            DataBits = int.Parse(SetPortValue("Data Bits", _serialPort.DataBits.ToString())),
            StopBits = (StopBits)Enum.Parse(typeof(StopBits), SetPortValue("Stop Bits", _serialPort.StopBits.ToString(), Enum.GetNames(typeof(StopBits)))),
            Handshake = (Handshake)Enum.Parse(typeof(Handshake), SetPortValue("Handshake", _serialPort.Handshake.ToString(), Enum.GetNames(typeof(Handshake))))
        };

        // Set timeouts
        _serialPort.ReadTimeout = 500;
        _serialPort.WriteTimeout = 500;

        // Open serial port
        _serialPort.Open();
        _continue = true;
        
        Thread readThread = new Thread(Read);
        readThread.Start();

        // Get user name
        Console.Write("Name: ");
        name = Console.ReadLine();
        Console.WriteLine("Type QUIT to exit");

        // Communication loop
        while (_continue)
        {
            message = Console.ReadLine();
            if (message.Equals("quit", StringComparison.OrdinalIgnoreCase))
            {
                _continue = false;
            }
            else
            {
                _serialPort.WriteLine($"<{name}>: {message}");
            }
        }

        // Clean up
        readThread.Join();
        _serialPort.Close();
    }

    // Read data from serial port
    public static void Read()
    {
        while (_continue)
        {
            try
            {
                string message = _serialPort.ReadLine();
                Console.WriteLine(message);
            }
            catch (TimeoutException) { }
        }
    }

    // General method to set port parameters
    public static string SetPortValue(string label, string defaultValue, string[] validOptions = null)
    {
        string value;

        if (validOptions != null)
        {
            Console.WriteLine($"Available {label} options:");
            foreach (string option in validOptions)
            {
                Console.WriteLine($"   {option}");
            }
        }

        Console.Write($"{label}({defaultValue}): ");
        value = Console.ReadLine();

        return string.IsNullOrEmpty(value) ? defaultValue : value;
    }

    // General method for setting numeric values
    public static string SetPortValue(string label, string defaultValue)
    {
        string value;
        Console.Write($"{label}({defaultValue}): ");
        value = Console.ReadLine();

        if (string.IsNullOrEmpty(value)) return defaultValue;

        return value;
    }
}

This example demonstrates how to configure and communicate with a COM port in C#. It allows you to send and receive messages via a serial port, configure various settings like baud rate, data bits, and stop bits, and handle serial communication in a multithreaded environment.