Serial Message Not Evaluating Correctly -- Arduino-VB.net App

I’m experiencing some confounding outcomes when reading from a serial connection in Arduino. The Arduino code below should turn on an LED for one second depending upon the text string received.

The strings are sent by a VB.net app (code attached) to an Arduino Leonardo through its USB connection. Each string is sent in ASCII and terminated with Environment.NewLine. I have also tried terminating with vbCr, vbLf, vbCrLf, vbNewLine.

If I send the string “abc” and evaluate the string using this code in Arduino
if (SerialMessageForCode == "abc")
the LED does not turn on.

However, if I send the string “xyz” and evaluate the string using this code
if (SerialMessageForCode.indexOf("xyz") != -1)
the LED does turn on.

Why will sending “abc” never trigger the LED in the Arduino code? I have commented the null character line SerialMessage[SerialMessage_char] = '\0'; from the sketch, but am getting the same problem. It is as if a non-printing character causes the string SerialMessageForCode not to equal "abc"

The Arduino sketch accurately sends back each message received and if I send “abc”, then “abc” will be sent by the Arduino back to the VB app and the VB app will correctly display "abc" in the textbox.

I've been working on troubleshooting this for over 6 hours and am running out of ideas.

Arduino Code:

const unsigned int SerialMessageLength = 20;
const int LED10 = 10;
String IncomingMessage;
String SerialMessage;
String SerialMessageForCode;

void setup()
{
  pinMode(LED10, OUTPUT);
  Serial.begin(9600);
  Serial.print("Arduino ready");
}

void loop()
{
  while (Serial.available() > 0)
  {
    static char SerialMessage[SerialMessageLength];
    static unsigned int SerialMessage_char = 0;
    char inByte = Serial.read();

    if (inByte != '\n' && (SerialMessage_char < SerialMessageLength -1) )
    {
      SerialMessage[SerialMessage_char] = inByte;
      SerialMessage_char++;
    }
    else
    {
      SerialMessage[SerialMessage_char] = '\0';
      SerialMessageForCode = SerialMessage;
      SerialMessage_char = 0;
      SerialMessageForCode = SerialMessage;
      Serial.print(SerialMessageForCode);
      flushSerial();
    }
  }
  if (SerialMessageForCode.indexOf("xyz") != -1)
  {
    SerialMessageForCode = "";
    digitalWrite(LED10, HIGH);
    delay(1000);
    digitalWrite(LED10, LOW);
  }

  if (SerialMessageForCode == "abc")
  {
    SerialMessageForCode = "";
    digitalWrite(LED10, HIGH);
    delay(1000);
    digitalWrite(LED10, LOW);
  }
}


void flushSerial()
{
  while (Serial.available())
  {
    Serial.read();
  }
}

The VB.Net form has the following controls:
TextBoxMessage
TextBoxSerialComm
ButtonSend
ButtonReset
LabelStatus

VB.Net Code:

Imports System.Configuration
Imports System.Diagnostics
Imports System.Drawing
Imports System.IO
Imports System.IO.Ports
Imports System.Management

