Arduino and Visual Basic Part 2: Receiving Data From the Arduino

This post continues from Arduino and Visual Basic Part 1: Receiving Data From the Arduino

In part 1 data was sent from an Arduino to a Visual Basic app and the data was displayed in a text box. This was all well and good but the app had no idea what the data was, it simply received it and displayed it.

In this part I add a couple of physical controls, a push button switch and a potentiometer, and want to display the values or state in the app. To do this I need to change how the data is formated. I need a way to tell which device the data is for.

Control Codes / Data Packet Formats

This guide uses a fairly simple Arduino sketch and Visual Basic app and only has 2 devices to worry about, as such there are going to be numerous ways to mark or ID the data. However, I want to consider future projects and want something that can be easily expanded later.

When super high speed communication is not required, I generally use ascii with a 1 or 2 charatcer ID at the start of the data packet. The ID lets me know what the data is for. In this case I am using the letter B for button and P for potentiometer. They really could be any character though.

Push Button Switch

The button switch has 2 states; not pressed or pressed. Open or closed, HIGH or LOW. The way I have the switch connected (see the circuit below) means the switch returns LOW when not pressed and HIGH when pressed. This leads me to use BL and BH.

BL = button switch is LOW (the button is not pressed / the switch is open)
BH = button switch is HIGH (the button is pressed / the switch is closed)

The codes are contained inside markers, < and >, therefore the complete control codes are <BH> and <BL>. More on the markers in a minute.

In the Arduino sketch a simple serial.print() statement is used.

if ( newSwitchState1 == HIGH ) { Serial.print("<BH>"); } else { Serial.print("<BL>"); }

The sketch is covered in detail below.

Potentiometer

The control code or data packet used for for the potentiometer is a little bit more complex. The value from the potentiometer can be anything from 0 to 1024 and is a numeric value. Since I am using ascii to commicate the value I need a way of converting the numeric value to ascii. A very simple way would be to use the Arduino seriual.print() statement. This automatically converts number to ascii (the value 1 becomes the character “1”), however, the value can be 0 or 1000, 1 character or 4 characters.

While it is possible to deal with variable length data in the Visual Basic app it makes life more difficult than it needs to be. I find it easier to use fixed length formats. In this case “0000” to “1023”.
Fixed length data is a lot easier to handle on the Arduino and a fixed data format comes in to its own when we start send data from the VB app to the Arduino. You could have different formats going either way but why.

To convert the potentiometer value to a ascii data code / (its a char array) I am using a function called formatNumber().
formatNumber(arg1, arg2) has 2 arguments, arg1 and arg2.
– arg1 is the value to be converted
– arg2 is the number of characters to use, or how long you want the ascii data to be.

is converted to a char array / string by using the formatNumber() function. FormatNumber() sets the value of the global char array numberString

formatNumber( newPotVal, 4);

The command or code is created with

       Serial.print("<P");
       Serial.print(numberString);
       Serial.print(">");

I’m not actually creating a code, I am simply sending the parts of the code out via serial.

The value of the potentiometer is converted in to a 4 character ascii string / char array.
– 0 becomes “0000”
– 200 becomes “0200”
– 1023 becomes “1023”

The complete data packet is “<P0000>” to “<P1023>”

You should have noticed the < and > characters. These are start and end markers and they allow the receiving app to check that it has received a complete data packet. The app checks it has received a < and > before trying to process the data.
Using start and end markers create a reliable and fairly simply way to know whole data packets have been received. It does mean that the data cannot contain the characters used as the markers though.

I am using ASCII, this means numeric values need to be converted to text. IE the value 1 becomes “1”. This makes handling the data a bit easier, especially the numbers, but does mean the communication is slower. If we send the value 255, as a numeric value it is one byte. As An ASCII string it is three bytes a “2” + a “5”, + another “5”. More on this below.

The Arduino Setup

Set up the Arduino with the following:
– D2 – LED + resistor
– D3 – button switch which pulled to ground with a 10K resistor
– A4 – potentiometer

Circuit

Arduino Sketch

/* 
* Sketch Arduino and Visual Basic Part 2 - Receiving Data From the Arduino
* Send data over serial to Visual Basic
* https://www.martyncurrey.com/arduino-and-visual-basic-part-1-receiving-data-from-the-arduino/
*/

/*
* Pins
* D2 - LED + resistor
* D3 - push button switch
* A4 - potentiometer
*
* It should noted that no data is sent until something changes
* The sketch can be expanded so that an initial value is sent
*/
 
// When DEGUG is TRUE print a newline characters
const boolean DEBUG = true;
 
const byte ledPin = 2;
const byte buttonSwitchPin = 3;
const byte potPin = A4;

boolean newSwitchState1 = LOW;
boolean newSwitchState2 = LOW;
boolean newSwitchState3 = LOW;
boolean oldSwitchState = LOW;

