0% found this document useful (0 votes)
287 views16 pages

Welcome To My Tutorial On Serial Port Communication in VB

The document discusses serial port communication in VB.Net. It explains that older versions of VB required using the MSComm control, but .Net 2.0 introduced the SerialPort class within the System.IO.Ports namespace. This allows intrinsic serial communication without legacy controls. It then summarizes the code shown, including enumerations for transmission type and message type, variables for serial properties and communication, and properties and constructors for the CommManager class that manages serial functionality.

Uploaded by

leonar3177
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
287 views16 pages

Welcome To My Tutorial On Serial Port Communication in VB

The document discusses serial port communication in VB.Net. It explains that older versions of VB required using the MSComm control, but .Net 2.0 introduced the SerialPort class within the System.IO.Ports namespace. This allows intrinsic serial communication without legacy controls. It then summarizes the code shown, including enumerations for transmission type and message type, variables for serial properties and communication, and properties and constructors for the CommManager class that manages serial functionality.

Uploaded by

leonar3177
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 16

Welcome to my tutorial on Serial Port Communication in VB.Net.

Lately Ive seen a lot


of questions on how to send and receive data through a serial port, so I thought it was
time to write on the topic. Back in the days of Visual Basic 6.0, you had to use the
MSComm Control that was shipped with VB6, the only problem with this method was
you needed to make sure you included that control in your installation package, not
really that big of a deal. The control did exactly what was needed for the task.

We were then introduced to .Net 1.1, VB programmers loved the fact that Visual Basic
had finally evolved to an OO language. It was soon discovered that, with all it's OO
abilities, the ability to communicate via a serial port wasn't available, so once again VB
developers were forced to rely on the MSComm Control from previous versions of
Visual Basic, still not that big of a deal, but some were upset that an intrinsic way of
serial port communication wasn't offered with the .net Framework.

Then along comes .Net 2.0, and this time Microsoft added the System.IO.Ports
Namespace, and within that was the SerialPort Class. DotNet developers finally had an
intrinsic way of serial port communication, without having to deal with the complexities
of interoping with an old legacy ActiveX OCX control. One of the most useful methods
in the SerialPort class is the GetPortNames Method. This allows you to retrieve a list
of available ports (COM1,COM2,etc.) available for the computer the application is
running on.

Now that we have that out of the way, lets move on to programming our application. As
with all application I create, I keep functionality separated from presentation, I do this
by creating Manager classes that manage the functionality or a given process. What we
will be looking at is the code in my CommManager class. As with anything you write in
.Net you need to add the references to the Namespace's you'll be using:

1 Imports System
2 Imports System.Text
3 Imports System.Drawing
4 Imports System.IO.Ports
5 Imports System.Windows.Forms

In this application I wanted to give the user the option of what format they wanted to
send the message in, either string or binary, so we have an enumeration for that, and an
enumerations for the type of message i.e; Incoming, Outgoing, Error, etc. The main
purpose of this enumeration is for changing the color of the text displayed to the user
according to message type. Here are the enumerations:
01 #Region "Manager Enums"
02 ''' <summary>
03 ''' enumeration to hold our transmission types
04 ''' </summary>
05 Public Enum TransmissionType
06     Text
07     Hex
08 End Enum
09  
10 ''' <summary>
11 ''' enumeration to hold our message types
12 ''' </summary>
13 Public Enum MessageType
14     Incoming
15     Outgoing
16     Normal
17     Warning
18     [Error]
19 End Enum
20 #End Region

Next we have our variable list, 6 of them are for populating our class Properties, the
others are being access throughout the manager class so they are made Global. Things
are a bit different when sealing with delegates and how objects are access through
VB.Net than they are in C#, so in the VB.Net version there are 2 more properties, and
an extra Boolean variable used to determine if the buffer is to write the current data to
the serial port. Here are the variables needed for the manager class:
01 #Region "Manager Variables"
02 'property variables
03 Private _baudRate As String = String.Empty
04 Private _parity As String = String.Empty
05 Private _stopBits As String = String.Empty
06 Private _dataBits As String = String.Empty
07 Private _portName As String = String.Empty
08 Private _transType As TransmissionType
09 Private _displayWindow As RichTextBox
10 Private _msg As String
11 Private _type As MessageType
12 'global manager variables
Private MessageColor As Color() = {Color.Blue, Color.Green,
13
Color.Black, Color.Orange, Color.Red}
14 Private comPort As New SerialPort()
15 Private write As Boolean = True
16 #End Region
NOTE:I always separate my code into sections using the #region ... #end region to
make it easier when scanning my code. It is a design choice so it's not necessary if you
don't want to do it.

