Beginner's Question About Serial Ports

jbrookley

Member
Joined
Jan 8, 2009
Messages
11
Programming Experience
1-3
Hello. I'm primarily a hardware engineer but I just recently started working with microcontrollers and I'm now working on my software coding. I programmed an Atmel chip to receive data from the RS232 port and send it back to the computer where it is received successfully by hyperterminal.

I am now trying to make a VB.net application (using VB Express 2008) that will send data to the RS232 port where the microcontroller will send it back and it can be viewed on hyperterminal.

Below is the code I've been working with. I basically have a button (Button2) that opens and closes the serial port, textbox 4 where I can write code to be sent, and button3 which sends the code to the RS232 port. It should display what is sent as well as what is received on listbox1.

Enclosed is the code I have:

VB.NET:
Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        If ((CheckBox1.Checked = True) And (CheckBox2.Checked = True)) Then
            TextBox1.Text = "Both"
        ElseIf (CheckBox1.Checked = True) Then
            TextBox1.Text = "One"
        ElseIf (CheckBox2.Checked = True) Then
            TextBox1.Text = "Two"
        Else
            TextBox1.Text = "You suck"
            TextBox2.Clear()
            MsgBox("Learn to Read, Noob!", MsgBoxStyle.Critical, "YOU FAIL")
        End If
    End Sub

    Private Sub CheckBox2_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CheckBox2.CheckedChanged

    End Sub

    Private Sub CheckBox1_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CheckBox1.CheckedChanged

    End Sub

    Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
        TextBox2.Text = "You should pick one . . ."
        If (ComboBox1.SelectedItem = "Apple") Then
            TextBox2.Text = "Apple!"
        ElseIf (ComboBox1.SelectedItem = "Orange") Then
            TextBox2.Text = "Orange!"
        ElseIf (ComboBox1.SelectedItem = "Monkey") Then
            TextBox2.Text = "Monkey!"
        ElseIf (ComboBox1.SelectedItem = "Donkey") Then
            TextBox2.Text = "Donkey!"
        End If
    End Sub

    Private Sub Label1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Label1.Click

    End Sub

    Private Sub Label2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Label2.Click

    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    End Sub

    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)

    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        If SerialPort1.IsOpen = False Then
            SerialPort1.Open()
            If SerialPort1.IsOpen() Then
                CheckBox3.Checked = True
                TextBox3.Text = "Port Open"
            Else
                CheckBox3.Checked = False
                TextBox3.Text = "Error: Port Closed"
            End If
        ElseIf SerialPort1.IsOpen = True Then
            SerialPort1.Close()
            If SerialPort1.IsOpen() Then
                CheckBox3.Checked = True
                TextBox3.Text = "Error: Port Open"
            Else
                CheckBox3.Checked = False
                TextBox3.Text = "Port Closed"
            End If
        End If
    End Sub

    Private Sub TextBox3_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)

    End Sub

    Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
        ListBox1.Items.Add("Received: " + SerialPort1.ReadLine())
    End Sub

    Private Sub CheckBox3_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CheckBox3.CheckedChanged

    End Sub

    Private Sub TextBox3_TextChanged_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox3.TextChanged

    End Sub

    Private Sub Button3_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        SerialPort1.WriteLine(TextBox4.Text)

        ListBox1.Items.Add("Sent: " + TextBox4.Text)
    End Sub

    Private Sub TextBox4_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox4.TextChanged

    End Sub
End Class

I apologize for having some additional code (I've just been playing with this, learning how everything works) so some of it is unrelated but I figured I'd post everything just in case.

The error I'm seeing is:

"Cross-thread operation not valid: Control 'ListBox1' accessed from a thread other than the thread it was created on."

Does anyone happen to know what this error entails or how I can fix it? Please let me know when you get the chance. Thanks in advance!
 
Whenever you have an issue the very first thing you should always do is read the relevant documentation. Sometimes it can be more difficult to identify what's the relevant documentation than others but the more experience you get the easier it will become.

The problem is arising because you're accessing your ListBox from the DataReceived event handler, which is executed in a background thread. This is from the MSDN documentation for the DataReceived event says this:
The DataReceived event is raised on a secondary thread when data is received from the SerialPort object. Because this event is raised on a secondary thread, and not the main thread, attempting to modify some elements in the main thread, such as UI elements, could raise a threading exception. If it is necessary to modify elements in the main Form or Control, post change requests back using Invoke, which will do the work on the proper thread.
It provides a link to the documentation for the Control.Invoke method that shows you how to use it. Here's a condensed version that will work in your case:
VB.NET:
Private Delegate Sub AddListBoxItemInvoker(ByVal item As Object)

Private Sub SerialPort1_DataReceived(ByVal sender As Object, _
                                     ByVal e As IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
    Me.AddListBoxItem(Me.SerialPort1.ReadLine())
End Sub

Private Sub AddListBoxItem(ByVal item As Object)
    If Me.ListBox1.InvokeRequired Then
        'We are on a secondary thread so delegation is required.
        Me.ListBox1.Invoke(New AddListBoxItemInvoker(AddressOf AddListBoxItem), _
                           item)
    Else
        'We are on the primary thread so add the item.
        Me.ListBox1.Items.Add(item)
    End If
End Sub
 
Perfect. Thanks so much. The program is now working and is receiving the data from my microprocessor. I knew it had to be something simple and it was driving me crazy.

Honestly, I didn't know where to look for documentation for this problem so knowing to check Microsoft's MSDN site is very helpful. I'm used to all my devices having datasheet for each piece of hardware. I'm still new to my software side. Anyway, knowing where to look now, I found the link you were referring to as well as the note you mentioned:

SerialPort.DataReceived Event (System.IO.Ports)

Thanks again!
 
If you haven't already you should install the MSDN Library locally. If you're using VB Express you can download MSDN Express from the same web page. That way you have integration with VS so you can use the F1 key and the Help menu. The most useful tool is the index, so you can go straight to documentation for a specific type or member without having to search.
 
Back
Top