Introduction
In case you ever wondered, my life is awesome. Yes, I am truly blessed to have a beautiful wife and beautiful daughter who love me. I am also truly blessed that I have a great, exciting, and an adventure of a job where I get to learn something strange or exciting every day! Today, I will share a bit of this experience with you, so that you don’t have to spend hours on Google, not knowing exactly what you should be looking for.
Today, I will demonstrate how easy it is (and yes, it is actually not too difficult) to create a program that reads data from a scale that is connected through an RS-232 serial port or USB to a serial port converter.
RS-232
RS-232 is a standard in telecommunications for the serial transmission of data. RS-232 defines the signals connecting between a data terminal such as a computer terminal and a data communication device, such as a modem. The RS-232 standard defines all the electrical characteristics of signals and timing of signals, the meaning of signals, and the physical size and pinout of connectors. The RS-232 standard is commonly used in computer serial ports. Wikipedia does a much better job of explaining the RS-232 standard than I can—after all, I am just a software guy. The little hardware-related stuff I once knew, I’ve forgotten….
Figure 1: RS-232 Port
You do get serial to USB converters nowadays that aid in communicating with any hardware from your PC. Here are a couple of links that can help you find the correct converter for your needs:
- http://www.usconverters.com/index.php?main_page=page&id=15
- http://www.aten.com/global/en/products/mobility-&-usb/usb-converters/uc232a/
Figure 2: USB to serial converter
I have written about ports and USBs before. I suggest you go through “Communicating Through USB Ports with Visual Basic” just to get some more background of what we will be doing today. This article recaps some of the most important information—for those of you who do not want to go through my old articles…
Now, you have a good understanding of what is available to you to communicate with a scale through your computer.
The Premise
You have to develop an app that communicates with a scale. This entails the following processes or events:
- Find out what type of scale you are dealing with.
- Find out whether or not the scale’s manufacturer provides some sort of manual or SDK or API. The reason for this is simple: If the manufacturer already supplies ways of communicating to their scale, it can save you a lot of research and development.
- Find out what operating system your application should operate on. Windows XP embedded differs quite a lot with Windows 8, for example. This is why it is pivotal knowing upfront what all the caveats will be.
- Find out how the scale will be connected to your computer. Will it be connected through a normal RS-232 serial port, or will it be connected through a USB-to-serial converter? If it is the latter, you might have to install a driver (which is usually supplied through the CD that accompanies the cable).
- Find out what type of information you need to extract from the scale and how the information gets sent whichever way.
This list may seem short, but it is absolutely critical to follow this small list. By following it, you will save a lot of time and you can start developing sooner.
Our Scale
The make and model of the scale I have used as an example for this article is Adam GFK 150. There is a handy manual that comes with the scale. Apart from all the technical jargon, the manual also contains all the settings for the scale.
These settings give you all your answers on how to configure your app to communicate properly with your scale. In case you don’t know or in case you’re about naïve, you require a bit of patience when it comes to changing a setting or two on a scale. It is very basic. There is only a few buttons to work with so you will find that you might end up a button several times to get access to a certain setting.
This Is What I Have Done
Keep “print” in for four seconds. This brings up the Print settings.
The “Print” settings include C1, C2, and C3. I don’t know what the ‘C’ represents…. Sorry.
To enter C1, C2, or C3 press “Func.”
To select a setting, press “Tare.”
The settings that you need to set are:
- C1 – On
- C2 – bd – 4800 (This is the baudrate)
- C3 – Print – Ct Sta
What will happen is that you will get a continuous flow of information from the scale. This information will include the weight of the product as well as the gross weight, etcetera.
The scale is now configured.
The Next Step
Connecting the scale is actually straightforward if it is connected through an ordinary RS-232 port. There is nothing special you have to do except to open a text editor to receive the information. On the other hand, if you are connecting through a USB-to-serial converter, you have to install the necessary drivers.
Installing the Drivers
The converter I am using an ATEN UC232A USB-to-RS232 serial port converter.
To install the drivers, follow these steps:
- Connect the two cables.
- Connect the cable to the PC.
- Insert the CD (I feel like Captain Obvious…)
- Open the “ReadMe” file. This file tells you exactly what folder you should look in and whichever platform for your Setup files.
- Open the “UC232A” Folder.
- Open the “Windows Series” Folder.
- Open the appropriate Windows Version Folder.
- Run Setup.exe.
If all goes well, the port should be installed as COM3. Knowing which port this is installed to is critical because you need to access and open this port to communicate with the scale. You can confirm this by opening your Device Manager and looking under the PORTS section.
Figure 3: Device Manager
Our Application
If you are still awake, we now can start with our small application.
Start Visual Studio and create a new Visual Basic Windows Forms project and add one textbox named txtData onto the form. Make the textbox big enough so that you can see the influx of data easier.
Add a New class and name it clsScale. Add the following Namespaces:
Imports System.Text Imports System.IO.Ports Imports System.Windows.Forms Imports System.Threading
You need these Namespaces because you are going to work with the computer’s ports, manipulate text, and create a thread to handle the information flow from the scale.
Now add the following Properties:
Private strBaudRate As String = "" Private strParity As String = "" Private strStopBits As String = "" Private strDataBits As String = "" Private strPortName As String = "" Public strData As String Public strDisplay As String Private mfMessageFormat As MessageFormat Public WithEvents comPort As New SerialPort() Public tbTextBoxDisplay As TextBox Public Property BaudRate() As String Get Return strBaudRate End Get Set(value As String) strBaudRate = value End Set End Property Public Property Parity() As String Get Return strParity End Get Set(value As String) strParity = value End Set End Property Public Property StopBits() As String Get Return strStopBits End Get Set(value As String) strStopBits = value End Set End Property Public Property DataBits() As String Get Return strDataBits End Get Set(value As String) strDataBits = value End Set End Property Public Property PortName() As String Get Return strPortName End Get Set(value As String) strPortName = value End Set End Property Public Property Format() As MessageFormat Get Return mfMessageFormat End Get Set(value As MessageFormat) mfMessageFormat = value End Set End Property Public Property TextWindow() As TextBox Get Return tbTextBoxDisplay End Get Set(value As TextBox) tbTextBoxDisplay = value End Set End Property Public Enum MessageFormat ASCII Hexadecimal End Enum
For the technical definitions on some of the unfamiliar terms, Wikipedia can always help. I have just created properties for this class. This makes it easier to use and to manipulate whichever scale property I need from my form.
Add the constructor:
Public Sub New() strBaudRate = "" strParity = "" strStopBits = "" strDataBits = "" strPortName = "COM3" tbTextBoxDisplay = Nothing comPort.DtrEnable = True comPort.ReadTimeout = 500 End Sub
Here, I set everything to its default starting value.
Open and close the port:
Public Function OpenPort() As Boolean Try If comPort.IsOpen = True Then comPort.Close() End If comPort.BaudRate = Integer.Parse(strBaudRate) comPort.DataBits = Integer.Parse(strDataBits) comPort.StopBits = DirectCast([Enum].Parse(GetType(StopBits), _ strStopBits), StopBits) comPort.Parity = DirectCast([Enum].Parse(GetType(Parity), _ strParity), Parity) comPort.PortName = strPortName comPort.Open() DisplayData("Port opened at " + DateTime.Now + vbLf) Return True Catch ex As Exception DisplayData(ex.Message) Return False End Try End Function Public Sub ClosePort() Try comPort.DtrEnable = False Thread.Sleep(500) RemoveHandler comPort.DataReceived, AddressOf _ comPort_DataReceived If comPort.IsOpen Then comPort.Close() End If Catch ex As Exception DisplayData(ex.Message) End Try End Sub
It determines if the port is open, then opens it, if needed, in the Open function. Now, we can receive information. Add the following:
Private Sub comPort_DataReceived(sender As Object, _ e As SerialDataReceivedEventArgs) Try Select Case Format Case MessageFormat.ASCII If comPort.IsOpen = True Then Dim msg As String = comPort.ReadLine() DisplayData(msg & Convert.ToString(vbLf)) Else Return End If Exit Select Case MessageFormat.Hexadecimal If comPort.IsOpen = True Then Dim bytes As Integer = comPort.BytesToRead Dim comBuffer As Byte() = New Byte(bytes - 1) {} comPort.Read(comBuffer, 0, bytes) DisplayData(ConvertByteToHex(comBuffer) & _ Convert.ToString(vbLf)) Else Return End If Exit Select Case Else If comPort.IsOpen = True Then Dim str As String = comPort.ReadLine() DisplayData(str & Convert.ToString(vbLf)) Else Return End If Exit Select End Select Catch ex As Exception Return End Try End Sub
This event determines in what format the messages are coming through. If it is in plain text (ASCII), it needs to read it properly, just as when the data is in Hexadecimal format, and display it properly inside the designated Textbox. Add the two Converting functions now:
Private Function ConvertHexToByte(strData As String) As Byte() strData = strData.Replace(" ", "") Dim comBuffer As Byte() = New Byte(strData.Length / 2 - 1) {} For i As Integer = 0 To strData.Length - 1 Step 2 comBuffer(i / 2) = CByte(Convert.ToByte _ (strData.Substring(i, 2), 16)) Next Return comBuffer End Function Public Function ConvertByteToHex(btData As Byte()) As String Dim builder As New StringBuilder(btData.Length * 3) For Each data As Byte In btData builder.Append(Convert.ToString(data, 16).PadLeft(2, _ "0"c).PadRight(3, " "c)) Next Return builder.ToString().ToUpper() End Function
Add the Display Sub now:
Private ReadOnly _sync As SynchronizationContext = _ SynchronizationContext.Current <STAThread> _ Public Sub DisplayData(strData As String) _sync.Send(Function(state) If strData.Contains("TEST") Then Dim arrSplit As String() arrSplit = strData.Split(vbCr & vbLf.ToCharArray()) For Each tmp As String In arrSplit If tmp.StartsWith("DATA") Then strData = tmp.ToString() strDisplay = strData End If Next If Not String.IsNullOrEmpty(strData) Then Dim strTemp As String = strData.TrimStart("TEST " _ .ToCharArray()).Trim() tbTextBoxDisplay.Text = strTemp End If Else tbTextBoxDisplay.Text = strData End If End Function, Nothing) End Sub
The preceding code segment is run on a separate thread; this helps in picking up the messages as they happen. A lot of string manipulation then gets done. It checks to see if a string with the text “TEST” exists; if it does, it breaks the string down further to find “DATA” and then just displays a little bit of information. Obviously, this is my logic for use in one of my apps, so you might end up looking for strings such as “Gross Wt” or “Kg“. It is all relative.
Add the last piece of code to Form 1:
Dim sScale As New clsScale() Private Sub Form1_Load(sender As Object, e As EventArgs) _ Handles MyBase.Load sScale.BaudRate = "4800" sScale.Parity = "0" sScale.StopBits = "1" sScale.DataBits = "8" sScale.PortName = "COM3" sScale.TextWindow = txtData sScale.OpenPort() End Sub
Conclusion
Knowing how to work with serial ports productively is a huge benefit in the working environment, and as you can see it is not that difficult.