Click here to Skip to main content
15,868,141 members
Articles / Programming Languages / C#
Article

Serial Communication in .NET 2.0

Rate me:
Please Sign up or sign in to vote.
4.29/5 (30 votes)
25 Sep 20066 min read 208.6K   3.5K   107   58
Describes the use of a timer instead of using handshaking protocols.

Sample Image - SerialCommunication.jpg

Introduction

Whoever work with standard RS232 components from a .NET environment, and need real, embedded-like RS232 communication, realize in a short time that the component needs to be wrapped, or at least, additionally supported by custom software. I designed this tutorial because I couldn’t find something similar on the web. The code is an excerpt from a huge GPS tracking application, and it proved to work nicely. Just to mention, that there are other methods for RS232 communication such as using hand-shaking protocols, and hardware/software enabled pin control.

Background

I won’t go in to the details of basic RS232 communication, except that it is a point-to-point communication between two hosts, and they could be computers or embedded devices. My point here will be the software implementation part, using C# in a .NET 2.0 environment to be precise, but the principles are adoptable to any other language and IDE. Also, the type of data I’m going to send/read is string, but with little more effort, the code can be adopted to send/receive any type of serializable data. One more restriction, the demo code is adopted to receive a huge block of data and then process it. Another way is to continually append read data to some FIFO buffer, and do an online parsing of whatever data has arrived at the time (search for delimiters inside the arrived data before the reading ends), for continual receiving of data without any pause between two packets.

Methods used

We will need as few as the following four methods to do the job:

  • void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e);
  • private void ReadData(object s, EventArgs e);
  • private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e);
  • private void AddRecieve(object s, EventArgs e);

Using the code

The first thing we need for an RS232 communication is a SerialPort component from the Components tab in the form editor's toolbox. The component itself supports both synchronous and asynchronous (event driven) communication. That means, for reading the port, we can use:

1. Blocking methods

Wait for the hardware to do the job, and then return to the app, so the read operation waits until the reading is finished (a few methods give us different ways of reading the port).

2. Non-blocking methods

We don’t wait in a loop for reading the port, we use interrupts, so when the port has something in an input buffer, the SerialPort component alarms us via delegate methods, such as DataRecieved.

Here, we will use event driven communication, because in my belief, this is the only true RS232 robust communication. So, lets begin. Let’s create some private members for our form, like:

C#
private System.Timers.Timer timer1;
private StringBuilder recievedB = new StringBuilder();
private string recievedData;

Now, what we first need to do is a basic setup of the component we put on our form, meaning, set the component name (say, serialPort1), baudRate, parity, stopBits, etc. On the Events tab in Properties window, we create the delegate for DataRecieved (actually, the MVS will do that for us when we desire it), and name it serialPort1_DataReceived(). We will see later what we need the timer for. As for the recieveB, we use a StringBuilder class because it has a nice method Append, which doesn’t recreate the string every time we do a concatenation, rather it uses something like linking lists of strings (actually, you don’t have to know how it works). And finally, when all data has arrived, we will need a string to hold the received data needed for further parsing, recievedData. Next comes the coding of the delegate method we created. If we intend to update some controls in the form (as is the usual case), we need to call this.Invoke(some_delegate_method), because of the cross-thread operations. Check MSDN help for help on Invoke. We will create the method like this:

C#
private void serialPort1_DataReceived(object sender, 
        System.IO.Ports.SerialDataReceivedEventArgs e)
{
    this.Invoke(new EventHandler(AddRecieve));
}

And next, we need to create and code the actual delegate to perform the reading:

C#
private void AddRecieve(object s, EventArgs e)
{
    string st = serialPort1.ReadExisting();
    recievedB.Append(st);

    timer1.Interval = 1000; 
    timer1.Start();
}

Let’s comment this code a bit. First, we call ReadExisting, which means reading anything that is in the SerialPorts input buffer. There can be a few bytes, or as many as a few kilobytes of data. Anyway, we read what’s arrived up to now, and Append that to our main holder for the received data – the recieveB (the StringBuilder class instance).

Now, the second part of this method. How do we know that the other side of the communication link finished sending data, so we can process it? Think logically for yourselves… For those who figured it out, yes, we know this when for some time (predefined time) there is nothing to read, meaning the event serialPort1_DataRecieved() isn’t firing for some time. This time can vary from 30ms (arguable) up to a minute, it's up to us to decide. In this case, we’ll be using a one second interval so called deadTimePeriod (there is a term for a similar thing, called readTimeout). What do we do with this timer? We crate the timer in the form's constructor, add the onElapsed method for firing up when the time has elapsed, and, I prefer the garbage collector not to destroy my timer. On every firing of the serialPort1_DataReceived() event, we restart the timer1 to the initial interval (in our case 1s), and start it again. Here is the form's construction:

C#
public Form1()
{
    InitializeComponent();
    serialPort1.Open();
    timer1 = new System.Timers.Timer(1000);
    timer1.Elapsed += new System.Timers.ElapsedEventHandler(timer1_Elapsed);
    GC.KeepAlive(timer1);
}

The method that will execute on the timer overflow is called timer1_Elapsed. Following that, we will code the method as:

C#
void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    timer1.Stop();
    this.Invoke(new EventHandler(ReadData));
}

First, we stop the timer, and second, we do the final receiving of the data. And again, just in case, we call Invoke. The actual method for reading the received data and parsing it looks something like:

C#
private void ReadData(object s, EventArgs e)
{
    recievedData = recievedB.ToString();
    int j = recievedB.Length;

    if (recievedData.Contains("RMR0" /*some delimiting end*/))
    {
        labelCard.Text = "Read " + j.ToString() + " bytes...";
        // finally we have the data, we need to process it
        ProcessData();
    }
    else
    {
        DialogResult dr =  MessageBox.Show("Bad card data detected!," + 
                           " Read good data?", "Error!", 
                           MessageBoxButtons.YesNo, 
                           MessageBoxIcon.Error);
        if (dr == DialogResult.Yes)
        {

        }
    }
}

