שתף באמצעות


Auto Detect Serial Port Arduino - Visual Studio VB

Question

Thursday, March 3, 2016 5:32 PM

Hello,

I am creating a script to auto-detect the arduino on the serial port. For some reason the code I found for this only displays ONE port even if there are TWO ports available. Arduino is on COM5. Any help will be greatly appreciated.

If I run the below code, I get COM1 & COM5:

    Sub GetSerialPortNames()
        For Each sp As String In My.Computer.Ports.SerialPortNames
            lstPorts.Items.Add(sp)
        Next
    End Sub

But if I run this, I only get COM1:

        Dim connectionScope As New ManagementScope()
        Dim serialQuery As New SelectQuery("SELECT * FROM Win32_SerialPort")
        Dim searcher As New ManagementObjectSearcher(connectionScope, serialQuery)
        Dim desc As String
        MsgBox(searcher.Get.Count) 'Displays only one port
        Try
            For Each queryObj As ManagementObject In searcher.Get()
                desc = queryObj("Name").ToString
                MsgBox(queryObj("Name")) 'Only shows COM1
                If (desc.Contains("Arduino")) Then
                    MsgBox(queryObj("Name"))
                End If
            Next

        Catch err As ManagementException
            MessageBox.Show("An error occurred while querying for WMI data: " & err.Message)
        End Try

All replies (16)

Friday, March 11, 2016 12:11 AM ✅Answered

Got it Cyrille.

    Private Sub autoconnect()
        For Each sp As String In My.Computer.Ports.SerialPortNames
            Try
                SerialPort1 = New SerialPort(sp, 9600, Parity.None, 8, StopBits.One)
                SerialPort1.ReadTimeout = 700
                SerialPort1.WriteTimeout = 700
                SerialPort1.Open()

                Dim ListeningWatch As New Stopwatch
                Dim serialMessage As String

                SerialPort1.Write("Arduino")

                ListeningWatch.Start()
                While ListeningWatch.ElapsedMilliseconds < 700 And ListeningWatch.IsRunning
                    serialMessage = SerialPort1.ReadLine() 
                    If serialMessage.Contains("Arduino") Then
                        ListeningWatch.Stop()
                        btnConnect.Text = "Disconnect"
                        ArduinoConnected = True
                        lstConsole.Items.Add("Arduino Connected")
                        Exit For
                    End If
                End While
            Catch ex As TimeoutException
            End Try
        Next
        If ArduinoConnected = False Then
            MsgBox("Arduino failed to connect. Please check that it is plugged in.")
        End If
    End Sub

Thursday, March 3, 2016 5:52 PM

I'm not too sure why you are doing a sql query here.

What I use for enumerating the available ports into a selectable combobox is:

don't forget to Imports System.IO.Ports

        Dim myPort As Array 'Array to hold the COM detected

        myPort = IO.Ports.SerialPort.GetPortNames() 'Get the portnames for the IO.Ports.SerialPort 

        'Loading COM into combobox
        ComboBox9.Items.AddRange(myPort)

Thursday, March 3, 2016 6:50 PM

I want to autodetect the arduino instead of adding the com ports to a combobox. So I need to analyze the description associated with the ports until I find "Arduino" rather than looking just at the port number.

 here is the original explanation of how to do it in C#

http://stackoverflow.com/questions/3293889/how-to-auto-detect-arduino-com-port


Thursday, March 3, 2016 7:00 PM

I see, sorry for the confusion about WMI...

What's your connectionScope parameter looking like? root\cimv2 maybe?


Thursday, March 3, 2016 8:50 PM

For some reason the code I found for this only displays ONE port even if there are TWO ports available. Arduino is on COM5. Any help will be greatly appreciated.

When you use My.Computer.Ports what are the names that you get?

When you examine the ports in device manager, what names are listed?

What is the hardware for these ports?  In some cases virtual ports report incorrect names.


Thursday, March 3, 2016 10:14 PM

COM1 and COM5

COM1  - Microsoft Raw Port
COM5  - Arduino