Now we need to create our class properties. All the properties in this class are public
read/write properties. As stated above we needed to add 2 additional properties for the
conversion from C# to VB.Net. We have properties for the following items:

 Baud Rate: A measure of the speed of serial communication, roughly


equivalent to bits per second.
 Parity: The even or odd quality of the number of 1's or 0's in a binary code,
often used to determine the integrity of data especially after transmission.
 Stop Bits: A bit that signals the end of a transmission unit
 Data Bits: The number of bits used to represent one character of data.
 Port Name: The port with which we're communicating through, i.e; COM1,
COM2, etc.
 MessageType: Outgoing, Incoming, Error, Warning, etc.
 Message: This is the actual message being sent through the serial port

We also have 4 properties that aren't related to the port itself, but with where the data
will be displayed, what transmission type to use, the message type, and the message
itself:

01 ''' <summary>
02 ''' property to hold the StopBits
03 ''' of our manager class
04 ''' </summary>
05 Public Property StopBits() As String
06     Get
07         Return _stopBits
08     End Get
09     Set(ByVal value As String)
10         _stopBits = value

11     End Set
12 End Property
13  
14 ''' <summary>
15 ''' property to hold the DataBits
16 ''' of our manager class

17 ''' </summary>
18 Public Property DataBits() As String
19     Get
20         Return _dataBits
21     End Get
22     Set(ByVal value As String)
23         _dataBits = value
24     End Set
25 End Property
26  
27 ''' <summary>
28 ''' property to hold the PortName
29 ''' of our manager class
30 ''' </summary>
31 Public Property PortName() As String
32     Get
33         Return _portName
34     End Get
35     Set(ByVal value As String)
36         _portName = value

37     End Set
38 End Property
39  
40 ''' <summary>
41 ''' property to hold our TransmissionType
42 ''' of our manager class

43 ''' </summary>
44 Public Property CurrentTransmissionType() As TransmissionType
45     Get
46         Return _transType
47     End Get
48     Set(ByVal value As TransmissionType)
49         _transType = value
50     End Set
51 End Property
52  
53 ''' <summary>
54 ''' property to hold our display window
55 ''' value
56 ''' </summary>
57 Public Property DisplayWindow() As RichTextBox
58     Get
59         Return _displayWindow
60     End Get
61     Set(ByVal value As RichTextBox)
62         _displayWindow = value

63     End Set
64 End Property
65  
66 ''' <summary>
67 ''' Property to hold the message being sent
68 ''' through the serial port

69 ''' </summary>
70 ''' <value></value>
71 ''' <returns></returns>
72 ''' <remarks></remarks>
73 Public Property Message() As String
74     Get
75         Return _msg
76     End Get
77     Set(ByVal value As String)
78         _msg = value

79     End Set
80 End Property
81  
82 ''' <summary>
83 ''' Message to hold the transmission type
84 ''' </summary>

85 ''' <value></value>
86 ''' <returns></returns>
87 ''' <remarks></remarks>
88 Public Property Type() As MessageType
89     Get
90         Return _type
91     End Get
92     Set(ByVal value As MessageType)
93         _type = value
94     End Set
95 End Property
96 #End Region

To be able to instantiate any class object we create we need Constructors. Constructors


are the entry point to your class, and is the first code executed when instantiating a class
object. We have 2 constructors for our manager class, one that sets our properties to a
specified value, and one that sets our properties to an empty value, thus initializing the
variables preventing a NullReferenceException from occurring. We also add an
EventHandler in the constructor, the event will be executed whenever there's data
waiting in the buffer:
01 #Region "Manager Properties"
02 ''' <summary>
03 ''' Property to hold the BaudRate
04 ''' of our manager class

05 ''' </summary>
06 Public Property BaudRate() As String
07     Get
08         Return _baudRate
09     End Get
10     Set(ByVal value As String)
11         _baudRate = value
12     End Set
13 End Property
14  
15 ''' <summary>
16 ''' property to hold the Parity
17 ''' of our manager class
18 ''' </summary>
19 Public Property Parity() As String
20     Get
21         Return _parity
22     End Get
23     Set(ByVal value As String)
24         _parity = value
25     End Set
26 End Property
27  
28 #Region "Manager Constructors"
29 ''' <summary>
30 ''' Constructor to set the properties of our Manager Class
31 ''' </summary>
32 ''' <param name="baud">Desired BaudRate</param>
33 ''' <param name="par">Desired Parity</param>
34 ''' <param name="sBits">Desired StopBits</param>
35 ''' <param name="dBits">Desired DataBits</param>
36 ''' <param name="name">Desired PortName</param>
Public Sub New(ByVal baud As String, ByVal par As String, ByVal sBits As
37
String, ByVal dBits As String, ByVal name As
38  
39 String, ByVal rtb As RichTextBox)
40     _baudRate = baud

41     _parity = par
42     _stopBits = sBits
43     _dataBits = dBits
44     _portName = name

45     _displayWindow = rtb
46     'now add an event handler
47     AddHandler comPort.DataReceived, AddressOf comPort_DataReceived
48 End Sub

49  
50 ''' <summary>
51 ''' Comstructor to set the properties of our
52 ''' serial port communicator to nothing