unsigned int oldPotVal = 0;
unsigned int newPotVal = 0;

 
// used to hold an ascii representation of a number
// [10] allows for 9 digits 
char numberString[10];
 
 
void setup()  
{
  pinMode(ledPin, OUTPUT); 
  digitalWrite(ledPin, LOW);
  pinMode(buttonSwitchPin, INPUT); 

  Serial.begin(9600);
  // while (!Serial) {;}
  Serial.println("Adruino is ready");
  Serial.println(" ");
}
 
 
void loop()  
{
    // simple debounce
    newSwitchState1 = digitalRead(buttonSwitchPin);      delay(1);
    newSwitchState2 = digitalRead(buttonSwitchPin);      delay(1);
    newSwitchState3 = digitalRead(buttonSwitchPin);
 
    if (  (newSwitchState1==newSwitchState2) && (newSwitchState1==newSwitchState3) )
    {
        if ( newSwitchState1 != oldSwitchState ) 
        {
            if ( newSwitchState1 == HIGH ) { Serial.print("<BH>"); } else { Serial.print("<BL>"); }
            if (DEBUG) { Serial.println("");  } 
            oldSwitchState = newSwitchState1;
        }   
    }


    // The potentiometer I am using jitters a bit so I only using changes of 3 or more.  
    newPotVal = analogRead(potPin); 
    if ( abs(newPotVal-oldPotVal) > 2)
    {
       oldPotVal = newPotVal;  
       formatNumber( newPotVal, 4);
       Serial.print("<P");   
       Serial.print(numberString);     
       Serial.print(">");
       if (DEBUG) { Serial.println("");  }      
    }    

    if ( newPotVal >= 1000 ) { digitalWrite(ledPin, HIGH);}
    else                     { digitalWrite(ledPin, LOW); }
  
   delay (250);
 }
 
  
void formatNumber( unsigned int number, byte digits)
{
    // Formats a number in to a string and copies it to the global char array numberString
    // Pads the start of the string with '0' characters
    //
    // number = the integer to convert to a string
    // digits = the number of digits to use. 
 
    char tempString[10] = "\0"; 
    strcpy(numberString, tempString);
 
    // convert an integer into a acsii string
    itoa (number, tempString, 10);
 
    // create a string of '0' characters to pad the number    
    byte numZeros = digits - strlen(tempString) ;
    if (numZeros > 0)
    {
       for (int i=1; i <= numZeros; i++)    { strcat(numberString,"0");  }
    }
     strcat(numberString,tempString); 
}

Connect the Arduino, upload the sketch and open the serial monitor. You should see something similar to:

Turn the potentiometer and see if the new values appear:

Press the button switch:

If you get similar results you know the sketch and circuit are working.

Turn the potentiometer all the way up. When the value gets to 1000 or higher the LED should come on.

The Arduino Sketch In Detail

The sketch is fairly simple:
– It reads the status of the button switch pin, and if it has changed, sends an ascii command via serial.
– It then reads the value from the potentiometer, and if this has changed, sends the potentiometer, command.

Check the status of the push button switch pin.
By using newSwitchState1 and oldSwitchState I can monitor when the state of the switch has changed.

   // simple debounce
    newSwitchState1 = digitalRead(buttonSwitchPin);      delay(1);
    newSwitchState2 = digitalRead(buttonSwitchPin);      delay(1);
    newSwitchState3 = digitalRead(buttonSwitchPin);
 
    if (  (newSwitchState1==newSwitchState2) && (newSwitchState1==newSwitchState3) )
    {
        if ( newSwitchState1 != oldSwitchState ) 
        {
            if ( newSwitchState1 == HIGH ) { Serial.print("<BH>"); } else { Serial.print("<BL>"); }
            if (DEBUG) { Serial.println("");  } 
            oldSwitchState = newSwitchState1;
        }   
    }

Using analogRead(), the value of the potentiometer is read. If the the value has changed the value is converted to an ascii command (via the formatNumber() function) and sent out via serial.

Bonus code. If the value of the potentiometer is >= 1000 the LED is turned on.

    // The potentiometer I am using jitters a bit so I only using changes of 3 or more.  
    newPotVal = analogRead(potPin); 
    if ( abs(newPotVal-oldPotVal) > 2)
    {
       oldPotVal = newPotVal;  
       formatNumber( newPotVal, 4);
       Serial.print("<P");   
       Serial.print(numberString);     
       Serial.print(">");
       if (DEBUG) { Serial.println("");  }      
    }    

    if ( newPotVal >= 1000 ) { digitalWrite(ledPin, HIGH);}
    else                     { digitalWrite(ledPin, LOW); }
  
   delay (250);

formatNumber() takes a numeric value and converts it to a fixed length ascii char array / string. The function takes 2 inputs, the value to be converted, and how many characters the char array will be. FormatNumber() copies the new ascii string to the global char array numberString

The value of the potentiometer is converted in to a 4 character ascii string / char array.
– 0 becomes “0000”
– 200 becomes “0200”
– 1023 becomes “1023”