Both show up in the Device Manager and in the combo box so I can manually select the port but if I run the other code to have it done automatically it only finds one port called COM1 Communications Port. If I could only see the port with the code, then auto-detecting the arduino would work.


Friday, March 4, 2016 12:34 AM

I tried that first and it did the same thing then changed the code to the above. Should I put those paramaters back in and change that root\cimv2 to something else?


Friday, March 4, 2016 2:04 AM

Have you seen this?

http://www.codeproject.com/Articles/32330/A-Useful-WMI-Tool-How-To-Find-USB-to-Serial-Adapto

The screen shot would indicate that the query should be SELECT * FROM MSSerial_PortName.  Most likely the Win32_SerialPort only refers to hardware based serial ports, not virtual ports.  MSSerial_PortName likely includes all serial adapters, both physical and virtual.

Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


Saturday, March 5, 2016 3:40 AM

That seems promising Reed! But I still can't get it to work yet. I tried it in my code and also downloaded the tool and clicked on "Find USB-Serial converters using WMI" but I get "An error occurred while querying for WMI data: Access denied".

Also downloaded the official tool from microsoft and got access denied. I am logged in as the administrator on this PC not sure what else it could be.

EDIT: I checked the COM Security  "Access Permissions" and "Launch and Activation Permissions" all local access are set to allow. I restarted my PC too just in case recent windows updates were messing with it. Also tried it first thing after rebooting to make sure nothing else was interfering.


Saturday, March 5, 2016 6:14 AM

If I run the WMI tool (right click run as admin) it works. Problem is autodetecting arduino is supposed to be a fool-proofing thing. If I need to ask people to run as admin, might as well tell them to check the ports by connecting and disconnecting the arduino.


Saturday, March 5, 2016 7:45 PM

If you now just need your application to automatically run as admin, add a new app.manifest file to the project and then edit the requestedExecutionLevel element, setting Level="requireAdministrator".

Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


Saturday, March 5, 2016 11:30 PM

I wonder if you aren't going through a lot of effort for nothing...  I'd be willing to bet that anyone who knows what an Arduino is also knows enough to figure out which COM port it is using.  Considering that every tutorial on getting started with the hardware includes instructions on finding the COM port, I think it would be safe to assume that users of your application could select the correct COM port for your software.

Now then, if your software is meant to work with some specific firmware running on an Arduino, then discovering a COM port with the "Arduino" description is not sufficient.  Suppose the user plugged in some other Arduino that wasn't running the intended firmware? If this is the scenario, then it may be better to poll each COM port with a specific command which will identify the correct device. For example, if the firmware automatically sends some welcome string or command prompt when connecting, your software can open each available serial port and look for that string.

I guess the main point here is that the description of the serial port may not be as useful as it might first appear, depending on how you are wanting to use the information.

Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


Tuesday, March 8, 2016 7:10 AM

This sounds promising! How do I add a new app manifest file? Last time I changed something in a config file it killed the application.

I want to have this done automatically because I am creating a finished product, not a kit. They won't know what an Arduino is. Just open this app on your PC, connect the box, and everything works.


Tuesday, March 8, 2016 9:04 PM

GOT IT WORKING! Basically I cycle through all the ports, ping them and wait half a second for them to respond. If they respond "Arduino", then I leave that port open. I had already tried to do this before but couldn't figure out how to keep the other subs going with the timer active. If you have any suggestions on how to simplify the below I am all ears. I am sure many will benefit from it. Hopefully sending "Arduino" to some random port doesn't cause some self-destruct thing :)

Imports System.IO.Ports

'in public class:

        Dim ArduinoConnected As Boolean