53 ''' </summary>
54 Public Sub New()
55     _baudRate = String.Empty
56     _parity = String.Empty
57     _stopBits = String.Empty
58     _dataBits = String.Empty
59     _portName = "COM1"
60     _displayWindow = Nothing
61     'add event handler
62     AddHandler comPort.DataReceived, AddressOf comPort_DataReceived
63 End Sub
64 #End Region

The first think you need to know about serial port communication is writing data to the
port. The first thing we do in our WriteData method is to check what transmission
mode the user has selected, since binary data needs to be converted into binary, then
back to string for displaying to the user. Next we need to make sure the port is open, for
this we use the IsOpen Property of the SerialPort Class. If the port isnt open we open it
by calling the Open Method of the SerialPort Class.

For writing to the port we use the Write Method. It is in this method we utilize the new
boolean variable, write to determine if we want to write the data.This is used to
handling byte transmission type when the data is in the incorrect format:

01 #Region "WriteData"
02 Public Sub WriteData(ByVal msg As String)
03 Select Case CurrentTransmissionType
04     Case TransmissionType.Text
05         'first make sure the port is open
06         'if its not open then open it
07         If Not (comPort.IsOpen = True) Then
08             comPort.Open()

09         End If
10         'send the message to the port
11         comPort.Write(msg)
12         'display the message
13         _type = MessageType.Outgoing
14         _msg = msg + "" + Environment.NewLine + ""
15         DisplayData(_type, _msg)
16         Exit Select
17     Case TransmissionType.Hex
18         Try

19             'convert the message to byte array


20             Dim newMsg As Byte() = HexToByte(msg)
21             'Determine if we are goint
22             'to write the byte data to the screen
23             If Not write Then
24                 DisplayData(_type, _msg)
25                 Exit Sub
26             End If

27             'send the message to the port


28             comPort.Write(newMsg, 0, newMsg.Length)
29             'convert back to hex and display
30             _type = MessageType.Outgoing
31             _msg = ByteToHex(newMsg) + "" + Environment.NewLine + ""
32             DisplayData(_type, _msg)
33         Catch ex As FormatException
34             'display error message
35             _type = MessageType.Error
36             _msg = ex.Message + "" + Environment.NewLine + ""
37             DisplayData(_type, _msg)
38         Finally
39             _displaywindow.SelectAll()
40         End Try
41         Exit Select
42     Case Else
43         'first make sure the port is open
44         'if its not open then open it
45         If Not (comPort.IsOpen = True) Then
46             comPort.Open()

47         End If
48         'send the message to the port
49         comPort.Write(msg)
50         'display the message
51         _type = MessageType.Outgoing
52         _msg = msg + "" + Environment.NewLine + ""
        DisplayData(MessageType.Outgoing, msg + "" +
53
Environment.NewLine + "")
54         Exit Select
55 End Select
56 End Sub
57 #End Region

You will notice in this method we call three methods:

 HexToByte
 ByteToHex
 DisplayData

These methods are required for this manager. The HexToByte method converts the data
provided to binary format, then the ByteToHex converts it back to hex format for
displaying. The last one, DisplayData is where we marshal a call to the thread that
created the control for displaying the data, since UI controls can only be accessed by the
thread that created them. First we'll look at converting the string provided to binary
format:
01 #Region "HexToByte"
02 ''' <summary>
03 ''' method to convert hex string into a byte array
04 ''' </summary>
05 ''' <param name="msg">string to convert</param>
06 ''' <returns>a byte array</returns>
07 Private Function HexToByte(ByVal msg As String) As Byte()
08     'Here we added an extra check to ensure the data
09     'was the proper length for converting to byte
10     If msg.Length Mod 2 = 0 Then
11         'remove any spaces from the string
12         _msg = msg

13         _msg = msg.Replace(" ", "")


