SerialPort (RS-232 Serial COM Port) in C#   .NET
  This article is about communicating through the PC's Serial COM  RS-232 port using Microsoft .NET 2.0 or later by using the  System.IO.Ports.SerialPort class.
 Way in  the Past...
 Back in my early (pre C# MVP) days, I had  written an article on DevHood  titled Serial   COM Simply in C#. It became quite popular and is (currently) the   top Google search for "serial  c#".  Now every week I get several e-mails with people asking  questions and  it is high time for some serious updating.
 The article was (originally) written soon after .NET was introduced  to the world, and other .NET serial port controls had not yet been  written. So at the time, this was an easy solution. Just use the  MSComm.ocx control from VS6 which most Devs had at the time. Now  however, there are many easier and preferred methods than dealing with  the complexities of interoping with an old legacy (non-.NET) ActiveX OCX  control.
  
 A Bright Future is  Here!
 Today, the primary solution is to use the new SerialPort  control that is part of .NET 2.0 and is freely available in C# Express on MSDN. It  is considerably easier to use and is a true .NET component.
  For loyal fans of  the tutorial, I've written a sample  code application, SerialPortTerminal.zip,  which you can try out to see how the new SerialPort control is used.  Requires Visual Studio 2005 & .NET 2.0 or later to compile &  run.
 For loyal fans of  the tutorial, I've written a sample  code application, SerialPortTerminal.zip,  which you can try out to see how the new SerialPort control is used.  Requires Visual Studio 2005 & .NET 2.0 or later to compile &  run.
  
 Continued Support
 Due to the high volume  of e-mail I've been receiving on serial port  communication in general,  I've wrote this post and added an FAQ   section to the bottom of the post.  Check this first if you have  questions.  If you post a question as a comment that hasn't been  answered in the post, I'll add it to the FAQ section. 
 For those of you who I've directed to this blog post, please  understand that I'm just another guy working away at a full time job  (helping manage the release of Team  System) who  has worked with serial RS-232 ports in the past (moving on to USB now). I  like to help people, hence I wrote the original article, this sample  code, and the FAQ, but do not have the resources to answer additional  serial port communication questions. Please check out the SerialCom   FAQ for other .NET COM Port solutions and technical support   options.
  
 Get Connected Up
 You can obtain USB to Serial  adapters (from NewEgg,   search using Froogle)   and have just about as many ports on your PC as you like. I carry   around two adapters with a null modem (what is  it?,  search Froogle)  between them so I can create a loopback to send & receive through  to separate ports on most any computer. I'd recommend doing the same for  when writing code for the serial port.
 If you'd like to  quickly and easily create your own external devices  to communicate with  the PC, I recommend starting with the Parallax  BASIC Stamp modules.  Parallax has lots of easy accessories  (such as LCDs, RF, Sounds, AD & DA, etc) for their modules. After   that you could migrate to an Atmel  Microcontroller  (recommended) or Microchip  PIC.
  
 Let's Have the Code
 Here is an example of  how easy it is to use the new SerialPort  control.
 Very simply,  here is how you can send a bit of data out the port.
  
    | // This is a new namespace in .NET 2.0 // that contains the SerialPort classusing System.IO.Ports;
 
 private static void SendSampleData()
 {
 // Instantiate the communications
   // port with some basic settingsSerialPort port = new SerialPort(
     "COM1", 9600, Parity.None, 8, StopBits.One);
 // Open the port for communications
 port.Open();
 
 // Write a string
 port.Write("Hello World");
 
 // Write a set of bytes
 port.Write(new byte[] {0x0A, 0xE2, 0xFF}, 0, 3);
 
 // Close the port
 port.Close();
 }
 | 
  
 
 Now let's take a look at what it takes to read data in from the  communications port. This demonstrates reading text; for an example of  reading binary data, see my SerialPortTerminal.zip  sample app.
 - Create a new "Console Application" and  replace all the default  class code with this code 
