[Resolved] VB6 with Uno serialprint to text box

Hi for those who understand VB6.

I found some code and added it in my project to remotely see some data at the PC

UNO sends:

      //send data to serial port for debugging/read data at the PC                       
      Serial.println(sensorValue); //max 3 digits
      Serial.println(brakeValue);   //max 3 digits
      Serial.println(speedcurveValue); //max 3 digits
      Serial.println(brakecurveValue); //max 3 digits
      Serial.println(speedstartValue); //max 3 digits
      Serial.println ("\t"); //use this to indicate end of datastream for next loop to detect
      delay(50);

While reading the data at the PC it needs to check if where to start so the 5 text boxes are filled with the correct values.
If I leave this line out: Serial.println ("\t "); it starts everytime after opening and closing the vb program it writes every time in a different box.
But if I add it it will not read with the below vb code.
So the code should search for the Tab and then display the next cyclus of data and put them in the text boxes.
I have tried numerous things like treshhold higher but I got lost in the things.
Any suggestion would be welcome

Paco

Private Sub Form_Load()
  With MSComm1
        If .PortOpen Then .PortOpen = False
        .CommPort = 4
        .Settings = "9600,N,8,1"
        .DTREnable = True
        .RTSEnable = True
        .RThreshold = 1
        .SThreshold = 0
        .PortOpen = True
  End With
  With Text1
    .BackColor = vbWhite
    .Locked = True
    .Text = ""
  End With
 End Sub

Private Sub MSComm1_OnComm()

Static Buffer As String
   Buffer = Buffer & MSComm1.Input
   If InStr(Buffer, vbCrLf) Then
      Dim TempBuffer() As String
      TempBuffer = Split(Buffer, vbCrLf)
       If UBound(TempBuffer) >= 5 Then
            Text1.Text = TempBuffer(0)
            Text2.Text = TempBuffer(1)
            Text3.Text = TempBuffer(2)
            Text4.Text = TempBuffer(3)
            Text5.Text = TempBuffer(4)
            Dim I As Integer
            Buffer = ""     'cleanup the Static buffer
            For I = 5 To UBound(TempBuffer) - 1
               'retain any extra data
               Buffer = Buffer & TempBuffer(I)
            Next I
        End If
   End If
End Sub

The problem is that with serial data they do not come in all at once.
Every line printed from the Arduino sends an CRLF but your VB code thinks that you have all 5 fields after every CRLF. Read your code to confirm this

So your test should be a test for "\t" or vbTAB if that exists instead

Static Buffer As String
   Buffer = Buffer & MSComm1.Input
   If InStr(Buffer, "\t") Then                        ' if the TAB char found then all 5 fields are in.
      Dim TempBuffer() As String
      TempBuffer = Split(Buffer, vbCrLf)
       If UBound(TempBuffer) >= 5 Then
            Text1.Text = TempBuffer(0)
            Text2.Text = TempBuffer(1)
            Text3.Text = TempBuffer(2)
            Text4.Text = TempBuffer(3)
            Text5.Text = TempBuffer(4)
            Dim I As Integer
            Buffer = ""                                      ' empty the Static buffer
            For I = 5 To UBound(TempBuffer) - 1
               ' retain any extra data
               Buffer = Buffer & TempBuffer(I)
            Next I
        End If
   End If

Hi Rob (Hallo :P)

Thanks for your answer.

I raised the delay in the UNO from 50 to 200 in the original VB code and it works. :slight_smile:
I am new to this serial stuff and for the purpose of the program to read the UNO I rather do not want to have any delay.

Is this possible?

I added the Tab just to make sure the difference between CRLF and TAB in VB when you need to search for the start and end of the information which is put in a buffer.
Do not know if this is really needed if I like to speed up things to have real time information gathered from the UNO to the PC program.

Paco

(The Netherlands)

To support what I like to accomplish
http://arduino.cc/forum/index.php/topic,93528.0.html
a screen shot of the simple PC control panel.

Data created or set in the slotrace speed controller need to be changed or read by the PC control program.
The speed and brake graph need to show in future the curve the trigger makes or is set compared to the motion of the speedtrigger.

When that is completed I like to add Bluetooth to the slot race speed controller so we can datalog all data during racing and graph each lap realtime to see where time is lost or to be gained. First PC then Adroid app.

Paco

ScreenHunter_01 Mar. 10 12.44.jpg

Hoi Paco,

We'll keep the discussion in English (but you can PM me in dutch if you want to).

The Arduino sends the bytes at a certain speed, so it takes (serious) time before they arrive at the PC. You don't need to add the delay in the UNO (unless the transmit buffers overflows)

Increase the serial speed to 115200 as that is 12x as fast as 9600, (both in VB and Arduino)

