Programming an RS-232 Scale with Visual Basic

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….

RS1
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:

RS2
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:

  1. Find out what type of scale you are dealing with.
  2. 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.
  3. 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.
  4. 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).
  5. 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:

  1. Connect the two cables.
  2. Connect the cable to the PC.
  3. Insert the CD (I feel like Captain Obvious…)
  4. Open the “ReadMe” file. This file tells you exactly what folder you should look in and whichever platform for your Setup files.
  5. Open the “UC232A” Folder.
  6. Open the “Windows Series” Folder.
  7. Open the appropriate Windows Version Folder.
  8. 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.

RS3
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.

Hannes DuPreez
Hannes DuPreez
Ockert J. du Preez is a passionate coder and always willing to learn. He has written hundreds of developer articles over the years detailing his programming quests and adventures. He has written the following books: Visual Studio 2019 In-Depth (BpB Publications) JavaScript for Gurus (BpB Publications) He was the Technical Editor for Professional C++, 5th Edition (Wiley) He was a Microsoft Most Valuable Professional for .NET (2008–2017).

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read