void formatNumber( unsigned int number, byte digits)
{
    // Formats a number in to a string and copies it to the global char array numberString
    // Pads the start of the string with '0' characters
    //
    // number = the integer to convert to a string
    // digits = the number of digits to use. 
 
    char tempString[10] = "\0"; 
    strcpy(numberString, tempString);
 
    // convert an integer into a acsii string
    itoa (number, tempString, 10);
 
    // create a string of '0' characters to pad the number    
    byte numZeros = digits - strlen(tempString) ;
    if (numZeros > 0)
    {
       for (int i=1; i <= numZeros; i++)    { strcat(numberString,"0");  }
    }
 
    strcat(numberString,tempString); 
 
}

Note:
formatNumber() does not check the size of the numberString buffer.
itoa does not check the size of the numberString buffer.

The Visual Basic App

For this guide I started with the app from the previous part and added a few things.

The connection process is the same as before and received data is copied to the text box as before. This time though, there is added code that precesses the received data and checks to see if it is something we want to use.

I also added extra labels used to show the new values that are received and I also added a couple of things to help with understanding what the app is doing; TIMER SPEED and CODE COUNT. Hopefully, what these are used for should be self explanatory.

There are several additions to the form

RECEIVED DATA has been renamed to DEBUG DATA
Internal variables are now copied to the text box so it is no longer used exclusively for received data.

BUTTON SWITCH
Shows the status of the button switch attached to the Arduino

POTENTIOMETER
Shows the value of the potentiometer attached to the Arduino

CODE COUNT
Shows the total number of data packets received. A data packet does not necessarily mean a command or code.
This is reset to 0 when the text box is cleared.

Try The App

If you are eager to see the new app in action, start up the Arduino, start up Visual Studio, load the project files and click the little Start.

Wait for the app to start, select the COM PORT and click CONNECT

When data is received it is copied to the text box. If the data is a valid code, either the Button Switch field or the potentiometer field is updated.

As an added bonus, when the value of the potentiometer is 100 or higher the potentiometer value turns red. Exciting stuff!

The Visual Basic Program

Here is the code. You can download below.

' Arduino and Visual Basic Part 1: Receiving Data From An Arduino
' A simple example of recieving serial data from an Arduino and displaying it in a text box
' https://www.martyncurrey.com/arduino-and-visual-basic-part-1-receiving-data-from-the-arduino/
'

Imports System
Imports System.IO.Ports
Imports System.Windows.Forms.VisualStyles.VisualStyleElement