I added the Tab just to make sure the difference between CRLF and TAB in VB when you need to search for the start and end of the information which is put in a buffer.
Do not know if this is really needed if I like to speed up things to have real time information gathered from the UNO to the PC program.

The check for TAB is really needed !! as in your protocol the TAB is a record separator and the CRLF is a field separator.

The arduino sends records with 5 values to the PC. These position of the individual values within the record define their meaning. The values are separated by CRLF and the records are separated by TAB's. If records were separated by CRLF you would never know where a new record starts.

As detecting the TAB separator automatically implies you have at least 5 fields the code does not need to test this.

Static Buffer As String
   Buffer = Buffer & MSComm1.Input
   If InStr(Buffer, "\t") Then                        ' if the TAB char found then all 5 fields are in.
      Dim TempBuffer() As String
      TempBuffer = Split(Buffer, vbCrLf)

            Text1.Text = TempBuffer(0)
            Text2.Text = TempBuffer(1)
            Text3.Text = TempBuffer(2)
            Text4.Text = TempBuffer(3)
            Text5.Text = TempBuffer(4)
            Dim I As Integer
            Buffer = ""                                      ' empty the Static buffer
            For I = 5 To UBound(TempBuffer) - 1
               ' retain any extra data
               Buffer = Buffer & TempBuffer(I)
            Next I

   End If

Hopes this helps.

Thanks Rob,

We stay in English here, so more people can learn from my mistakes. :wink:

Upped the speed in UNO and PC to 115200 bps and removed the dealy in the UNO.

Added your code and expanded it a little for more parts of data gathering from the UNO.
I also changed the "\t" to "vbTab" as it did not split the dimbuffer with it as it did not recognized the "\t"

Now I get some runtime error 9 Subscript out of range on for example the temp4 = tempbuffer(3) line.
So I changed the textboxes and read the buffer to a long declared string
Same problem.
I also see in the text boxes when the code stops that there sometimes othe characters in the textbox.
They are shown in the text box as a thick black vertical stripe and in the debug screen as square.

So it looks like the splitting is not quick enough?
Do not know if that causes the script out of range problems as a result.

Private Sub MSComm1_OnComm()

Static Buffer As String
Dim temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8 As String

   Buffer = Buffer & MSComm1.Input
   Text9.Text = Buffer                                ' temp Debug window textbox
   If InStr(Buffer, vbTab) Then                        ' if the TAB char found then all 8 fields are in.
      Dim TempBuffer() As String
      TempBuffer = Split(Buffer, vbCrLf)
            temp1 = TempBuffer(0)
            temp2 = TempBuffer(1)
            temp3 = TempBuffer(2)
            temp4 = TempBuffer(3)
            temp5 = TempBuffer(4)
            temp6 = TempBuffer(5)
            temp7 = TempBuffer(6)
            temp8 = TempBuffer(7)
            Text1.Text = temp1
            Text2.Text = temp2
            Text3.Text = temp3
            Text4.Text = temp4
            Text5.Text = temp5
            Text6.Text = temp6
            Text7.Text = temp7
            Text8.Text = temp8
            Dim I As Integer
            Buffer = ""                                      ' empty the Static buffer
            For I = 8 To UBound(TempBuffer) - 1
               ' retain any extra data
               Buffer = Buffer & TempBuffer(I)
            Next I

   End If
End Sub

The check for TAB is really needed !! as in your protocol the TAB is a record separator and the CRLF is a field separator.

Which, of course, is quite unusual. Sending value, tab, value, tab, value, tab, value, tab, value, CR, LF would make a lot more sense.

paulsa

      //send data to serial port for debugging/read data at the PC                       
      Serial.print(sensorValue);
      Serial.print("\t");
      Serial.print(speedstartValue);
      Serial.print("\t");  
      Serial.print(speedcurveValue);
      Serial.print("\t");
      Serial.print(brakeValue);               
      Serial.print("\t");
      Serial.print(brakecurveValue);
      Serial.print("\t");
      Serial.print(sensorMin);
      Serial.print("\t");
      Serial.print(sensorMax);
      Serial.print("\t");
      Serial.println(modelName);
      //delay(500);

So Serial.println is the CRLF?

Then I changed the way of detecting the Tab and CrLf the otherway around but same problem.

Private Sub MSComm1_OnComm()