- Add a  reference to "System.Windows.Forms" to the project 
- Run w/ F5,  to exit the app, press Ctrl-Break. 
- Get   Connected Up with two USB to Serial adapters and a null modem 
- Use  another app, the code above, or the SerialPortTerminal.zip  example to send data and watch it come in with this code 
  
    | #region Namespace Inclusionsusing System;
 using System.IO.Ports;
 using System.Windows.Forms;
 #endregion
 
 namespace SerialPortExample
 {
 class SerialPortProgram
 {
 // Create the serial port with basic settings
 private SerialPort port = new SerialPort("COM1",
 9600, Parity.None, 8, StopBits.One);
 
 [STAThread]
 static void Main(string[] args)
 {
 // Instatiate this class
 new SerialPortProgram();
 }
 
 private SerialPortProgram()
 {
 Console.WriteLine("Incoming Data:");
 
 // Attach a method to be called when there
       // is data waiting in the port's bufferport.DataReceived += new
         SerialDataReceivedEventHandler(port_DataReceived);
 // Begin communications
 port.Open();
 
 // Enter an application loop to keep this thread alive
 Application.Run();
 }
 
 private void port_DataReceived(object sender,
       SerialDataReceivedEventArgs e){
 // Show all the incoming data in the port's buffer
 Console.WriteLine(port.ReadExisting());
 }
 }
 }
 | 
  
 
 One of the (several) new methods that is supported, and one I'm very  glad is finally here, is the ability to obtain a list of the COM ports  installed on the computer (ex: COM1, COM2, COM4). This is definately  helpful when you want to present the list of ports avalible for the user  to select from (as in the SerialPortTerminal.zip  Win App example).
  
    | foreach (string s in SerialPort.GetPortNames())System.Diagnostics.Trace.WriteLine(s);
 | 
  
 
 Here are two helpful little methods for sending files through the  serial port. Of course, these are the bare essentials and as always, you  should check to make sure the port is open first (port.IsOpen) and use  try/catch around trying to open a file, but you get the gist with this  code. The binary sending routine is limited to about 2GB (the size of an  int), but this should be okay for most uses. 
  
    | using System.IO;
 private static void SendTextFile(
   SerialPort port, string FileName){ port.Write(File.OpenText(FileName).ReadToEnd()); }
 
 private static void SendBinaryFile(
   SerialPort port, string FileName){
 using (FileStream fs = File.OpenRead(FileName))
 port.Write((new BinaryReader(fs)).ReadBytes(
       (int)fs.Length), 0, (int)fs.Length);}
 | 
  
 
 
 RS-232 Project Photos
 Each of these involve RS-232 serial port communications.
    |  | 
  | Just what's needed to get started with   microcontrollers, a Basic Stamp, mini LCD display, power,  and RS-232 port.
 | 
  
 
    |  | 
  | Two USB to Serial adapters with a null modem to loopback and test your serial software.
 | 
  
 
    |  | 
  | The brains to a mini automated radio station  that  let me control my PC & home using my HAM radio from  around  town.
 | 
  
 
 
Port Wiring Notes
 DB9 Male (Pin Side)                   DB9 Female (Pin Side)
DB9 Female (Solder Side)              DB9 Male (Solder Side)
   -------------                          -------------
   \ 1 2 3 4 5 /                          \ 5 4 3 2 1 /
    \ 6 7 8 9 /                            \ 9 8 7 6 /
     ---------                              ---------
DB9 Female to DB9 Female Null-Modem Wiring
2 |  3 |  7 |  8 | 6&1|  5 |  4
---- ---- ---- ---- ---- ---- ----
3 |  2 |  8 |  7 |  4 |  5 | 6&1
9-pin   25-pin  Assignment                 From PC
------  ------  -------------------------  ------------
Sheild  1       Case Ground                Gnd
1       8       DCD (Data Carrier Detect)  Input
2       3       RX  (Receive Data)         Input
3       2       TX  (Transmit Data)        Output
4       20      DTR (Data Terminal Ready)  Output
5       7       GND (Signal Ground)        Gnd
6       6       DSR (Data Set Ready)       Input
7       4       RTS (Request To Send)      Output
8       5       CTS (Clear To Send)        Input
9       22      RI  (Ring Indicator)       Input
- RTS & DTR are binary outputs that can be manually set and held
- DCD, DSR, CTS, and RI are binary inputs that can be read
- RX & TX can not be set manually and are controlled by the UART
- maximum voltages are between -15 volts and +15 volts
- binary outputs are between +5 to +15 volts and -5 to -15 volts
- binary inputs are between +3 to +15 volts and -3 to -15 volts
- input voltages between -3 to +3 are undefined while output voltages
 between -5 and +5 are undefined