Of course, the method ProcessData() is open for you to code it. The send method is trivial, on buttonSend_Click, just send whatever you need - in this case, the text from textBoxSend. This could be done as an asynchronous method as well, using standard asynchronous method, invoking in .NET 2.0.

Points of Interest

Finally, I feel I need to explain the whole process again. The communication points are A and B. Both sides open their ports, and side B starts sending bytes over the comm. link. A serialPort1 component on side A is receiving data in almost a byte-by-byte basis, and is filling some sort of a buffer. The point here, was knowing when side B has sent us all data it wished to send in this transmission so side A can start examining the data in whole. Point A does this by using a timer which counts the time between two successive receiving of data packets from point B. When this time is, in our case, longer than 1s, point A knows that point B sent one whole packet. Well, this covers the basics of the non-handshaking protocol RS232 communication.

And again, of course, there are other port signals in RS232 such as CTS, RTS, which are also known as signals for implementing hand-shaking protocols, but we intend not to use them, because not every embedded system has a hand-shaking RS232 port enabled.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Chief Technology Officer Novotek
Serbia Serbia
Founder and CTO of Novotek, IT company for developing new technologies.
Former job as a CTO in MAXBet Serbia(www.maxbet.rs) for developing games (software, hardware, embedded, PLCs) and Information Systems for casino and sports betting.
Second, is the main love, and it is home/building automation, and a few projects for Spain market, involving building automation, remote sensing/centralized server and HVAC systems control.

Key interest: green energy, energy saving, HW embedded systems, RFID systems, acceleration sensors in 3D gaming applications, 3D TV
Main technologies: C# .NET, C++, DirectX, OpenGL, Android, Linux, Kernel and Android patching, SQL Server and ADO .Net, ASP .net, Ajax, Keil, PCad...

Comments and Discussions

 
Questionexporting data through an RS232 to a pc Pin
Member 107316647-Apr-14 14:02
Member 107316647-Apr-14 14:02 
GeneralMy vote of 5 Pin
Milind More5-Jul-10 1:18
Milind More5-Jul-10 1:18 
QuestionRS232 COMMUNICATION Pin
ranjithreddy4you1114-Apr-10 20:40
ranjithreddy4you1114-Apr-10 20:40 
GeneralrecievedData question Pin
chris_thanks15-Sep-09 23:47
chris_thanks15-Sep-09 23:47 
GeneralReading the weight data from Mettler ToleDo weighing machine via RS232 Pin
Arul Soosai19-Apr-09 22:47
Arul Soosai19-Apr-09 22:47 
Hi All,

I have written the code for reading data in textbox from serial port.
Its working.

But I need some idea how to do this way in checking weight(milligram) using Mettler Toledo weighing machine via RS232.

Please help and pass me the code or idea

Thanks in advance
GeneralRe: Reading the weight data from Mettler ToleDo weighing machine via RS232 Pin
sel200527-Nov-09 6:24
sel200527-Nov-09 6:24 
GeneralRe: Reading the weight data from Mettler ToleDo weighing machine via RS232 Pin
Dardo23-Feb-11 5:32
Dardo23-Feb-11 5:32 
GeneralRe: Reading the weight data from Mettler ToleDo weighing machine via RS232 Pin
mikepc27-Nov-09 8:22
mikepc27-Nov-09 8:22 
QuestionHow can i access the Serial Port of clients Machine Pin
Pandithan30-Mar-09 20:55
Pandithan30-Mar-09 20:55 
AnswerRe: How can i access the Serial Port of clients Machine Pin
mikepc27-Nov-09 8:27
mikepc27-Nov-09 8:27 
QuestionCan you help me? Pin
ycycn21-Jan-09 3:12
ycycn21-Jan-09 3:12 
AnswerRe: Can you help me? Pin
mikepc21-Jan-09 3:18
mikepc21-Jan-09 3:18 
GeneralRe: Can you help me? Pin
ycycn22-Jan-09 2:52
ycycn22-Jan-09 2:52 
GeneralUsing DataReceived Event Handler Pin
Dan Randolph27-Apr-08 17:33
Dan Randolph27-Apr-08 17:33 
GeneralRe: Using DataReceived Event Handler Pin
mikepc28-Apr-08 0:28
mikepc28-Apr-08 0:28 
Generalserial port problem Pin
mano_meee30-Mar-08 3:28
mano_meee30-Mar-08 3:28 
GeneralRe: serial port problem Pin
mikepc30-Mar-08 21:30
mikepc30-Mar-08 21:30 
GeneralRe: serial port problem Pin
mano_meee31-Mar-08 23:36
mano_meee31-Mar-08 23:36 
GeneralRe: serial port problem Pin
mikepc1-Apr-08 1:16
mikepc1-Apr-08 1:16 
GeneralRe: serial port problem Pin
mano_meee1-Apr-08 2:54
mano_meee1-Apr-08 2:54 
GeneralRe: serial port problem Pin
mikepc2-Apr-08 1:50
mikepc2-Apr-08 1:50 
GeneralRe: serial port problem Pin
mano_meee3-Apr-08 3:46
mano_meee3-Apr-08 3:46 
GeneralRe: serial port problem Pin
Member 21603171-May-08 16:55
Member 21603171-May-08 16:55 
GeneralRe: serial port problem Pin
mano_meee2-May-08 8:29
mano_meee2-May-08 8:29 
GeneralRe: serial port problem [modified] Pin
Member 21603174-May-08 16:01
Member 21603174-May-08 16:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.