'in main window form load:

        Timer2.Enabled = False
        ArduinoConnected = False


 Private Sub autoconnect()
        For Each sp As String In My.Computer.Ports.SerialPortNames
            Try
                SerialPort.PortName = sp
                SerialPort.BaudRate = 9600
                SerialPort.DataBits = 8
                SerialPort.Parity = Parity.None
                SerialPort.StopBits = StopBits.One
                SerialPort.Handshake = Handshake.None
                SerialPort.Encoding = System.Text.Encoding.Default
                SerialPort.Open()
                SerialPort.Write("Arduino")
                Timer2.Interval = 500
                Timer2.Enabled = True
                While Timer2.Enabled And ArduinoConnected = False
                    Application.DoEvents()
                End While
                If ArduinoConnected Then
                    Exit For
                End If
                SerialPort.Close()
            Catch ex As Exception
                MsgBox(ex.Message)
            End Try
        Next
    End Sub

    Public Sub Timer2_Tick(sender As Object, e As EventArgs) Handles Timer2.Tick
        Timer2.Stop()
    End Sub

    Public Sub SerialPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort.DataReceived
        Dim str As String = SerialPort.ReadExisting()
        If str.Contains("Arduino") Then
            ArduinoConnected = True
            lstConsole.Items.Add("Arduino Connected")
        End If
    End Sub

Tuesday, March 8, 2016 10:21 PM

Your Timer2 is doing it's cycle only once, and you are defeating the Timer threading ability by doing a While loop (The While...Doevents is not necessary when using a Timer... that's the all point of using a Timer.).

And since you are doing only one cycle with your Timer, maybe you should just use a StopWatch, basically you are waiting for the answer for 500ms... so do a  While StartTime-Now <500  ReadLine...

Although it is nice to spell out the parameters for your serialport, you are not (yet?) using parameters, also using the class name as object name is looking for confusion down the Strict programming road so rename the object.

Have a look at this:

        Dim _serialPort As SerialPort

        _serialPort = New SerialPort("sp", 9600, Parity.None, 8, StopBits.One)
        _serialPort.Handshake = Handshake.None 'The default here... why bother?
        _serialPort.Encoding = System.Text.Encoding.Default 'Again the Default...
        ' What about the TimeOuts? need to handle the exceptions if used
        '_serialPort.ReadTimeout = 500
        '_serialPort.WriteTimeout = 500
        _serialPort.Open()

        Dim ListeningWatch As New Stopwatch
        Dim serialMessage As String

        _serialPort.Write("Arduino")

        ListeningWatch.Start()

        While ListeningWatch.ElapsedMilliseconds < 500 And ListeningWatch.IsRunning
            serialMessage = _serialPort.ReadLine() 'wait for a line until the timeout time is reached
            If serialMessage.Contains("Arduino") Then
                ListeningWatch.Stop()                'Do the other stuff here to get out of the For loop too
            End If
        End While

Thursday, March 10, 2016 6:52 PM

Thanks Cyrille. I am having trouble getting this new code to work. It does not read anything from the arduino. Also, in the console I get a bunch of: Exception thrown: 'System.TimeoutException' in System.dll

   Private Sub autoconnect()
        Dim ListeningWatch As New Stopwatch
        Dim serialMessage As String
        For Each sp As String In My.Computer.Ports.SerialPortNames
            serialMessage = Nothing
            ListeningWatch.Reset()
            Try
                _SerialPort = New SerialPort(sp, 9600, Parity.None, 8, StopBits.One)
                _SerialPort.ReadTimeout = 500
                _SerialPort.WriteTimeout = 500
                _SerialPort.Open()

                _SerialPort.Write("Arduino")
                ListeningWatch.Start()

                While ListeningWatch.ElapsedMilliseconds < 500 And ListeningWatch.IsRunning
                    serialMessage = _SerialPort.ReadLine() 
                    If serialMessage.Contains("Arduino") Then
                        ListeningWatch.Stop()
                        btnConnect.Text = "Disconnect"
                        ArduinoConnected = True
                        lstConsole.Items.Add("Arduino Connected")
                    End If
                End While
                ListeningWatch.Stop()
            Catch ex As TimeoutException
                _SerialPort.Close()
            End Try
        Next
        If ArduinoConnected = False Then
            MsgBox("Arduino failed to connect. Please check that it is plugged in.")
        End If

    End Sub