- positive voltages indicate ON or SPACE, negative voltages indicate
 OFF or MARK
 
 Other Resources
 Here are some additional sites, libraries, tutorials, etc. These are  links that I just found around the net and am providing for convenience  (they are not endorsed).
  Where CF = Compact Framework
  
 The Final Say (aka Conclusion)
 The new SerialPort class in .NET 2.0 rocks! It is much easier to use  than getting the old MSComm.ocx control going in a .NET app, contains  new functionality, is a 'native' .NET control, has docs built into the  MSDN Library, and is easy to use.
  
 Frequently Asked  Questions (FAQ)
 I'm adding this section (as of 8/10/06) to address the common  questions I get on this post and through e-mail.  Chances are, if you  ask a good question in the comments here, I'll post it here for others  to see easily.
 - Q: When updating a control (like a text box) while in  the  DataRecieved event, I get an error.       
 A: The SerialPort  class raises events on a separate thread than the main form was create  on.  Windows Forms controls must be modified only on their original  thread.  Thankfully there is an easy way to do this.  Each Windows  control has a "Invoke" method which will run code on the control's  original thread.  So to put the recently received data into a text box  (txtLog), this would do it:   txtLog.Invoke(new EventHandler(delegate {  txtLog.Text += comport.ReadExisting(); });   You can see this more in  action in the "Log" event of "Terminal.cs" my sample code project, SerialPortTerminal.zip.
- Q: I can't find the System.IO.Ports  namespace.       
 A:  Using Visual Studio 2003?  The new namespace, and SerialPort class, is  part of .NET 2.0 and Visual Studio 2005.  It is not included in .NET 1.x  (and Visual Studio 2003).  Even if you have .NET 2.0 or Visual Studio  2005 installed, you can not access the class from within Visual Studio  2003.
- Q: I only have .NET 1.1, what can I  do?       
 A:  Upgrade to .NET 2.0.  Seriously, it's free.  In fact, you can get the  great C# and VB Visual Studio Interactive Development Environment (IDE)  editors for FREE now with C#   Express and VB  Express.   The .NET   2.0 Software Development Kit (SDK) for command-line development is   also free.  If you really must stay in .NET 1.1, you can use the   technique I talk about in Serial   COM Simply in C# or a 3rd party library.
- Q: I'm sending data to my device, but it is  not responding.
 A:  First make sure the device will respond using a standard app like  Hyperterminal.  Check the settings (baud rate, data bits, stop bits,  etc) and make sure they match with your code.  Try sending binary data  via binary arrays.  Many devices expect a carriage return at the end of a  command, so be sure to send 0x0D or \n.  String data can be easily  converted to a binary array using:
 byte[] data =   System.Text.ASCIIEncoding.Default.GetBytes("Hello World\n");
 com.Write(data,  0, data.Length);
 Many devices require several carriage  returns first to sync baud rates, so send several, like:  com.Output("".PadLeft(9, '\n'));  It you're communicating with a modem,  make sure Echo Back is turned on.  Send "ATE1\n".  Other than this, just  keep trying and playing around with it.  It can be hard because you  don't see the response from the device as easily as you would with a  terminal app.
- Q:  When I put received data to a text box or rich text box, I  get a strange  symbols.       
 A: The default font of text boxes  is designed only to show standard characters.  Try using "CharMap" (a  free tool in WinXP, click "Start", "Run", type "CharMap", enter).   "Terminal" is a font designed to show classic ASCII characters and is  what most terminal apps (like my sample code and Hyperterminal) use.   There are also many ASCII codes that won't display correctly.  This is  why I choose to show the hex data instead of an ASCII string a lot of  the time.  System.Convert.ToString(mybyte, 16) will convert a byte to a  string hex code, for example: byte b = 13; string s =  Convert.ToStrong(b, 16).PadLeft(2, '0'), then s will contain "0D".  See  the "ByteArrayToHexString" and "HexStringToByteArray" methods in my  sample app, SerialPortTerminal.zip.
- Q: What about USB communications?  How can I  do USB?
 This  post isn't about USB.  Believe me, I wish the .NET framework supported  USB natively, and I'm doing what I can here at Microsoft to see USB get  into the framework in the future.  For now, you can use a USB   to Serial adapter.  I use a lot of these.  They plug into the USB  port, then appear just as a SerialPort to the PC.  Microcontroller  vendors such as Microchip, Atmel,  and TI  make chips that do this for projects.  There is a lot of info on USB and C#  out there too (such as this great  article).
- Q: Can I use the sample code here in my own  projects (commercial  or not)?
 Yes!  All sample code on my blog is free public domain  material.  I'm not a legal guy so I don't know the exact words to use,  but I'll try...  I'm not responsible for any problems!  Use at your own  rick etc.  However, have at it, if it helps you out, fantastic, that's  what it's here for.