14         'create a byte array the length of the
15         'divided by 2 (Hex is 2 characters in length)
16         Dim comBuffer As Byte() = New Byte(_msg.Length / 2 - 1) {}
17         For i As Integer = 0 To _msg.Length - 1 Step 2
            comBuffer(i / 2) =
18
CByte(Convert.ToByte(_msg.Substring(i, 2), 16))
19         Next
20         write = True
21         'loop through the length of the provided string
22         'convert each set of 2 characters to a byte
23         'and add to the array
24         'return the array
25         Return comBuffer
26     Else
27         'Message wasnt the proper length
28         'So we set the display message
29         _msg = "Invalid format"
30         _type = MessageType.Error
31         ' DisplayData(_Type, _msg)
32         'Set our boolean value to false
33         write = False
34         Return Nothing
35     End If
36 End Function
37 #End Region

Here we convert the provided string to a byte array, then the WriteData method sends
it out the port. For displaying we need to convert it back into string format, so we use
the ByteToHex method we created:
01 #Region "ByteToHex"
02 ''' <summary>
03 ''' method to convert a byte array into a hex string
04 ''' </summary>
05 ''' <param name="comByte">byte array to convert</param>
06 ''' <returns>a hex string</returns>
07 Private Function ByteToHex(ByVal comByte As Byte()) As String
08     'create a new StringBuilder object
09     Dim builder As New StringBuilder(comByte.Length * 3)
10     'loop through each byte in the array

11     For Each data As Byte In comByte


        builder.Append(Convert.ToString(data, 16).PadLeft(2,
12
"0"c).PadRight(3, " "c))
13         'convert the byte to a string and add to the stringbuilder
14     Next

15     'return the converted value


16     Return builder.ToString().ToUpper()
17 End Function
18 #End Region

The last method that WriteData depends on is the DisplayData method. Here we use
the Invoke Method of our RichTextBox, the control used to display the data, to create a
new EventHandler which creates a new Delegate for setting the properties we wish for
our message, then appending it to the value already displayed.
We had to change the format of the DisplayData method as VB.Net handles delegates
completely different than C#. Instead of putting the functionality of the delegate in the
method, we had to create a seperate method, then use the AddressOf Method to
reference the procedure that will act as our delegate:
01 #Region "DisplayData"
02 ''' <summary>
03 ''' Method to display the data to and
04 ''' from the port on the screen

05 ''' </summary>
06 ''' <remarks></remarks>
07 <STAThread()> _
08 Private Sub DisplayData(ByVal type As MessageType, ByVal msg As String)
09     _displaywindow.Invoke(New EventHandler(AddressOf DoDisplay))
10 End Sub
11 #End Region

NOTE: You will notice that we have added the STAThreadAttribute to our method.
This is used when a single thread apartment is required by a control, like the
RichTextBox.

Now we will look at our delegate method, which is responsible for setting all of the
properties of our display window,
which is a RichTextBox, as it has text formatting options not available to the regular
TextBox:

1 #Region "DoDisplay"
2 Private Sub DoDisplay(ByVal sender As Object, ByVal e As EventArgs)
3     _displaywindow.SelectedText = String.Empty
    _displaywindow.SelectionFont = New
4
Font(_displaywindow.SelectionFont, FontStyle.Bold)
    _displaywindow.SelectionColor = MessageColor(CType(_type,
5
Integer))
6     _displaywindow.AppendText(_msg)
7     _displaywindow.ScrollToCaret()
8 End Sub
9 #End Region

If you will read my tutorial on Serial Port Communication in C# you will see the same
exact functionality that is in the DisplayData method, except in VB.Net, as pointed out
earlier, requires the AddressOf Operator to reference a method to act as the
delegate.The next method we will look at it used when we need to open the port
initially. Here we set the BaudRate, Parity, StopBits, DataBits and PortName Properties
of the SerialPort Class:

01 #Region "OpenPort"
02 Public Function OpenPort() As Boolean
03     Try
04         'first check if the port is already open
05         'if its open then close it
06         If comPort.IsOpen = True Then
07             comPort.Close()
08         End If

09  
10         'set the properties of our SerialPort Object
11         comPort.BaudRate = Integer.Parse(_baudRate)
12         'BaudRate
13         comPort.DataBits = Integer.Parse(_dataBits)
14         'DataBits
        comPort.StopBits =
15
DirectCast([Enum].Parse(GetType(StopBits), _stopBits), StopBits)
16         'StopBits
        comPort.Parity = DirectCast([Enum].Parse(GetType(Parity),
17
_parity), Parity)
18         'Parity
19         comPort.PortName = _portName
20         'PortName
21         'now open the port
22         comPort.Open()

