How to Work with Serial Port Communication in C#

By FoxLearn 12/25/2024 8:56:09 AM   46
In this tutorial, we’ll explore the basics of how to perform serial port communication within C# .NET applications.

Serial communication can be done through a physical serial port on a computer or via a USB-to-serial adapter if your computer lacks a serial port.

1. Detecting Available Serial Ports

Before starting communication, you first need to check which serial ports are available.

In a C# application, this can be done by accessing the system’s available serial ports.

public List<string> GetAllPorts()
{
    return new List<string>(System.IO.Ports.SerialPort.GetPortNames());
}

Alternatively, you can use a WMI query to retrieve the serial ports:

private List<ManagementObject> GetAllComPorts()
{
    using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_SerialPort"))
    {
        return searcher.Get().Cast<ManagementObject>().ToList();
    }
}

2. Opening and Closing Serial Ports

Once the available serial ports are detected, the next step is to open a port for communication. After data is transmitted or received, the port must be closed to free up system resources.

System.IO.Ports.SerialPort myPort = new System.IO.Ports.SerialPort("COM1");
if (!myPort.IsOpen)  // Check if port is not open
{
    myPort.Open();
}
// Perform communication tasks here
myPort.Close();

3. Sending and Receiving Data Through Serial Communication

Effective serial communication requires knowledge of the data your device expects and how to handle its responses.

Here’s an example showing how to send and receive data via the serial port in C#.

using System;
using System.Timers;

public class CommTimer
{
    private Timer _timer;
    public bool _timedOut { get; private set; }

    public CommTimer()
    {
        _timedOut = false;
        _timer = new Timer();
        _timer.AutoReset = false;
        _timer.Enabled = false;
        _timer.Elapsed += OnTimedCommEvent;
    }

    private void OnTimedCommEvent(object sender, ElapsedEventArgs e)
    {
        _timedOut = true;
        _timer.Stop();
    }

    public void Start(double timeoutPeriod)
    {
        _timer.Interval = timeoutPeriod; // Timeout in milliseconds
        _timedOut = false;
        _timer.Start();
    }

    public void Stop()
    {
        _timer.Stop();
        _timedOut = true;
    }

    public void Dispose()
    {
        _timer?.Dispose();
    }
}

public void SendReceiveData()
{
    byte[] cmdByteArray = new byte[1];
    
    // Reset buffers and prepare the serial port
    SerialObj.DiscardInBuffer();
    SerialObj.DiscardOutBuffer();

    // Send command
    cmdByteArray[0] = 0x7a; // Example command
    SerialObj.Write(cmdByteArray, 0, 1);

    using (CommTimer tmrComm = new CommTimer())
    {
        tmrComm.Start(4000); // Set timeout to 4 seconds

        // Wait for data or timeout (non-blocking)
        while (SerialObj.BytesToRead == 0 && !tmrComm._timedOut)
        {
            System.Threading.Thread.Sleep(10); // Briefly wait, yielding control to the CPU
        }

        if (SerialObj.BytesToRead > 0)
        {
            byte[] inbyte = new byte[1];
            SerialObj.Read(inbyte, 0, 1);
            if (inbyte.Length > 0)
            {
                byte value = inbyte[0];
                // Process the received value as needed
            }
        }
    }

    // Clean up and close serial port
    SerialObj.DiscardInBuffer();
    SerialObj.DiscardOutBuffer();
    SerialObj.Close();
}

In this example, we first discard any existing data in the input/output buffers. Then, a byte array is written to the serial port, representing a command (in this case, 0x7a). After sending the data, we set a timer to wait for a response, allowing up to 4 seconds for the device to reply. If a response is received, we process the data accordingly.