Serial isn't just for... "How to Communicate with a Microcontroller or Other Serial Device in VB.Net"

Description

Today's project by Reed Kimble is so old school it's now new school. Experience of using Serial Port fell off a while ago (remember the last machine you had that even had a Serial Port on it?) yet using them is having a resurgence with the rise of microcontrollers.

And the fact he's done it in VB, my first dev love, is icing on the cake...

Introduction

With today's low-cost electronics and micro-manufacturing techniques the average electronics hobbyist has access to a plethora of powerful little microcontrollers (MCUs), along with a huge assortment of possible peripherals, and nearly all of these require a RS-232 serial interface to communicate with a PC. The accessibility and ease-of-use of VB.Net has made it an attractive platform for developing small purpose-driven applications meant to configure or otherwise communicate with these microcontrollers and microcontroller-based devices. However, as obvious a choice as the SerialPort component is, there are some common pitfalls to its use; and even though these pitfalls are explained in the documentation, a proper implementation of the component can still be elusive for some developers. This article will attempt to explain the common usage of the SerialPort component and offer a sample "SerialDevice" class which can be used to encapsulate the SerialPort component instance along with the data and logic associated with its usage.

Table of Contents

Microcontrollers (MCUs)

There are a few very popular hobby/prototyping MCU platforms, among them are Arduino, BasicStamp , and more recently mBed. But there are also many, many others out there. These typically range from 8-bit to 32-bit processors containing some amount of flash-memory used for storage and operating memory, as well as an array of peripherals such as Digital/Analog I/O, UARTs, I2C/SPI buses, etc. Most are inexpensive (<$100 USD) and several offer rich online communities and/or public code libraries. These devices are popular with electronics designers and hobbyists alike, and once you get past the initial introduction and setup they tend to be quite easy to work with.

Since these devices are popular with electronics designers and hobbyists and since Visual Basic .Net is free, easy to use, and well supported it is natural that people would attempt to write a VB app to configure or communicate with their MCU, having little or no programming experience at the outset. There are typically just a few requirements for this type of application; it needs to connect to the MCU on a serial port (often a USB virtual serial port) and then send and receive what are usually a small number of bytes representing a command with possible parameters and a command execution response. Sometimes the response is expected to contain a long sequence of byte data which will require further processing beyond a simple status result comparison, but most times the result will be a small number of bytes which decode to a status result or requested data value. Due to the nature of the SerialPort component and its multithreaded events the process of sending a command, reading a result, and then processing that result is not as intuitive as the methods of the SerialPort component might make it seem.

...

Serial Port Pitfalls

...

Using the SerialPort Component

...

"SerialDevice" Code Sample

The following code sample defines a SerialDevice class which encapsulates the SerialPort component and worker Task, along with the functionality outlined above. This class is meant to provide a lot of flexibility in usage and can benefit from performance improvements by redesigning it to fit a specific purpose. But as a general sample the performance should be adequate for most purposes. First we'll look at the code and then we'll go over the members in greater detail.

Code Description

The class begins by declaring the SerialPort component, then a thread-safe queue of bytes to use as the primary working data buffer, and finally the Task object along with the related CancellationTokenSource and ManualResetEvent needed to control the secondary thread's execution. ...

...

Usage Example

A common scenario when working with a MCU is to send a command to configure or interrogate the device. Many MCU's firmware will use a simple text-based protocol with all data transmitted in ASCII text and control codes implemented using ASCII format codes. Commonly the user only needs to look for a single character such as Carriage Return (CR) or Line Feed (LF) or Zero (0) to indicate the end of a response. To that end, we will build a simple program that allows us to build up a message from characters received from an MCU.

The following example will demonstrate the use of a SerialDevice instance in a Windows Forms Application. The example will use a RichTextBox as a console screen allowing the user to type in characters which are passed to the MCU connected on COM3 (the characters are not displayed in the RichTextBox as they are typed). The MCU then simply echos any received character back to the PC. The SerialDevice CheckMessageComplete delegate will look for a CR character (13) to determine when a message is complete and the ProcessMessage delegate will display the complete message in the RichTextBox. In this way, the program will buffer characters until the Enter key pressed and then the entire string will be written to the RichTextBox. Keep in mind though that each byte is passed through the MCU before being buffered by the SerialDevice for display in the RichTextBox.

Summary

With this design, the SerialDevice class offers a versatile framework for communicating with a MCU or other serial device regardless of the particular data protocol employed. A similar design could be used in a more purpose-specific way to more efficiently analyze and process the received data based on protocol-specifics unique to the application. That said, this class should still be suitable for many quick-and-simple MCU configuration and/or interrogation utilities.

The example also shows how to implement a SerialPort component, and the basic event handling routines could be used directly on a form without the encapsulating "SerialDevice" class. The SerialDevice class can be stripped apart into its constituent components in order to apply each concept to a another design.

Once you click through and read it all, you'll well be on the read to SerialPort Oneness.