Static Buffer As String
Dim temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8 As Long

   Buffer = Buffer & MSComm1.Input
   Text9.Text = Buffer                                ' temp Debug window textbox
   If InStr(Buffer, vbCrLf) Then                        ' if the TAB char found then all 8 fields are in.
      Dim TempBuffer() As String
      TempBuffer = Split(Buffer, vbTab)
            temp1 = TempBuffer(0) 'speed
            temp2 = TempBuffer(1) 'start speed
            temp3 = TempBuffer(2) 'speed curve
            temp4 = TempBuffer(3) 'brake
            temp5 = TempBuffer(4) 'brake curve
            temp6 = TempBuffer(5) 'modelname
            temp7 = TempBuffer(6) 'sensorMin
            temp8 = TempBuffer(7) 'sensorMax
            Text1.Text = temp1
            Text2.Text = temp2
            Text3.Text = temp3
            Text4.Text = temp4
            Text5.Text = temp5
            Text6.Text = temp6
            Text7.Text = temp7
            Text8.Text = temp8
            Dim I As Integer
            Buffer = ""                                      ' empty the Static buffer
            For I = 8 To UBound(TempBuffer) - 1
               ' retain any extra data
               Buffer = Buffer & TempBuffer(I)
            Next I

   End If
End Sub

So Serial.println is the CRLF?

Serial.println() does exactly the same stuff as Serial.print() with the addition that it sends a carriage return and line feed to the serial port, too (after the data it sends).

So, yes, I think that is a better way to send the data.

   If InStr(Buffer, vbCrLf) Then                        ' if the TAB char found then all 8 fields are in.

When the code and the comments disagree, the comment doesn't serve much purpose, does it?

So, what IS in buffer when this function returns true?

What is in the TempBuffer elements? Why do you need to when assign those strings to floats, and then assign the floats to text fields? Seems like a lot of overhead when what you want is to get string data from the serial port and display it is string fields on the form.

            Buffer = ""                                      ' empty the Static buffer
            For I = 8 To UBound(TempBuffer) - 1
               ' retain any extra data
               Buffer = Buffer & TempBuffer(I)
            Next I

What extra data? What about the tabs that used to separate the fields?

Paul,

As you see I followed your advise and changed the way UNO sends the data.
Sorry for disagreement is comments. I hope it never happens again. but I cant promiss it. :grin:

I copied the code from the net and I am slowly adapting it to my needs and maybe others.
I am new to this serial stuff and as I did not wrote this original code it might be that some things are left I do not have the knowledge for now to understand. But I am always willing to learn as I learn every day.

For your question about:

Buffer = ""                                      ' empty the Static buffer
            For I = 8 To UBound(TempBuffer) - 1
               ' retain any extra data
               Buffer = Buffer & TempBuffer(I)
            Next I

I have tried to understand it but I do not.
You mean that this is not needed or do I need to change the code in general?

Paco

The Split command earlier on creates an array of strings, by splitting the specified string at the tabs. If the specified string contains 7 tabs, as yours should, you would get exactly 8 strings in the output array. That bit of code is dealing with the 9th and on substrings. Unless there is an error in communication, you shouldn't need that code.

If there is an error in communication, and there are more than 8 values in the packet, you probably want to discard the whole packet, rather than use the first 8 values on the first pass, and the rest on the next pass (with more added...)

If you are going to keep that code, though, when you re-create the original buffer, minus the first 8 values, you need to put the tabs back between the values as you reassemble the string.

Paul,

Understand 99% what you explain. Thanks
BTW. If I comment these lines still got the same error.

So what I know and understand.
The oncomm event puts data in the buffer.
When the CRLF is found it stops putting data in the buffer and assuming all 8 value are there due to the Crlf at the end.
Then it sorts the buffer on the tab's and put each value in a textbox.
In the end it clears the buffer.
Start all over again.

Now one thing I might have overlooked in this copied code what if the buffer is not filled from value 1 but starts at value 4 and then the CRLF is received.
This would be a false data assumption.
How does it know all 8 values are in? It only looks at the CrLf assuming all data is in?
Wouldnt it be better to add a start marker (startbit) then the data and then the CrLF (stopbit)
Then only sort the data if the full line from start to stop bit is received.

Paco

I tried some more with the current code and reduced speed to 9600 bps and no delay in the UNO code

I can start the program several times in arow but without unknown cause it hangs with subscript out of range 1 out of 10.
It always happens in the part where the array is splitted by the tab.
When I commented all those except for line one and two there it runs fine.
But the more I ask to be splitted from text3.text the more the program stops.
This looks like a fundemental problem in splitting the array to the textboxes.
When it needs to split it does it correctly and the values go to the correct textbox.

Paco

I also see in the text boxes when the code stops that there sometimes othe characters in the textbox.
They are shown in the text box as a thick black vertical stripe and in the debug screen as square.

Probably VB interpretation of CRLF in a textBox

More debugging done.

I currently use an other code in VB, Uno still the same 9600 and no delay.
But the eratic problem out out of script stays.
When there is no error the data is in the correct boxes.

Private Sub MSComm1_OnComm()