23         'display message
24         _type = MessageType.Normal
        _msg = "Port opened at " + DateTime.Now + "" +
25
Environment.NewLine + ""
26         DisplayData(_type, _msg)
27         'return true
28         Return True

29     Catch ex As Exception
30         DisplayData(MessageType.[Error], ex.Message)
31         Return False
32     End Try
33 End Function
34 #End Region

Now that we have opened our port for communication for sending data through, we
need to be able to close the port when we are finished without our application. Here we
simply call the Close Method of the SerialPort Object, which also disposes of the
internal stream being used for the data transmission:
01 #Region " ClosePort "
02 Public Sub ClosePort()
03     If comPort.IsOpen Then
        _msg = "Port closed at " + DateTime.Now + "" +
04
Environment.NewLine + ""
05         _type = MessageType.Normal
06         DisplayData(_type, _msg)
07         comPort.Close()
08     End If

09 End Sub
10 #End Region

Next lets take a look at our event handler. This event will be executed whenever there's
data waiting in the buffer. This method looks identical to our WriteData method,
because it has to do the same exact work:
01 #Region "comPort_DataReceived"
02 ''' <summary>
''' method that will be called when theres data waiting in the
03
buffer
04 ''' </summary>
05 ''' <param name="sender"></param>
06 ''' <param name="e"></param>
Private Sub comPort_DataReceived(ByVal sender As Object, ByVal e As
07
SerialDataReceivedEventArgs)
08     'determine the mode the user selected (binary/string)
09     Select Case CurrentTransmissionType
10         Case TransmissionType.Text

11             'user chose string


12             'read data waiting in the buffer
13             Dim msg As String = comPort.ReadExisting()
14             'display the data to the user
15             _type = MessageType.Incoming
16             _msg = msg
            DisplayData(MessageType.Incoming, msg + "" +
17
Environment.NewLine + "")
18             Exit Select
19         Case TransmissionType.Hex
20             'user chose binary

21             'retrieve number of bytes in the buffer


22             Dim bytes As Integer = comPort.BytesToRead
23             'create a byte array to hold the awaiting data
24             Dim comBuffer As Byte() = New Byte(bytes - 1) {}
25             'read the data and store it
26             comPort.Read(comBuffer, 0, bytes)
27             'display the data to the user
28             _type = MessageType.Incoming
            _msg = ByteToHex(comBuffer) + "" + Environment.NewLine +
29
""
            DisplayData(MessageType.Incoming, ByteToHex(comBuffer) +
30
"" + Environment.NewLine + "")
31             Exit Select
32         Case Else

33             'read data waiting in the buffer


34             Dim str As String = comPort.ReadExisting()
35             'display the data to the user
36             _type = MessageType.Incoming

37             _msg = str + "" + Environment.NewLine + ""


            DisplayData(MessageType.Incoming, str + "" +
38
Environment.NewLine + "")
39             Exit Select
40     End Select

41 End Sub
42 #End Region

We have 3 small methods left, and these are actually optional, for the lack of a better
word. These mthods are used to populate my ComboBoxe's on my UI with the port
names available on the computer, Parity values and Stop Bit values. The Parity and Stop
Bits are available in enumerations included with the .Net Framework 2.0:

 Parity Enumeration
 StopBits Enumeration
01 #Region "SetParityValues"
02 Public Sub SetParityValues(ByVal obj As Object)
03     For Each str As String In [Enum].GetNames(GetType(Parity))
04         DirectCast(obj, ComboBox).Items.Add(str)
05     Next
06 End Sub
07 #End Region
08  
09 #Region "SetStopBitValues"
10 Public Sub SetStopBitValues(ByVal obj As Object)
11     For Each str As String In [Enum].GetNames(GetType(StopBits))
12         DirectCast(obj, ComboBox).Items.Add(str)
13     Next
14 End Sub
15 #End Region
16  
17 #Region "SetPortNameValues"
18 Public Sub SetPortNameValues(ByVal obj As Object)
19  
20     For Each str As String In SerialPort.GetPortNames()
21         DirectCast(obj, ComboBox).Items.Add(str)
22     Next

23 End Sub
24 #End Region

That is how you do Serial Port Communication in VB.Net. Microsoft finally gave us
intrinsic tools to perform this task, no more relying on legacy objects. I am providing
this class and a sample application to show how to implement what we just learned.
What I am providing is under the GNU General Public License meaning you can
modify and distribute how you see fit, but the license header must stay in tact. I hope
you found this tutorial useful and informative, thatnk you for reading.

You might also like