Public Class Form1

    ' Global variables.
    ' Anything defined here is available in the whole app
    Dim selected_COM_PORT As String
    Dim receivedData As String = ""
    Dim commandCount As Integer = 0

    ' This called when the app first starts. Used to initial what ever needs initialising.
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Timer1.Enabled = False
        selected_COM_PORT = ""
        For Each sp As String In My.Computer.Ports.SerialPortNames
            comPort_ComboBox.Items.Add(sp)
        Next

        TimerSpeed_value_lbl.Text = Timer1.Interval
    End Sub

    ' When the value of the COM PORT drop doewn list changes,
    ' copy the new value to the comPORT variable.
    Private Sub comPort_ComboBox_SelectedIndexChanged(sender As Object, e As EventArgs) Handles comPort_ComboBox.SelectedIndexChanged
        If (comPort_ComboBox.SelectedItem <> "") Then
            selected_COM_PORT = comPort_ComboBox.SelectedItem
        End If
    End Sub

    ' Try to open the com port or close the port if already open
    ' Note: There is no error catching. If the connection attampt fails the app will crash!
    Private Sub connect_BTN_Click(sender As Object, e As EventArgs) Handles connect_BTN.Click
        If (connect_BTN.Text = "CONNECT") Then
            If (selected_COM_PORT <> "") Then

                ' Try allows me to trap an errors such as the COM port not being available
                ' Without it the app crashes.
                Try
                    SerialPort1.PortName = selected_COM_PORT
                    SerialPort1.BaudRate = 9600
                    SerialPort1.DataBits = 8
                    SerialPort1.Parity = Parity.None
                    SerialPort1.StopBits = StopBits.One
                    SerialPort1.DtrEnable = True
                    SerialPort1.RtsEnable = True
                    SerialPort1.Handshake = Handshake.None

                    SerialPort1.Encoding = System.Text.Encoding.Default 'very important!
                    SerialPort1.ReadTimeout = 10000

                    SerialPort1.Open()

                Catch ex As Exception
                    MessageBox.Show(ex.Message + vbCrLf + "Looks like something else is using it.", "Error opening the serial port", MessageBoxButtons.OK, MessageBoxIcon.Error)
                End Try

            Else
                MsgBox("No COM port selected!")
            End If
        Else
            Try
                SerialPort1.Close()
            Catch ex As Exception
                MessageBox.Show("Serial Port is already closed!")
            End Try
        End If

        ' Separating opening the port and setting the variables like this makes the
        ' code a little more clear.
        If (SerialPort1.IsOpen) = True Then
            connect_BTN.Text = "DIS-CONNECT"
            Timer1.Enabled = True
            timer_LBL.Text = "TIMER: ON"
        Else
            connect_BTN.Text = "CONNECT"
            Timer1.Enabled = False
            timer_LBL.Text = "TIMER: OFF"
        End If

    End Sub

    ' Process received data. Append the data to the text box
    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick

        'stop the timer (stops this function being called while it is still working
        Timer1.Enabled = False
            timer_LBL.Text = "TIMER: OFF"

            ' get any new data and add the the global variable receivedData
            receivedData = ReceiveSerialData()

        If (receivedData <> "") Then
            recData_RichTextBox.AppendText("RD = " + receivedData)

            'If receivedData contains a "<" and a ">" then we have data
            If ((receivedData.Contains("<") And receivedData.Contains(">"))) Then
                parseData()
            End If

            recData_RichTextBox.SelectionStart = recData_RichTextBox.TextLength
            recData_RichTextBox.ScrollToCaret()

        End If

        ' restart the timer
        Timer1.Enabled = True
        timer_LBL.Text = "TIMER: ON"

    End Sub


    ' Check for new data
    Function ReceiveSerialData() As String
        Dim returnData As String = ""
        Dim Incoming As String = ""
        Try
            Incoming = SerialPort1.ReadExisting()
            If Incoming IsNot Nothing Then
                returnData = Incoming
            End If
        Catch ex As TimeoutException
            Return "Error: Serial Port read timed out."
        End Try
        Return returnData
    End Function

    Function parseData()

        ' uses the global variable receivedData
        Dim pos1 As Integer
        Dim pos2 As Integer
        Dim length As Integer
        Dim newCommand As String
        Dim done As Boolean = False

        While (Not done)

            pos1 = receivedData.IndexOf("<") + 1
            pos2 = receivedData.IndexOf(">") + 1

            'occasionally we may not get complete data and the end marker will be in front of the start marker
            ' for exampe "55><"
            ' if pos2 < pos1 then remove the first part of the string from receivedData
            If (pos2 < pos1) Then
                receivedData = Microsoft.VisualBasic.Mid(receivedData, pos2 + 1)
                pos1 = receivedData.IndexOf("<") + 1
                pos2 = receivedData.IndexOf(">") + 1
            End If

            If (pos1 = 0 Or pos2 = 0) Then
                ' we do not have both start and end markers and we are done
                done = True

            Else
                ' we have both start and end markers

                length = pos2 - pos1 + 1
                If (length > 0) Then

                    'remove the start and end markers from the command
                    newCommand = Mid(receivedData, pos1 + 1, length - 2)

                    ' show the command in the text box
                    recData_RichTextBox.AppendText("CMD = " & newCommand & vbCrLf)

                    'remove the command from receivedData
                    receivedData = Mid(receivedData, pos2 + 1)


                    ' B for button switch
                    If (newCommand(0) = "B") Then
                        If (newCommand(1) = "L") Then
                            buttonSwitchValue_lbl.Text = "LOW"
                        ElseIf (newCommand(1) = "H") Then
                            buttonSwitchValue_lbl.Text = "HIGH"
                        End If
                    End If ' (newCommand(0) = "B")


                    ' P for potentiometer
                    If (newCommand.Substring(0, 1) = "P") Then
                        Dim tempVal As Integer = Val(newCommand.Substring(1, 4))

                        If (tempVal > 999) Then
                            potentiometerValue_lbl.ForeColor = Color.Red
                        Else
                            potentiometerValue_lbl.ForeColor = Color.Black
                        End If
                        potentiometerValue_lbl.Text = tempVal

                    End If

                    commandCount = commandCount + 1
                    commandCountVal_lbl.Text = commandCount

                End If ' (length > 0) 

            End If '(pos1 = 0 Or pos2 = 0)

        End While

    End Function



   ' Clear the text box
    Private Sub clear_BTN_Click(sender As Object, e As EventArgs) Handles clear_BTN.Click
        recData_RichTextBox.Text = ""

        commandCount = 0
        commandCountVal_lbl.Text = commandCount
    End Sub

End Class

The Program In Detail

The code starts by declaring 3 global variables. COM_PORT and receivedData are the same before. commandCount is new.
COM_PORT is used to hold the COM port after the user has selected from the drop down list.
receivedData us used to hold data received over the serial channel
commandCount is used to store the number of data packets received so far. Ideally it should be called dataPacketCount but hey.

    ' Global variables.
    ' Anything defined here is available in the whole app
    Dim selected_COM_PORT As String
    Dim receivedData As String = ""
    Dim commandCount As Integer = 0

