Click here to Skip to main content
16,020,622 members
Articles / Desktop Programming / WPF

Serial Communication using WPF, RS232 and PIC Communication

Rate me:
Please Sign up or sign in to vote.
4.89/5 (31 votes)
24 Nov 2010CPOL7 min read 195.6K   28K   54   26
RS232 Communication from PC to a PIC using WPF

Introduction

This article will show you how to achieve Serial RS232 communication using WPF. Its overall layout and design is simple as the code is what I wished to focus on. In particular, there are key points such as the Dispatcher.Invoke method and the ASCII to HEX conversion that are key stumbling blocks in serial communication to PICs that I have addressed.

Assumed Knowledge

This article expects a developer to have a basic understanding of C# and WPF.

Background

I've spent the last 7 years of my life happily programming in C#. About 5 months ago, I decided to make the move to WPF and it's been an interesting journey. I'm an electrical engineer and spend a majority of my time making my computer talk to the outside world. I was working on a DMX project and decided to utilise a XAML interface in WPF rather than the boring limited C# forms.

So the idea behind it all is to have a WPF project talk to a PIC Micro controller. In C#, this is achieved by utilising System.IO.Ports; library and in WPF it's no different. However, there are some unique problems that any user from a C# background will encounter. This is the lack of an Invoke method, this is only slightly true as is hidden in there, however has been inherited by the Dispatcher Class.

Using the Code

The code is laid out very simply with little attention paid to naming conventions, etc. This will be addressed at a later date, however I wanted to get the basics out here so people can start using the code.

First, we will start of with the Interface. This is very basic and is simply a ComboBox's box for COM Port and Baud Rate a Textbox for Data to send and a Richtextbox to display the received data from the COMS Port with a few buttons for actions. I've not show the code for this as it can be download in the source and the layout is not important.

Basic Style

ScreenShot.JPG

Advanced Style

Screenshot2.JPG

XAML Data Provider

The first important factor is where the COM port Names and Baud rates come from. Now there are ways of getting the relevant data from the computer you are using but I wanted a little more control so I placed all the titles in an XML file called CommsData.xml. This data is provided by a "Data Provider" and each one is placed within the Windows.Resource element. The XPath determines which element I'm looking at and the x:Key is what I referenced in my code.

XML
<Window.Resources>
     <XmlDataProvider x:Key="ComPorts" Source="CommsData.xml" XPath="/Comms/Ports" />
     <XmlDataProvider x:Key="ComSpeed" Source="CommsData.xml" XPath="/Comms/Baud" />
 </Window.Resources>

To understand a little further, we need to examine the contents of CommsData.xml.

XML
<Comms>
  <Ports>COM1</Ports>
  <Baud>921600</Baud>
</Comms>

The <Comms> is my root element you can only have one of these in a data file. The <Ports> and <Baud> child elements separate the text so my data providers can only see what I want them to see. Each child element can have its own children; all you would have to do is set up the Data Providers correctly to show the data you want. If you want to format the way this data is presented, please search for the use of Data Templates.

The Data Providers are utilised by binding the ItemsSource properties of each ComboBox. Where below ComPorts is the x:Key I selected for my Data Provider:

XML
ItemsSource="{Binding Source={StaticResource ComPorts}}"

Setting up the Serial Port

There are two approaches to this in the C# environment - you can drag an element onto the form and edit its attributes or you could hard code it. In WPF, unfortunately you must hard code the Com Port, however this is very easy to do.

First, we must include a reference to the IO Port library:

C#
using System.IO.Ports;

Now, we can create a serial port. For ease, I have named this one serial however if you are utilising more ports, the naming convention should be changed.

C#
SerialPort serial = new SerialPort();

There are several properties of the serial port you can edit. This occurs within the source code when the Connect button is pressed, however could be set anywhere as long as it is done before the port is opened.

C#
serial.PortName = Comm_Port_Names.Text; //Com Port Name                
serial.BaudRate = Convert.ToInt32(Baud_Rates.Text); //COM Port Sp
serial.Handshake = System.IO.Ports.Handshake.None;
serial.Parity = Parity.None;
serial.DataBits = 8;
serial.StopBits = StopBits.One;
serial.ReadTimeout = 200;
serial.WriteTimeout = 50;

