This article discusses the demo programme included with the ArduinoSerialClass library described in Part 2 which itself connects with devices running the a standard Arduino Sketch Framework described in Part 1
The demo programme simply illustrates techniques for using the ArduinoSerialClass Library DLL. This allows an application to connect to a board and automatically discover what values and status information it is returning and what specific commands it will respond to.
If you happen to have a number of boards all doing different things with different sensors and output devices this enables you to have a generic application which will communicate correctly with any of the boards.
For example you many have several different units which are all capable of, amongst other things, reporting the current temperature. Using the standard framework and by making each version report the temperature in the same format you can have an application which will read the temerature from any of the boards.
Using the code
The code bundled with this article is the same as in Part 2. Here we are going to describe how the Demo application uses the ArduinoSerialClassLibrary.
To recap the library has two objects -
DetectArduinoClass has a constructor, one public method and one property.
New(String) takes an optional String parameter "target" which will be the start of the full name of the port(s) to find. The target defaults to "Arduino".
New() scans the Management Objects looking for serial ports whose name matches the target.
PortList is a Dictionary(Of String, String) which will contain a list of all of the ports that match the target name. The short name will be the key (eg COM23) and the full name will be the definition value (eg "Arduino Leonardo (COM23)")
Rescan(String, Boolean) searches the management objects again. The string parameter is again optional as the target name to find, and the boolean parameter if true will clear the existing port list before rescanning.
ArduinoSerialClass is slightly more complex. As well as a constructor
New(String) it has two methods
OutputPins are all Dictionary(Of String,String). The keys are the identifiers used for particular items and the definitions are the descriptions or, in the case of
Status, the actual values for the particular item.
ValDesc will have the same keys, as will
Turning to the demo program TestApp, it is found as a separate project in the code file consists of a single windows form.
On the left is a panel headed "Available Devices". This simply shows the PortList property from a
DetectArduinoClass object on form load.
Dim det As New DetectArduinoClass()
If det.PortList.Count > 0 Then
Dim ypos As Integer = 100
For Each item In det.PortList
Dim lbl As New Label
lbl.Name = item.Key
lbl.Top = ypos
lbl.AutoSize = True
lbl.Left = 20
lbl.Text = item.Key & " = " & item.Value
ypos += 20
In a full application we would probably create a connect button against each item so that we could choose which device to connect to. For now we'll simply connect to the first one found.
Private WithEvents ard As ArduinoSerialClass
ard = New ArduinoSerialClass(det.PortList.Keys(0))
On the right of the screen we have panels to show the capabilities of the connected board and display its current status values and any dynamic values that are being reported.
When we create the new object
ArduinoSerialClass(portname) if the serial port can be opened it immediately requests all the descriptions and status information. This may take a few moments to be updated so we will fire off a timer to give the board time to respond and then interrogate the information returned in the object.
ard = New ArduinoSerialClass(det.PortList.Keys(0))
Private Sub tmrChk_Tick(sender As Object, e As EventArgs) Handles tmrChk.Tick
If ard.PortFound Then
lblConnected.Text = ard.ComPortName
lblConnected.BackColor = Color.Green
grpDeviceInfo.Visible = True
grpSktechCmds.Visible = True
grpValues.Visible = True
lblConnected.Text = "Not Connected"
lblConnected.BackColor = Color.Red
grpDeviceInfo.Visible = False
grpSktechCmds.Visible = False
grpValues.Visible = False
So if the ard object reports that it has connected to the port we can now update the status on the screen
The firmware and hardware info is all in property
txtStatus.Text = "Unit Name: " & ard.FStatus.UnitID & vbCrLf
txtStatus.Text &= "Firmware: " & ard.FStatus.Sketch & vbCrLf
txtStatus.Text &= "Ver: " & ard.FStatus.Ver & " "
txtStatus.Text &= " " & ard.FStatus.CompDate & vbCrLf
txtStatus.Text &= "Author: " & ard.FStatus.Author
The system status which is common to all boards using the framework is in properties
txtSystemStatus.Text = "Serial values out = " & IIf(ard.SendSerialEnabled,"ON", "OFF") & vbcrlf
If ard.SendSerialEnabled Then
btnEnableLoop.Text = "Enable Serial Out"
btnEnableLoop.BackColor = Color.LightPink
btnEnableLoop.Text = "Disable Serial Out"
btnEnableLoop.BackColor = Color.LightGreen
txtSystemStatus.Text &= "Arduino Loop Time = " & ard.LoopTime & " ms"
If ard.LoopTime >= numLoop.Minimum Then
numLoop.Value = ard.LoopTime
numLoop.Value = numLoop.minimum
We can also have controls to set those properties. In both cases after setting the property we fire off tmrChk again so that it can update any changes once they have been actioned.
Private Sub btnEnableLoop_Click(sender As Object, e As EventArgs) Handles btnEnableLoop.Click
If ard.PortFound Then
ard.SendSerialEnabled = Not ard.SendSerialEnabled
Private Sub btnLoop_Click(sender As Object, e As EventArgs) Handles btnLoop.Click
If ard.PortFound Then
ard.LoopTime = numLoop.Value
numLoop.Value = 999
For the various descriptors - commands, inputs and outputs, we can just update a text box to list them
txtSketchCmds.Text = ard.Cmds.Count & " Commands reported" & vbcrlf
For Each cmd In ard.Cmds
txtSketchCmds.Text &= cmd.Key & " " & cmd.Value & vbCrLf
and similarly for the others. To send a command to the unit we have simply provided a textbox to enter the required string and a button to send it. We could dynamically create a separate button and parameter box for each command.
For the unit status and values, we want to read the descriptor from one dictionary (
.StatusDesc) and then the corresponding value from the other dictionary (
txtSketchStatus.Text = ard.StatusDesc.Count & " status report values" & vbCrLf
For Each entry In ard.StatusDesc
txtSketchStatus.Text &= entry.Value & " = " & ard.Status(entry.Key) & vbcrlf
Dim ypos As Integer = 55
For Each entry In ard.ValDesc
Dim lblD As New Label
lblD.Name = "lblDesc" & entry.Key
lblD.Top = ypos
lblD.AutoSize = True
lblD.Left = 20
lblD.Text = entry.Value
Dim lblV As New Label
lblV.Name = "lbl" & entry.Key
lblV.Top = ypos + 14
lblV.AutoSize = True
lblV.Left = 20
lblV.Text = "x"
lblV.Font = New Font(lblV.Font, FontStyle.Bold)
ypos += 40
For the values we have created Label controls with the name "lbl" & entry.key - for eample lblA
This will enable us to find the appropriate label when we want to update its value when we are polling the board, or in response to an event raised by the
A poll timer,
tmrPoll, will be enabled whenever the board is sending serial values. When it fires we will get the values and update them. SInce we may have many values to collect there is a possibility that the
_vals structure in the ArduinoSerialClass might get updated whilst we are accessing it which will generate an exception, so we will start by making a local copy of it and working with that.
Dim lbls As Control()
Dim cpy As Dictionary(Of String, String)
cpy = New Dictionary(Of String, String)(ard.Vals)
For Each v In cpy
lbls = Me.Controls.Find("lbl" & v.Key, True)
lbls(0).Text = v.Value
Catch ex As Exception
lbls() is an array of controls returned by
.Find, we are assuming that there is only one control with a matching name and using
lbls(0). You can improve this.
And that's really all there is to it. The full code together with the project for the ArduinoSerialClassLib is in the download. You will need Visual Studio to edit this of course.
Assuming you don't want to change anything in the class library you can use the compiled DLL in the bin/release folder. If you are making changes you'll probably be wanting to work with the bin/debug version at first and update the TestApp reference after every compile.
Points of Interest
So we have seen the possible benefits of using a standardised approach to all of our Arduino sktech programmes and having a standard library to access them. Code re-use, more rapid application development focussing on the important stuff at each end - the sensor and device controls in the Arduino sketch and the user interface and data structures at the control PC end.
Of course there is an overhead - you are loading up some of PROGMEM on the Arduino with a lot of string constants that you might not need - you can always trim them down if the real useful code gets too big.
What has been presented here is just one possible way of doing this. You may have your own requirements for a communication - command and response - protocol between the Arduino and the PC. Whatever best suits your particular way of working and applications is the best solution.
This particular format has enabled us to develop a lot of variants on our particular network of things.
I'd be very interested to hear of any suggestions for alternatives and improvements - either as comments on here, or new articles or simply email me.
Roger C-O, August 2016
First published 2nd August 2016