Next is Form1_Load(). This is called once when the app first starts. As in the previous part, it is used to perform whatever initialisation is required, code that needs to run once. In this case, get the list of available COM ports and load the list into the comboBox drop down list.
TimerSpeed_value_lbl is updated with the frequency of the timer tick.

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Timer1.Enabled = False
        selected_COM_PORT = ""
        For Each sp As String In My.Computer.Ports.SerialPortNames
            comPort_ComboBox.Items.Add(sp)
        Next

        TimerSpeed_value_lbl.Text = Timer1.Interval
    End Sub

When the CONNECT button is clicked, connect_BTN_Click is called. Here the serial port is opened. This is covered in detail in the previous guide so I will not go over it here.

Private Sub connect_BTN_Click(sender As Object, e As EventArgs) Handles connect_BTN.Click
    If (connect_BTN.Text = "CONNECT") Then
        If (selected_COM_PORT <> "") Then

            ' Try allows me to trap an errors such as the COM port not being available
            ' Without it the app crashes.
            Try
                SerialPort1.PortName = selected_COM_PORT
                SerialPort1.BaudRate = 9600
                SerialPort1.DataBits = 8
                SerialPort1.Parity = Parity.None
                SerialPort1.StopBits = StopBits.One
                SerialPort1.DtrEnable = True
                SerialPort1.RtsEnable = True
                SerialPort1.Handshake = Handshake.None

                SerialPort1.Encoding = System.Text.Encoding.Default 'very important!
                SerialPort1.ReadTimeout = 10000

                SerialPort1.Open()

            Catch ex As Exception
                MessageBox.Show(ex.Message + vbCrLf + "Looks like something else is using it.", "Error opening the serial port", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try

        Else
            MsgBox("No COM port selected!")
        End If
    Else
        Try
            SerialPort1.Close()
        Catch ex As Exception
            MessageBox.Show("Serial Port is already closed!")
        End Try
    End If

    ' Separating opening the port and setting the variables like this makes the
    ' code a little more clear.
    If (SerialPort1.IsOpen) = True Then
        connect_BTN.Text = "DIS-CONNECT"
        Timer1.Enabled = True
        timer_LBL.Text = "TIMER: ON"
    Else
        connect_BTN.Text = "CONNECT"
        Timer1.Enabled = False
        timer_LBL.Text = "TIMER: OFF"
    End If

End Sub

The Timer1_Tick function has been expanded. There is now an added check looking for the < and > start and end characters. If there are present then it means the data contains a full code or command and the parseData() function is called. parseData() uses the receivedData global variable.

Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick

    'stop the timer (stops this function being called while it is still working
    Timer1.Enabled = False
        timer_LBL.Text = "TIMER: OFF"

        ' get any new data and add the the global variable receivedData
        receivedData = ReceiveSerialData()

    If (receivedData <> "") Then
        recData_RichTextBox.AppendText("RD = " + receivedData)

        'If receivedData contains a "<" and a ">" then we have data
        If ((receivedData.Contains("<") And receivedData.Contains(">"))) Then
            parseData()
        End If

        recData_RichTextBox.SelectionStart = recData_RichTextBox.TextLength
        recData_RichTextBox.ScrollToCaret()

    End If

    ' restart the timer
    Timer1.Enabled = True
    timer_LBL.Text = "TIMER: ON"

End Sub

Function parseData() is new. It takes the receivedData variable and looks for a code/command. If it finds one it checks to see what it is and then acts accordingly.

The actual code/command minus the start and end markers has to be copied from receivedData. To do this the position of the start and end markers is found and then the data between the two markers is copied into a variable called newCommand.

newCommand is tested against expected values; B for button, P for potentiometer.

 Function parseData()

     ' uses the global variable receivedData
     Dim pos1 As Integer
     Dim pos2 As Integer
     Dim length As Integer
     Dim newCommand As String
     Dim done As Boolean = False

     While (Not done)

         pos1 = receivedData.IndexOf("<") + 1
         pos2 = receivedData.IndexOf(">") + 1

         'occasionally we may not get complete data and the end marker will be in front of the start marker
         ' for exampe "55><"
         ' if pos2 < pos1 then remove the first part of the string from receivedData
         If (pos2 < pos1) Then
             receivedData = Microsoft.VisualBasic.Mid(receivedData, pos2 + 1)
             pos1 = receivedData.IndexOf("<") + 1
             pos2 = receivedData.IndexOf(">") + 1
         End If

         If (pos1 = 0 Or pos2 = 0) Then
             ' we do not have both start and end markers and we are done
             done = True

         Else
             ' we have both start and end markers

             length = pos2 - pos1 + 1
             If (length > 0) Then

                 'remove the start and end markers from the command
                 newCommand = Mid(receivedData, pos1 + 1, length - 2)

                 ' show the command in the text box
                 recData_RichTextBox.AppendText("CMD = " & newCommand & vbCrLf)

                 'remove the command from receivedData
                 receivedData = Mid(receivedData, pos2 + 1)


                 ' B for button switch
                 If (newCommand(0) = "B") Then
                     If (newCommand(1) = "L") Then
                         buttonSwitchValue_lbl.Text = "LOW"
                     ElseIf (newCommand(1) = "H") Then
                         buttonSwitchValue_lbl.Text = "HIGH"
                     End If
                 End If ' (newCommand(0) = "B")


                 ' P for potentiometer
                 If (newCommand.Substring(0, 1) = "P") Then
                     Dim tempVal As Integer = Val(newCommand.Substring(1, 4))

                     If (tempVal > 999) Then
                         potentiometerValue_lbl.ForeColor = Color.Red
                     Else
                         potentiometerValue_lbl.ForeColor = Color.Black
                     End If
                     potentiometerValue_lbl.Text = tempVal

                 End If


                 commandCount = commandCount + 1
                 commandCountVal_lbl.Text = commandCount

             End If ' (length > 0) 

         End If '(pos1 = 0 Or pos2 = 0)

     End While

 End Function

Rather than looking for the complete code, which I could have just as easy done, I check the first character of the command first.

 If (newCommand(0) = "B") Then

If the command starts with a B I know it is for the button switch so the next character should be a H or a L

                    If (newCommand(1) = "L") Then
                         buttonSwitchValue_lbl.Text = "LOW"
                     ElseIf (newCommand(1) = "H") Then
                         buttonSwitchValue_lbl.Text = "HIGH"
                     End If

For this basic example there isn’t really any need to have 2 stages of logic and a simple check for “BL” and “BH” would be easier.

If (newCommand= "BL") Then           buttonSwitchValue_lbl.Text = "LOW"
ElseIf (newCommand= "BH") Then   buttonSwitchValue_lbl.Text = "HIGH"
End If

For the potentionmeter I check for a P. Unlike the button switch which only has two states, the potentionmeter has a value which needs to be extracted. To help with this the tempVal variable is used.

The val() statement converts an ascii string into a numeric value. It is the oposite of what happened on the Arduino where a numeric value is converted to the string.

newCommand includes the initial P which the val() statement doesn’t like so I get the just the numeric characters by using substring. newCommand.Substring(1, 4) returns the part of newCommand starting at the character at position 1 and ending at position 4.

                 If (newCommand.Substring(0, 1) = "P") Then
                     Dim tempVal As Integer = Val(newCommand.Substring(1, 4))

Once I have the actual value it can be displayed in the form. However, if the value is >999 it is displayed in red.

 If (tempVal > 999) Then
                         potentiometerValue_lbl.ForeColor = Color.Red
                     Else
                         potentiometerValue_lbl.ForeColor = Color.Black
                     End If
                     potentiometerValue_lbl.Text = tempVal

And that really all there is to it.

The Visual Basic app can now process and detect control codes and display the values is the associated fields in the app form.

Download

Download the Arduino sketch
Download the Visual Basic project You will need to have Visual Studio installed to use the VB project files.  

Next Steps

In part 3 we look at send data from teh VB app to the Arduino. Fun times!

If you want to know more about sending complex commands or data packets see Arduino Serial: ASCII Data and Using Markers to Separate Data

26 thoughts on “Arduino and Visual Basic Part 2: Receiving Data From the Arduino”

  1. Thank you for this article- I still did not read it but it looks good- I will try it pretty soon- again thanks for you effort

    Reply
  2. I ran the program and sometimes it works good and sometimes it gets stuck.
    The VB says (after it compiles the program) that there might be a null exeption when running the program since the parse() function may not return a value for all cases. Is there a cure for that?
    Appreciate an answer to my E- mail
    Thanks a lot

    Reply
    • Hi Dan,

      I haven’t used this for a while but I never had an issue in the past and I use the same code on my dropController project which runs without a problem.

      The parseData() does not return a value. It looks for the start and end markers and then takes the data they contain. If it finds data it checks what the data is.

      Can you post a more specific error and possible show the program line in the code.

      Reply
  3. The null you see from the vb could be an empty com port. Or not existing tha port

    I have the same issue

    By the way it is very good example and very well comment, it helps a lot !!!! Well done!!!

    Kind regards
    Tasos

    Reply
  4. Hi Martyn,

    I have a problem and was wondering if you could guide what the issue could be?

    Setup:
    I setup a board with 2 switches, Switch A and Switch B. Switch A = Pin D2 and Switch B = Pin D4. Used the same code of yours in the vb software to monitor both pins. In the arduino, I programmed them as AH, AL (for Switch A) and BH, BL (for Switch B). Attached 10K ohm resistor against Switch A as per your diagram and again one more 10K ohm resistor against Switch B in the same manner and polarity.
    Power Source: USB from the laptop (no external power).

    Problem:
    Both the pin outputs keep swapping between H and L after every few seconds (ranges between 3 seconds to 15 seconds but averages at about 6-8 seconds). Could there be an issue with the circuitry? By turning on/off the switch – i am still not able to make out if its affecting the signals as the output keeps swapping between H and L for both pins every few seconds.

    Could you guide what could be the issue?

    Reply
    • Hi Martyn,

      Here is a sample output with timestamp. You can notice the difference in seconds. This keeps repeating for ever.

      00:30:40 – Command = AL
      00:30:40 – Command = BL
      00:30:47 – Command = AH
      00:30:47 – Command = BH
      00:30:50 – Command = AL
      00:30:50 – Command = BL
      00:30:58 – Command = AH
      00:30:58 – Command = BH
      00:31:02 – Command = AL
      00:31:02 – Command = BL
      00:31:09 – Command = AH
      00:31:09 – Command = BH
      00:31:13 – Command = AL
      00:31:13 – Command = BL
      00:31:20 – Command = AH
      00:31:21 – Command = BH
      00:31:24 – Command = AL
      00:31:24 – Command = BL

      Reply
      • My first thought is an issue with the switches or lose connections. Are you moving the circuit while using it?

        Try different switches if you can. If not, remove the switches and replace with a short length of wire and then use the wire as a switch.

        Also try just using the serial monitor.

        Reply
        • Hi Martyn,

          Thanks for your guidance. Yes, I verified everything that you said. The circuit is not moving, its static on a table. Infact, I dont have switches at the moment as I am still prototyping. I am using two short wires instead as a switch.

          Upon further research, I found many people are having similar issues. I even measured the voltage across the pins in a H and L state and they were reporting 0.45-0.50 volts – which is almost an OFF state.

          I found there could be 2 possible issues:

          1) Circuit is incorrect. I will start from scratch again. This is because voltage drop across the PINs are 0.45v during H and L – indicates an incorrect circuit setup.

          2) The OFF and ON swaps are explained due to tri-state of the PINs. I read a lot about everyone having this issue. One link here: https://forum.arduino.cc/index.php?topic=183977.0 and many of them are suggesting different methods to rule out the tri-state of the PINS.

          I will address both issues above if possible and post the outcome soon. Thanks a lot for your guidance though and it was helpful to start looking in the right direction towards trouble shooting the issue.

          Also, Yes, Output in Serial Monitor was also behaving the same way as explained yesterday.

          Thanks so much. I will keep you posted on how this goes.

          Regards,
          John.

          Reply
          • Here’s the link http://arduino.stackexchange.com/questions/12951/testing-tri-state-pin-erroneous-results-with-internal-pullup/12955#12955 that explains the behaviour I was having. Unfortunately, I am not very good at designing circuits, so I cannot interpret how to come up with the schematics for this suggestion, so i will have to consult someone or maybe you could help with a diagram if time allows you. If not, its ok, i will manage somehow. Isn’t this the exact behavior i reported initially? pretty much so.

            Thanks once again. Will post further updates.

            Regards,
            John.

            Reply
            • I would expect this behaviour if the pin was floating, do you have the it set for input?

              What is the voltage from the VCC rail? The opposite side of the switch. This is marked +5V on the switch in the diagram above.

              You also try switching the polarity of the switch. Make the resistor pullup and then connect the switch to GND. This swaps how the switch works. HIGH is not pressed, GND is pressed.

              Reply
            • Hi Mark,

              See my responses below.

              I would expect this behaviour if the pin was floating, do you have the it set for input?
              Yes, both were set to INPUT.

              What is the voltage from the VCC rail? The opposite side of the switch. This is marked +5V on the switch in the diagram above.
              Constantly getting >4.5v.

              You also try switching the polarity of the switch. Make the resistor pullup and then connect the switch to GND. This swaps how the switch works. HIGH is not pressed, GND is pressed.
              Am bad at understanding electronic language technically but I sort of get the idea of what you are suggesting. Also, I even tried adding >1M Ohm resistor and using that PULLUP PIN idea from the other post – even that didn’t work.

              Going by your suggestion to use PULLUP, I found a way to make it work. Not sure if this is good enough for a production environment but the outcome is perfectly as expected.

              I removed all the resistors and converted both the pins from INPUT to INPUT_PULLUP. Then, directly connected pins to switch (aka the 2 wires as I do not have physical switches) and from switch to ground thereby using the internal pullups of the nano. It worked perfectly after that. Only had to reverse the logic like you suggested that it would return HIGH when not pressed and GND when pressed.

              This was my new schematic setup here https://www.arduino.cc/en/Tutorial/InputPullupSerial and I setup 2 switches instead of one with the changes explained above and now it works perfectly. Thank you so much for your suggestions and directions.

              Thanks for all your help.

              I would still be interested to resolve the issue with your suggestion though. I am still not convinced why it didn’t work with the external resistors and I will update you when i get to work on it.

              But for now – it worked perfect after using both pins as pullups.

              Thanks for all your help.

              Cheers.

              Regards,
              John.

              Reply
  5. Thank you so much for this posting. It was exactly what I needed to start a project. Your
    sharing is greatly appreciated.

    Reply
  6. halo sir,

    I want to ask something about this project, i made something a little different from the program you created, i just use push button without potentiometer etc, i set the program on arduino to send serial data “” if pushbutton one is pressed and ” “If not pressed, I try to simplify the program you have created with the sole purpose of changing the text label and changing the fill color of a shape I have created using the program in the timer1 section as follows:

    Private Sub Timer1_Tick (ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

    ReceivedData = ReceiveSerialData ()
    Tbxinput.Text & = receivedData
    If (receivedData = “”) Then
    Lbllampu1.Text = “lampu1: On”
    Lampu1.FillColor = Color.Blue
    End If
    End Sub
    No error message appears but the program does not work as I like(the text label is unchanged and the fill color does not change), can you show me where the mistake I made and how it should be, please help me, thanks

    Reply
  7. Don’t use “” use something with an actual value like “Lamp: Off”. On the Arduino, keep the switch state in a variable and only send “Lamp: Off” when the state changes to off.

    Reply
    • I’m sorry sir, I do not mean to write “” (empty) in the comment field, but I write (“”), if I write “” + (inside), the word in it suddenly disappears after the comment is sent and I do not know why Like that, sorry I did not realize it
      Back to my program, actually what I mean in the “” sign is not empty, but there is a word if push button on press and if pushbutton is removed and with the program I use above does not work as desire

      Reply
    • I just change the serial data I send from arduino because if the write in this comment always disappear: P, sorry sir I repeat the question

      I send the data serial “1H” if pushbutton is pressed, and “1L” if pushbutton is released, the serial data is received and read in the textbox, and I want to use it to change the text and change the shape color,

      ReceivedData = ReceiveSerialData ()
      Tbxinput.Text & = receivedData
      If (receivedData = “1H”) Then
      Lbllampu1.Text = “lampu1: On”
      Lights1.FillColor = Color.Blue
      End If
      End Sub

      No error message appears but the program does not work as I like (the text label is unchanged and the fill color does not change), can you show me where the mistake I made and how it should be, please help me, thanks

      Reply
      • I suspect the value of receivedData is not just 1H. Are there additional characters, possibly non print characters?

        Check the length of receivedData.

        Reply
  8. I am working on a project similar to the one described here. Also, I have read Part 1 of this post.
    I want a connection of 4 to 5 push buttons (e.g A,B,C,D), a RFID reader and a few RFID tags. For example when button ‘A’ is pressed, I want to record ‘A’ into a tag that is placed before the reader. Besides, I want to keep count of how many times each button has be pressed and send this information to my VB.Net application.

    I am a final year student of computer science with no electronic background. My project is a little more complex but this aspect is a major hurdle for me to overcome. Everyone, please help me on this. I would also want to know what electronic components are needed to accomplish this task.

    If you feel the information is not sufficient, please let me know. Thank you very much.

    Reply
  9. I think there is a little bug in the software.

    if (newButtonSwitchState != oldButtonSwitchState)
    {
    oldButtonSwitchState = newButtonSwitchState;
    –> if (oldButtonSwitchState == true)

    I think that it should be “newButtonSwitchState”

    Reply
  10. sorry sir,
    i wanna ask about, how we read the digitalwrite in arduino and then send to VB10, which in VB10, when we got the data that change the backcolor of a shape.

    to make it clear for exmple
    make a code of traffic light and in VB just monitoring.
    i mean when the light change in arduino, arduino send the data to VB and the shape of the lamp is changed in the VB

    thanks before

    Reply
  11. grazie ho usato questa trasmissione per il mio progetto
    ho modificato con un ingresso interrupt arduino 0/1
    e altro ingresso per badge
    e altro per ingresso 0/1
    per mio progetto industria 4.0

    Reply
  12. Hi Martyn,

    I’m working on a personal project and found your project by searching on google. Your project is great!

    I would have question given that I am not familiar with transmitting and receiving string I would like to know just how I can in VB.net transmit data from three trackBar and receive them with Arduino.

    I studied your code but and did some tests but without success :-(

    thanks for your help

    Chris

    Reply
  13. I tried this vb code. And I am having an issue with the parsedata(). I am pressing a button that sends a command to the arduino. The received response is first printed in the richtextbox1 just like your code but then in the parse data() I am checking the received response string within the start and end markers, if it contains a certain set of characters I am printing the string in another textbox.

    Now the issue I am facing is. For most cases I am able to see the string getting printed in the textbox. But sometimes the printing is not happening, even when I am receiving the correct response in the rich textbox1. I ran the debugger and used breakpoints and realised that at times the parse data() is not able to recognize the end marker. This pos2 becomes 0 and the while loop terminates due to which print operation does not occur.
    I know it’s been really long since you posted this. But it would be very helpful if you could help me with my problem.

    Hoping to hear from you in the mail.
    Thank you

    Reply

Leave a Reply to Tasos Cancel reply