For information about these attributes, please see RS-232 communication protocol. These settings should satisfy a majority of applications, however there are two important attributes. ReadTimeout is the time allowed to read data received on the serial port. If this is set to low, then errors may occur and message can be cut short. WriteTimeout is the time allowed to write data out of the serial port - this can cause errors if you are trying to write long strings of data.

I have found no perfect formula for these values and a trial and error approach is necessary, bearing in mind that the greater the time allowed, the more delay your program will inherit.

Receiving Data

Now that we have a serial port, it important to set up a function call for every time the serial port has data to be read out. This is far more efficient that producing a thread, polling for data and waiting for a time out exception. To do this, we simply introduce the following code:

C#
serial.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(Recieve);

This will call the Recieve function every time data is received. Within this function, we read the data out to a String called recieved_data and then we Invoke a function to write this data to our form. To enable Invoke, we have to include:

C#
using System.Windows.Threading;
C#
private void Recieve(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    // Collecting the characters received to our 'buffer' (string).
    recieved_data = serial.ReadExisting();
    Dispatcher.Invoke(DispatcherPriority.Send, 
	new UpdateUiTextDelegate(WriteData), recieved_data);
}

Now in WPF, we have to use a Dispatcher.Invoke method. The purpose of this is quite simple, the main form is controlled by its own thread. When the serial port announces it has received data, a new thread is created to read this data out. The Invoke method allows the string of data to be passed from the serial data received thread to the form thread when it is possibly preventing any errors.

The data can be written to any control capable of displayed text. In this example, we display it via a RichTextbox. In WPF, you can only write a Flow Document to a RichTextbox so you must crate a Paragraph to write the data in and then add this Paragraph to the Flow Document before displaying it. More complicated than C#, however not impossible to work with.

C#
FlowDocument mcFlowDoc = new FlowDocument();
Paragraph para = new Paragraph();
C#
private void WriteData(string text)
{
    // Assign the value of the plot to the RichTextBox.
    para.Inlines.Add(text);
    mcFlowDoc.Blocks.Add(para);
    Commdata.Document = mcFlowDoc;
}

Sending Data

This is where things may change if you are communicating between computers, the protocol will change and you can send data using the standard serial.Write(string) method as in C#. However, if you are communicating to a P PIC micro-controller, you must convert the text to HEX bytes.

The text held with SerialData TextBox is sent to a SerialCmdSend function. This takes several steps in its encoding of the data string. The first is to check if the serial port is open serial.IsOpen. It's imperative to do so otherwise an error will be flagged. Within the try{} catch{} method is the encoding routine.

C#
using System.Threading;
C#
if (serial.IsOpen)
{
    try
    {
        // Send the binary data out the port
        byte[] hexstring = Encoding.ASCII.GetBytes(data);
        foreach (byte hexval in hexstring)
        {
            byte[] _hexval = new byte[] { hexval }; 	// need to convert byte 
						// to byte[] to write
            serial.Write(_hexval, 0, 1);
            Thread.Sleep(1);
        }
    }
    catch (Exception ex)
    {
        para.Inlines.Add("Failed to SEND" + data + "\n" + ex + "\n");
        mcFlowDoc.Blocks.Add(para);
        Commdata.Document = mcFlowDoc;
    }
}

Now it is important to understand what is occurring here and why. The first step is to convert the string hex values in a byte array. For example, "123" will become:

[1]-49 
[2]-50  
[3]-51

Now in computer to computer communication, this can be sent directly using:

C#
serial.Write(hexstring, 0, hexstring.length);

In PIC communication, however, there was a problem with this method. This may be apparent only when using higher Baud Rates but is caused by the computer timing issues as the computer will try and send the data continuously and the PIC will be overloaded. The program on the PIC will crash and need to be reset, in real world applications we can't have this.

The secret is to only send 1 byte at a time ensuring there is a delay in between bytes. The delay only has to be 1 millisecond however if this is not used the PIC will crash. This is done in the loop shown again below. The extra step within this loop to convert each byte to a byte array (byte[]) is annoyingly necessary as the serial.Write method utilised will only send a byte array.

C#
foreach (byte hexval in hexstring)
{
    byte[] _hexval = new byte[] { hexval }; // need to convert byte to byte[] to write
    serial.Write(_hexval, 0, 1);
    Thread.Sleep(1);
}

Finally, there you have it - a working WPF serial communication platform for RS-232 check back for a fully working release and a re-design using Microsoft Expression Blend.