- Q: When using SerialPort.Open() (or  SerialPort.PortOpen = true) I  get the exception  "UnauthorizedAccessException" or the error "An  unhandled  exception of type  'System.Runtime.InteropServices.COMException' occurred  in  axinterop.mscommlib.dll"
 It may be one of a few factors:
 - It may require Administrative  privileges to use the port. 
- The port may already be open by  another program, only one app can  use a port at a time. 
- The port may not exist on the computer (this happens a lot).  Verify  the port you're trying to open is listed in the Device Manager (FAQ  #9). 
- The  name being provided is not exactly correct.         
 Use  the full name of the port when opening, like "COM1" (not  "1")
 
- Q: How do I know what COM ports are on my PC?
 Use the  Device Manager ("Start", "Run", "devmgmt.msc") and look  for the "Ports"  node (see below).  If you don't see a Ports node, it's because  there are not Serial or Parallel ports installed in the PC.  Many  laptops these day's don't have a serial port.  You can get more serial  ports very easily today with USB   to Serial adapters.
 
   
- Q: How do I communicate with my specific  device?  Modem, Mobile  Phone, LED/LCD Display, Scanner, etc       
 This post is  specific to general, device independent, serial port communications.   You will need to find information about the protocol used for your  specific device elsewhere.  Comments that ask about specific devices  will be deleted (to reduce spam).  I'd recommend looking on the  manufacture's website, writing/calling the manufacture, or searching  online for your specific device, like "Motorola Razor Serial Protocol".
- Q: What pins can I use for  powering devices, a high signal, or  for boolean input & output?       
 The TX & RX pins  carry the standard serial signal, but the other pins can be used as  high/low input/output pins.  The output pins (4 DTR or 8 CTS), supply 5  to 15 volts (15v is proper RS-232 standard) when high and 0 to -15 volts  when low.  They only supply flea current so they're not meant to be  used for powering any devices (like USB is designed for).  However, they  can be used as a reference voltage or for switching to one of the input  pins for a high or low signal.  The input pins (1 DCD, 6 DSR, 8 CTS,  and 9 RI) can be used to detect a high or low signal.  Proper RS-232  signal levels are -15v for a low and +15v for a high (compared to  ground, pin 5).  A MAX232  or similar chip takes a TTL 0-5v input and produces the -15v to +15v  levels.  However, most PC RS-232 COM ports will accept a 0v for low and  5v for high, but it is not guaranteed and alters from PC to PC.  If you  want a simple "toggle high", just hold pin 4 DTR high, and switch it to  pin 1 DCD.  The .NET SerialPort class has easy to use properties for  switching the output pins high or low and for detecting the current  level of the input pins.  I have been able to use pin 4 DTR for a very  low current (20ma max) PIC processors, but not reliably.  I prefer to  always supply external power and use pin 4 as a signal to turn on or off  my device.  I'll attach pin 4 to a transistor that switches my power  source to my PIC to turn it on or off.
- Q:  What about ‘packets’?  Does RS-232 support any commands or  data  segregation?       
 No.  Serial data flow through RS-232  has nothing to do with ‘packets’. It’s just a stream of bytes in and  out. Any notion of data compartmentalization (packets) would have to be  coded by you for your unique use.  Much of my time working with serial  has been spent on defining useful packet like protocols, that usually  include some type of header, command structure, and CRC check.  For  example, the first two bytes are the packet length, the next two bytes  is the command, next two bytes are parameters, and the last byte is a  CRC.  Then my apps would buffer incoming data and look in the buffer for  valid packets.  Of course it differs depending on the device you’re  working with and your specific needs.  USB does have specific  communications protocol defined, one of them being command based, like  the little packet just mentioned.  But with USB, you’re able to get the  whole command and parameter together at once, with serial you have to  create the protocol yourself, buffer, and parse the data.  My previous   serial post has more info under the header “Protocol Development”.
- Q: How do you detect when a device is  connected or disconnected?        
 Simply put, the device usually start or stop sending  data.  There is no built in events on a connect or disconnect.  But  there are a few tricks you can do, if you’re creating the serial device  you have more options.  I’ve had my devices (and PC apps) send a  constant “are you there” set of bytes, like 00 00 11 11 00 00 hex (I’d  use a ‘are you there’ custom ‘packet’ as in Q12 above) till a device on  the other end responds.  You could also use hardware, that’s what some  of the other signals lines are for (CDC, DSR, RTS, CTS, RI), you can tie  one of these high and then catch an event when the line goes high you  know there’s a device there, when it goes low the device is gone.
- Q:  How can I get more support?  What are my support options?