Public Class Form1

    Dim WithEvents ArduinoConnection As New IO.Ports.SerialPort
    Public ArduinoPort As String
    Public ArduinoDetected As Boolean
    Public ArduinoNotDetected As String
    Public ArduinoState As String
    Public DataSentFromArduino As String
    Public CurrentMessage As String
    Private DataReceivedToCheckForEcho As String

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim connectionScope As New ManagementScope()
        Dim serialQuery As New SelectQuery("SELECT * FROM Win32_SerialPort")
        Dim searcher As New ManagementObjectSearcher(connectionScope, serialQuery)

        Try
            For Each item As ManagementObject In searcher.[Get]()
                Dim desc As String = item("Description").ToString()
                Dim deviceId As String = item("DeviceID").ToString()

                If desc.Contains("Arduino") Then
                    ArduinoDetected = True
                    ArduinoPort = deviceId
                    LabelStatus.Text = "Arduino found " + ArduinoPort.ToString()
                End If
            Next
        Catch exception As ManagementException
            ArduinoDetected = False
            ArduinoNotDetected = exception.Message
        End Try

        If ArduinoDetected = False Then
            LabelStatus.Text = "Arduino not found"
        Else
            CreateArduinoConnection()
        End If
    End Sub

    Private Sub CreateArduinoConnection()
        Try
            If ArduinoConnection.IsOpen = True Then
                ArduinoConnection.Close()
            End If
            ArduinoConnection.PortName = ArduinoPort
            ArduinoConnection.BaudRate = 9600
            ArduinoConnection.DtrEnable = True
            ArduinoConnection.RtsEnable = True
            ArduinoConnection.DataBits = 8
            ArduinoConnection.Parity = Parity.None
            ArduinoConnection.StopBits = StopBits.One
            ArduinoConnection.Handshake = Handshake.None
            ArduinoConnection.Encoding = System.Text.Encoding.ASCII
            ArduinoConnection.Open()
        Catch ex As Exception
            MessageBox.Show("Could not connect" _
                , "Problem", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
        End Try
    End Sub

    Private Sub ButtonSend_Click(sender As Object, e As EventArgs) Handles ButtonSend.Click
        Dim TextToSend As String = TextBoxMessage.Text
        SendMessageToArduino(TextToSend)
        TextBoxMessage.Text = ""
    End Sub

    Private Sub SendMessageToArduino(ByVal Message As String)
        CurrentMessage = Message
        If ArduinoConnection.IsOpen Then
            ArduinoConnection.DiscardInBuffer()
            ArduinoConnection.Write(Message + vbNewLine) '(Message + Environment.NewLine)
        Else
            MessageBox.Show("Could not send" _
                , "Problem", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
        End If
    End Sub

    Private Sub ArduinoConnectionDataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles ArduinoConnection.DataReceived
        DataSentFromArduino = ArduinoConnection.ReadExisting()
        Invoke(SafelyReadDataFromSerialThread, DataSentFromArduino)
    End Sub

    Delegate Sub myMethodDelegate(ByVal [text] As String)
    Dim SafelyReadDataFromSerialThread As New myMethodDelegate(AddressOf UseDataSentFromArduino_InUIThread)

    Private Sub UseDataSentFromArduino_InUIThread(ByVal myString As String)
        TextBoxSerialComm.AppendText(DataSentFromArduino + Environment.NewLine)
    End Sub

    Private Sub ButtonReset_Click(sender As Object, e As EventArgs) Handles ButtonReset.Click
        If ArduinoConnection.IsOpen Then
            ArduinoConnection.Close()
        End If
        ArduinoConnection.BaudRate = 1200
        ArduinoConnection.Open()
        ArduinoConnection.Close()

        TimerRestartArduino.Enabled = True
        TimerRestartArduino.Interval = 10000
    End Sub

    Private Sub TimerRestartArduino_Tick(sender As Object, e As EventArgs) Handles TimerRestartArduino.Tick
        TimerRestartArduino.Enabled = False
        CreateArduinoConnection()
    End Sub

End Class

What do your serial prints tell you? Even if you have to use the monitor and type the VBA output by hand.

If I use the Arduino Serial Monitor, I see absolutely no problems. Sending either "xyz" or "abc" will cause the LED to light, but only when sending from the Arduino Serial Monitor.

Are you sending "abc" or are you sending "abc" followed by a Newline ? If you get a '\n' you add it to the String and then compare the String to "abc" but it has a Newline at the end so does not match

If you feel that you must use Strings then take a look at the Serial.readStringUntil() function Serial.readStringUntil() - Arduino Reference

I’m sending “abc” followed by vbCrLf, so the carriage return line feed is in there with “abc”. As far as I understand vbCrLf is equal to '\n' – perhaps I am wrong in this assumption.

The Arduino code if (inByte != '\n' && (SerialMessage_char < SerialMessageLength -1) ) should call to else if a '\n' is encountered.

The line SerialMessage[SerialMessage_char] = '\0'; will add a null character; but even if this line is commented-out, and a null character is not added, somehow the carriage return line feed still is in the string.

Thanks for the suggestion with the Serial.readStringUntil(). I will see if I can get that to work.

sounds more like Carriage Return and Linefeed to me

If I were you I would take a look at Serial input basics - updated

1 Like

You are indeed.

These are different tests. Try both tests with both xyz and abc.

a7

As I understand '\n' is interpreted as a line feed character. In VB.net vbLf is a line feed character. I have used the following code in the VB app to send the string:
ArduinoConnection.Write(Message + vbLF)

So, it seems logical to me that this would send "abc" plus the line feed. When the Arduino code encountered a line feed, it is supposed to add a null character, but even with the line SerialMessage[SerialMessage_char] = '\0'; commented-out, the string is still not evaluating correctly.

Test for carriage return too: '\r'.

if (inByte != '\n' && (SerialMessage_char < SerialMessageLength -1) )
    {
      SerialMessage[SerialMessage_char] = inByte;

reads to me as "if a Newline is received and the String length has not been reached then ad the Newline to the String". How do you interpret it ?

I don't generally use Strings as I prefer strings, but do Strings need to be terminated with a '\0' as you seem to be doing ?

Do you understand the difference between Strings and strings ?

if (inByte != '\n' && (SerialMessage_char < SerialMessageLength -1) )
    {
      SerialMessage[SerialMessage_char] = inByte;

I read this as "if the byte coming in is not a line feed, and if the byte will not exceed the max length of the message, then add the byte to the message."

This is why I don't understand why the line feed is still on the end of the String.

The following line will add the terminal '\0', but even if this line is commented-out, the String still doesn't equal "abc".

SerialMessage[SerialMessage_char] = '\0';

I've done some reading on strings and Strings and was not too worried about using a String in this case as it was simply a way to test out an project idea.

...I'm still experimenting with the Serial Inputs Basics post and the readStringUntil function. Hopefully, I can work toward a solution, but it sure is frustrating :slight_smile:

My apologies. I missed the negation, but if a Carriage Return is received before the Linefeed then that will be added to the String so it will not equal "abc"

@UKHeliBob I've just finished studying the examples given on the Serial input basics thread you recommended. The thread has been consolidated into a new thread and it sure is worth reading-- thanks so much for recommending it.

@Robin2 has a specific example using start- and end-markers that is particularly suited to what I was trying to do.

The code posted under the example works perfectly with my VB app. For those who might read this in the future, the only thing that has to be changed on the VB app code posted earlier is reflected below on the last line in this snippet:

Private Sub SendMessageToArduino(ByVal Message As String)
        CurrentMessage = Message
        If ArduinoConnection.IsOpen Then
            ArduinoConnection.DiscardInBuffer()
            ArduinoConnection.Write("<" + Message + ">")

...this adds the "<" ">" marks to the message and there is now no need to send the vbLf since the start and end markers make it clear to Arduino what is being sent as a message.

I will re-visit my original code to try to understand exactly why it doesn't work, but at least I can now move forward.

A big thanks to @Robin2 for making this possible.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.