Static strBuffer As String
  With MSComm1
    'test for incoming event
    Select Case .CommEvent
        Case comEvReceive
            '
            ' Something to receive
            ' Receive it and add to our static Buffer
            '
            strInput = .Input
            strBuffer = strBuffer & strInput
            Do
                '
                ' Check if there's a complete record in the Buffer
                ' NOTE: This code assumes that the sender terminates
                ' each record with a Carriage Return Line Feed Pair
                ' If this is not the case then change vbCrLf below
                ' to whatever the terminator is
                '
                intPos = InStr(strBuffer, vbCrLf)
                If intPos <> 0 Then
                    '
                    ' Yes, there is a complete record
                    ' Extract it from the Buffer and process it
                    '
                    
                    strInput = Mid$(strBuffer, 1, intPos - 1)
                    str = Split(strInput, vbTab)
                    Text9.Text = strInput
                    Text1.Text = str(0)
                    Text2.Text = str(1)
                    Text3.Text = str(2)
                    Text4.Text = str(3)
                    Text5.Text = str(4)
                    Text6.Text = str(5)
                    Text7.Text = str(6)
                    Text8.Text = str(7)
                    '
                    ' Check if there's anything else in the Buffer
                    '
                    If intPos + 1 < Len(strBuffer) Then
                        '
                        ' Yes, move it to the front of the Buffer
                        ' and go round the loop again
                        '
                        strBuffer = Mid(strBuffer, intPos + 2)
                    Else
                        '
                        ' Nothing left in the Buffer
                        ' Flush it and signal to exit the loop
                        '
                        strBuffer = ""
                        boComplete = True
                    End If
                Else
                    '
                    ' Haven't got a complete record yet
                    ' exit the loop and wait for the next
                    ' comEvReceive event
                    '
                    boComplete = True
                End If
            Loop Until boComplete = True
        End Select
  End With 'MSComm1
  Dim temp As Long

' ARProgressBar1.Value = Text1.Text 'str(0) 'temp2 '150 'str(1)
   
End Sub

Problem I encounter and debug when script out of range appears:
If line Text7.Text = str(6) is out of range it is the str(6) value that causes the problem out of range.
The strBuffer has 17 data blocks which are clearly seperated by single (VBTAB) and double blocks (VBCRLF) .
Now this line should count back for the 8 values needed: strInput = Mid$(strBuffer, 1, intPos - 1)? Or do I misunderstand
The strInput only has 5 values ..... "-150-1-200-420-0" .......... the dashes show in VB debugger as a square block.
There should be 8 values?
intPos = 17

str(0) = ""
str(1) = "155"
str(2) = "1"
str(3) = "200"
str(4) = "420"
str(5) = "0"

The 8 data values should be : 11-120-115-155-1-200-420-0
What goes wrong?
Although there are enough datablocks in the buffer the splitter detects less despite the clear difference between vbtab and crlf.
Is it so hard to get some simple plain data (no commas or points) out of the UNO? :cold_sweat:

Any suggestion to this bottleneck is appriciated.

One way to get it better is to ket the Arduino send "id: value \n" pairs. Th id indicates the datafield and the value its value.

Then you wil get an id and a value so you know which textbox to set. The added value of this way is that you can process per field iso all fields at once. You can even send different fields with different frequencies.

Give it a try.

Rob,

That is an option and I have to look into that how to achieve.
But this basic stuff should work too?
Like said as soon as the program runs OK it is displaying the correct data in the correct boxes.
It hangs on the first or two loops of the splitting.

I downloaded from the MSDN side a oncomm sample.
I ran this to a text box and viewed it a few times after start up.
When the program runs mostly the first 2 lines are missing data.
The first line is never correct.
After this the data looks fine.

So I just thougth of taking out (throw away) the first 3 readings of the oncomm.
I think the splitting and out of range is the due to this start up of the receiving of data in the oncomm event.
Have to see if I can mange this garbage stuff.

Paco

As we have 8 values with 7 tabs extracted from the buffer I like to perform this comparison.

                    strInput = Mid$(strBuffer, 1, intPos - 1)
                    strCheck = InStr(strInput, vbTab)' check if there are enough tabs
                    If strCheck < 7 Then' if we do not have enough tabs
                     'exit loop 'exit the current parsing loop
                    End If

So if we do not have 7 tabs we are sure we do not have all data for one reason or an other so we have to exit the loop and do not need to split the data as this is the cause of the problem.
Why is the exit loop commented? Lack of my ability to code properly :slight_smile:
But it explains what I try to achieve code wise

Paco

The first line is never correct.

So you have discovered that for a good protocol between sender and receiver you not only need field separators and record separators but also a record start character to get synchonization :slight_smile:

Still I propose you change the system that you not wait for 7 or 8 fields but just for a field value pair. This makes it also easier to expand in the future!

I am busy with it.

Paco