How to Read and Write From the Serial Port in C#

Aimen Fatima Feb 02, 2024
  1. Serial Port
  2. Serial Port Chat Application Using C#
How to Read and Write From the Serial Port in C#

This tutorial will help you to understand the concept of the serial port in C# language and its use for data reading and writing. We will demonstrate the SerialPort class implemented in C# through an example project.

Serial Port

Our computer systems have several ports to transfer data for various purposes. The serial port is an interface to transfer data sequentially by transferring one-bit data at a time rather than sharing multiple bits in parallel.

Serial Port in C#

C# provides a built-in class to implement serial port functionality in your program. You can receive and send data to the device connected to your system’s serial port.

The namespace that implements the serial port class is System.IO.Ports.

You must import the System.IO.Ports namespace in your program and create an object of the static class SerialPort.

The SerialPort class provides a default constructor, and constructors are overloaded, requiring different parameters. Following is the example of initializing the object using default and one of the overloaded constructors.

The second line in the following code uses the overloaded constructor to initialize PortName, BaudRate, Parity, DataBits, and StopBits.

static SerialPort _serialPort = new SerialPort();
SerialPort _serialPort = new SerialPort("COM3", 9600, Parity.One, 8, StopBits.Two);

SerialPort class contains properties like BaudRate, BytesToWrite, BytesToRead, DataBits, Encoding, PortName, Parity, etc. Numerous public methods have been implemented to provide complete functionality for communication, e.g., Close(), GetPortNames(), Open(), Read(), Write(), etc.

Properties like ReadTimeOut and WriteTimeOut can also be set, like the following:

_serialPort.ReadTimeout = 1000;
_serialPort.WriteTimeout = 1000;

After setting all the required parameter values, we need to notify the compiler to open the port for communication using the Open() method.

_serialPort.Open();

The ReadLine() method can read the message received through the serial port.

string message = _serialPort.ReadLine();

Serial Port Chat Application Using C#

This section presents a complete C# program for a chat application that uses Serial Port for communication. This code snippet should be executed on both the connected systems to send and receive data.

Note: Use a null modem cable to connect the systems.

Create a C# project in Visual Studio, paste the code snippet into the Program.cs file, and execute it.

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

public class MyChatBot {
  static bool _resume;

  // Create a new SerialPort object
  static SerialPort _serialPortObj = new SerialPort();

  public static void Main() {
    string userName;
    string inputMessage;
    Thread read_Thread = new Thread(Read);
    StringComparer string_Comparer = StringComparer.OrdinalIgnoreCase;

    // Set the required attributes.
    _serialPortObj.PortName = SetPort(_serialPortObj.PortName);
    _serialPortObj.Parity = SetParity(_serialPortObj.Parity);

    _serialPortObj.StopBits = SetStopBits(_serialPortObj.StopBits);
    _serialPortObj.Handshake = SetHandshake(_serialPortObj.Handshake);

    // Set the read/write timeouts
    _serialPortObj.ReadTimeout = 1000;
    _serialPortObj.WriteTimeout = 1000;

    _serialPortObj.Open();
    _resume = true;
    read_Thread.Start();

    Console.Write("Enter Your Name: ");
    userName = Console.ReadLine();

    Console.WriteLine("Type Exit to exit");

    while (_resume) {
      inputMessage = Console.ReadLine();

      if (string_Comparer.Equals("exit", inputMessage)) {
        _resume = false;
      } else {
        _serialPortObj.WriteLine(String.Format("<{0}>: {1}", userName, inputMessage));
      }
    }

    read_Thread.Join();

    // Close the serial port
    _serialPortObj.Close();
  }

  public static void Read() {
    while (_resume) {
      try {
        // read the received message
        string _recerivedMessage = _serialPortObj.ReadLine();
        Console.WriteLine(_recerivedMessage);
      }

      catch (TimeoutException) {
      }
    }
  }

  // setters for attributes
  public static string SetPort(string defaultPortName) {
    string newPortName;

    Console.WriteLine("Available Ports:");
    foreach (string a in SerialPort.GetPortNames()) {
      Console.WriteLine("   {0}", a);
    }

    Console.Write("Enter COM port value (Default: {0}): ", defaultPortName);
    newPortName = Console.ReadLine();

    if (newPortName == "" || !(newPortName.ToLower()).StartsWith("com")) {
      newPortName = defaultPortName;
    }
    return newPortName;
  }

  public static Parity SetParity(Parity defaultParity) {
    string parityValue;

    Console.WriteLine("Available Parity Values:");
    foreach (string a in Enum.GetNames(typeof(Parity))) {
      Console.WriteLine("   {0}", a);
    }

    Console.Write("Enter Parity value (Default: {0}):", defaultParity.ToString(), true);
    parityValue = Console.ReadLine();

    if (parityValue == "") {
      parityValue = defaultParity.ToString();
    }

    return (Parity)Enum.Parse(typeof(Parity), parityValue, true);
  }

  public static StopBits SetStopBits(StopBits defaultStopBits) {
    string stopBitValue;

    Console.WriteLine("Available StopBits Values:");
    foreach (string a in Enum.GetNames(typeof(StopBits))) {
      Console.WriteLine("   {0}", a);
    }

    Console.Write(
        "Enter a StopBits value (ArgumentOutOfRangeException occurs for None value. Select another. \n (Default Value: {0}):",
        defaultStopBits.ToString());
    stopBitValue = Console.ReadLine();

    if (stopBitValue == "") {
      stopBitValue = defaultStopBits.ToString();
    }

    return (StopBits)Enum.Parse(typeof(StopBits), stopBitValue, true);
  }

  public static Handshake SetHandshake(Handshake defaultHandshake) {
    string handshakeValue;

    Console.WriteLine("Available Handshake Values:");
    foreach (string a in Enum.GetNames(typeof(Handshake))) {
      Console.WriteLine("   {0}", a);
    }

    Console.Write("Enter Handshake value (Default: {0}):", defaultHandshake.ToString());
    handshakeValue = Console.ReadLine();

    if (handshakeValue == "") {
      handshakeValue = defaultHandshake.ToString();
    }

    return (Handshake)Enum.Parse(typeof(Handshake), handshakeValue, true);
  }
}

The above code snippet first creates a SerialPort object and implements the setters to set optional attributes. The default values for BaudRate and DataBits are common, so they are not required to be set by the user.

The Read() function reads the input from the serial port. The program prompts the user to enter the input text and sends it to the serial port until the user enters exit as input.

The SetPort(), SetParity(), SetStopBits(), and SetHandshake() are setters to set the attributes values.

Output:

The user will be prompted to set the required values by selecting the available options, e.g., in the following output, we have chosen Com3, Parity value to be Odd, StopBits to be Two, and Handshake value to be None.

After setting the parameter values, the communication will start using the serial port until the user enters the exit to terminate the program.

Output for Chat App