History

  • Release V1.0 Basic style and source
  • Release V1.1 Advanced style and source

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer Manchester Metropolitan University
United Kingdom United Kingdom
I have a large amount of experience in image processing undertaking it as a major part of my PhD. As an assistant lecturer I have helped teach the subject mater at masters level and programming skills to undergraduates. I have a good grasp of the abilities of various image processing methods and an expertise in there practical application.

What makes my experience unique is the ability to design a high-specification machine vision system from principle up. Using my extensive knowledge of electronics to produce the custom electronics often required to help provide the best images possible. Such well designed systems assist image processing algorithms and increase their abilities. Additional expertise developed from my education focuses around software engineering, electronic engineering and practical skills developed in mechanical engineering. My PHD research has produced industry quality designs that surpass the ability of products currently available to end users with in-depth experience of Image processing, microcontrollers (PIC’s) and FPGA devices. I am also experience with the new range of development boards that are replacing traditional microcontroller programming methods.

Comments and Discussions

 
PraiseThank you so much! Pin
Coco_Yen11-Apr-23 21:40
Coco_Yen11-Apr-23 21:40 
QuestionDebugging issues Pin
Árni Ingason15-Jan-20 23:28
Árni Ingason15-Jan-20 23:28 
QuestionUart Communication validation Pin
Member 1297727022-Jan-19 21:21
Member 1297727022-Jan-19 21:21 
BugI am getting ? marks whaen there shouldn't be. Pin
aspriddell28-May-17 3:46
aspriddell28-May-17 3:46 
QuestionGreat work! Pin
Tobybar18-Oct-16 5:08
Tobybar18-Oct-16 5:08 
GeneralMy vote of 5 Pin
viler8410-May-16 13:39
viler8410-May-16 13:39 
Question..read data from two PICs Pin
All4Suri2-Nov-14 4:51
All4Suri2-Nov-14 4:51 
QuestionData Received Event Not fire Pin
azim070188-Dec-13 20:22
professionalazim070188-Dec-13 20:22 
AnswerRe: Data Received Event Not fire Pin
C_Johnson9-Dec-13 0:01
C_Johnson9-Dec-13 0:01 
GeneralRe: Data Received Event Not fire Pin
azim070189-Dec-13 7:47
professionalazim070189-Dec-13 7:47 
GeneralRe: Data Received Event Not fire Pin
C_Johnson9-Dec-13 9:53
C_Johnson9-Dec-13 9:53 
GeneralRe: Data Received Event Not fire Pin
azim070189-Dec-13 19:10
professionalazim070189-Dec-13 19:10 
Generalthank you Pin
Amir Behzadpour22-Aug-13 20:46
Amir Behzadpour22-Aug-13 20:46 
GeneralMy vote of 5 Pin
Thomas Rex11-Jul-13 4:14
Thomas Rex11-Jul-13 4:14 
GeneralMy vote of 5 Pin
Pjalle5-Feb-13 2:38
Pjalle5-Feb-13 2:38 
Questionabout 9-bit RS-232 Pin
Svetlin Parev30-Jan-12 22:24
Svetlin Parev30-Jan-12 22:24 
AnswerRe: about 9-bit RS-232 Pin
C_Johnson2-Feb-12 20:49
C_Johnson2-Feb-12 20:49 
Generalwork and simple Pin
bt_tnt4-Apr-11 7:50
bt_tnt4-Apr-11 7:50 
GeneralRe: work and simple Pin
C_Johnson6-Apr-11 21:55
C_Johnson6-Apr-11 21:55 
GeneralMy vote of 1 Pin
Adam Hamilton15-Feb-11 7:58
Adam Hamilton15-Feb-11 7:58 
GeneralRe: My vote of 1 Pin
C_Johnson28-Mar-11 9:04
C_Johnson28-Mar-11 9:04 
GeneralRe: My vote of 1 Pin
Amir Mahfoozi30-Sep-11 20:05
Amir Mahfoozi30-Sep-11 20:05 
GeneralRe: My vote of 1 Pin
C_Johnson1-Oct-11 7:44
C_Johnson1-Oct-11 7:44 
GeneralRe: My vote of 1 Pin
Deoye26-May-14 5:45
Deoye26-May-14 5:45 
GeneralUnable to download Pin
Stotty23-Nov-10 5:49
Stotty23-Nov-10 5:49 

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.