Question Serial port communication problems.

schonertod

Member
Joined
Nov 5, 2010
Messages
9
Programming Experience
1-3
Hey guys new to the forum. I have been playing with visual basic for a few years. I am writing an automation program for an associated research HYPOT tester and one of my current problems is trying to split the data i recieve back from the box.

Currently i have two commands i use
TD? and SALL? both do the same thing but return different data. TD? when sent to the box will return the test results and of course there is no auto return when test is complete so i have to either set some kinda of timer to get the data after the test is complete or just keep pinging the box tell the test returns with either a pass or fail. If any one knows a better way to do that then that would fix one of my other problems

But right now my problem is when i ping the box with TD? it returns

"M11,ACW,test results{pass|fail},1.50,10.00,10ms"

What I am trying to do is use a split command to split that line into strings based off "," as my dilimeter. Currently i am useing this set up

dim resultstring as string = main.serialport1.readexisting
dimresultarray as string = split(resultstring, ",",6)

txtTestResult.Text = resultarray(2)

for the most part is does return the test results but other times it will either error out saying that resultarray(2) is out side the index or it will display one of the other strings (acw or 1.50). Is there a more accurate way to do this. I am also printing the full string pulled from the buffer into a text doc as a data log.
 
Does this communication happen in poll intervals?

This is best guess here is that the split is splitting less than 2 elements ... that's probably due to the fact that the box still did not send the information.
Why don't you use main.serialport1.ReadTo(",") to get one string at a time and trap the Exception in case it times out ???
 
I am not sure what you mean by poll intervals.

I am completly new to RS232 style applications. I am used to running GPIB style and those i normaly can just cheat by using the NI program.

there are two things i need to do with the string coming from the box. I need to pull the status of the test and i need to pring the full string into a log file. I will have to look into the .ReadTo(","). How could i use that to pull the 3rd str that would come out.
 
Remember that every character received by the serial port, stays there in the buffer... sometimes you think you're reading a new message, but it was something received minutes before.
There are commands to read just part of it / clear the buffer / check its size that you must be digging into. And it really depends on how the device you're working with handles the comms. You can always debug.print or send the readings to a textbox to see how the device replies to it, so you can have a good idea on how to handle it properly.

------------------------------

Poll Intervals -> every once a second you read again the message; or every 200ms you read again the message.

VB.NET:
dim dummy as string
dim ThirdString as string

dummy = SerialPort1.ReadTo(",")    ' 1st string gone
dummy = SerialPort1.ReadTo(",")    ' 2nd string gone
ThirdString  = SerialPort1.ReadTo(",")

and after a bit (maybe a Thread.Sleep) you should clear the serial port buffer (I forgot the command) or else next time you try to read there will be that leftovers there.
don't forget to Try_Catch, serial ports are always headache.
 
So i figured out what my problem was. I was trying to read the results faster then the box could return it not to mention you were right about the buffer still hold the last results. So i put in a pause feature making my program wait 100ms before trying to read and now it works fine. the command to clear the buffer is serialport.discardINbuffer.


Now i have a whole new problem and that is i have a test loop for my testing that uses a case select stament to read the test results and depending on what the result is it will either print a line and continue or it will print a line and then flag the test loop to stop. My number one problem is my whole app locks up while test is running. Is there a better way to overcome that other then background worker? I am trying to use background worker right now but it keeps returning an exception stating that my serial port is not open but i know it is.
 
IF... (and that is a big IF )... IF your device replies in a formal way, always sending a message terminator that cannot be confused as part of the message itself, you can use the MessageReceived event from the SerialPort object to deal with it, that means you don't have to pause the UI thread, and it won't hang.

But in case your device is not so nice you can either use background worker or the actual thread class.... background worker is just damn easier to do.
And believe me, BG worker does work fine. I just released V1.00 of a program with 4 background workers communicating with 2 different serial devices and a database

a couple of code examples on how I used it.

here is the MainFrm header
VB.NET:
     Private WithEvents CommsReader As System.ComponentModel.BackgroundWorker
     Private RIGConn As New SerialComm
SerialComm - it's a form class with a private SerialPort inside. The form is a nice friendly drop-down box with the port numbers
CommsReader - repeats every 900ms and call SerialComm methods to Read and Write

and in the MainFrm_load I have
VB.NET:
        My.Settings.RIG_ComPort = RIGConn.Initialise(My.Settings.RIG_ComPort, "fancy title here")

        ' Create our communications reader thread
        CommsReader = New System.ComponentModel.BackgroundWorker
        CommsReader.WorkerReportsProgress = True
        CommsReader.WorkerSupportsCancellation = True
        CommsReader.RunWorkerAsync()
which means, the UI thread is initialising, opening the com port and the BG worker is reading and writing to it.


have fun....
 
so let me see if i get this. when useing BGWorker i need to have it open the serial port? cuz when i tried to use it before it would error out once it tried to do anything with the serial port stating that it was not open when if fact i knew it was. I am still readin up on threading but backgroundworker seems easy but im still confused with how to fully use it. BTW thanks for your help
 
actually is kinda the other way around:
I've open and close the port on my MainForm events... and I read and write to it on the BG worker.
Note that the worker is declared in the same MainForm...

aren't u trying to open and close the port everytime (just as you would do with a database) ???
a com port is a resource that you want to keep lock for as long as you're using it, but be sure to .close at the end

I'll post a skeleton for the Background worker and how I initialised my com port... hope it helps:
Port initialisation:
VB.NET:
        Try
            With myComPort   ' change any of those parameters as needed
                If .IsOpen Then .Close()
                .BaudRate = 19200
                .DataBits = 8
                .DiscardNull = False
                .DtrEnable = False
                .Handshake = Handshake.None
                .Parity = Parity.None
                .ParityReplace = 63
                .PortName = "COM1"   '  Or whatever number you need, remeber you have to write "COM" plus the number
                .ReadBufferSize = 4096
                .ReadTimeout = 5000
                .ReceivedBytesThreshold = 1
                .RtsEnable = False
                .StopBits = StopBits.One
                .WriteBufferSize = 2048
                .WriteTimeout = -1
                .NewLine = vbCr
                .Open()
            End With
            Return true
        Catch ex As Exception  ' Important to Catch and handle this well to make sure everything went smooth
            MessageBox.Show(ex.Message, "CriticalError", MessageBoxButtons.OK, MessageBoxIcon.Error)
            Return false
        End Try

BG worker skeleton:
VB.NET:
Public Class MainFrm
   Private WithEvents CommsReader As System.ComponentModel.BackgroundWorker

   Private Sub MainFrm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      ' Call here the method that initialises the com port
      If(init_com_port() = false) then
            exit sub ' you can't read if it fails to open the port
      End if

      ' Create our communications reader thread
      CommsReader = New System.ComponentModel.BackgroundWorker
      CommsReader.WorkerReportsProgress = True
      CommsReader.WorkerSupportsCancellation = True
      CommsReader.RunWorkerAsync()

   End Sub
   Private Sub CommsReader_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles CommsReader.DoWork
      While Not CommsReader.CancellationPending
         ' do the reading/writing of the com port
         ** read **

         ** write **

         System.Threading.Thread.Sleep(1000)  ' or how long you want it to be
      End While
   End Sub
   Private Sub MainFrm_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
      CommsReader.CancelAsync()
      myComPort.Close()
   End Sub
End Class
 
dude your the man. Out of all the posts i have seen online about BGworker yours by far has to be the best and simple. So inside the Commsreader_dowork the .cancellationpending is a statement for putting in say a cancel button right? all i need a select case statment in side the dowork sub that should be fine right?
 
As a suggestion, when you have read from the Serial Port, do not try and do the processing on the same thread. In my application, I add the data that has been read to a Queue (of String). I then have another thread that does the processing of all strings in the Queue. By doing it this way, the threads can run at different priorities and therefore different speeds.
 
ok i think i broke my application. All of a sudden it seems like my class page is clashing with my main form. I have created a Class called Commands.vb to allow me to create reusable commands that i can call. I open the comport from the main form I click the test btn which checks if the port is open and if it is then it calls the command _commands.Test which writes the command to start the tester. But is errors out saying the port is not open. Yet i tried to open the port from the commands class and it doesnt keep my settings so it errors out saying com1 doesnt exist cuz im on com 3. Why would my class page clash with my main form like this?

FYI if i write the test command into the main form it works fine
 
Ok I have the BG worker working but im having a problem with trying to run commands from my commands class it claims that my port is not open. Is the BG worker not allowed to do that?
Pretty much my code goes like this

btnTEST_click(...)
if SPsite0.isopen then
BGW1.runworkerasync()
end if
end sub

BGW1_dowork(...)
dim flag as integer = 0
me.spsite0.writeline("TEST")
do while flag = 0
Commands.discardRXBuffer()
Pause(4) '= 400ms
commands.Testdata()
Pause(1) '= 100ms
commands.teststatus()
select case my.settings.teststatus()
case "Pass"
'do thing
case "Fail"
Flag = 1
end select
loop
end sub

There is more but this is pretty mush what im doing. i know the test loop works because it works out side of the BGworker my problem is once i hit the discardRXbuffer is errors saying port closed but yet it starts the test just fine. Any help
 
please, whenever posting code use the CODE tag.
regarding your problem I really don't know, I don't remember any framework problems related to that, so maybe you're closing it somewhere else.
try to run the thing with a breakpoint in any place you call SPsite0.close

remember that this thing is looping again and again, and you're not re-testing the IsOpen bit.

dude your the man.
thanks
So inside the Commsreader_dowork the .cancellationpending is a statement for putting in say a cancel button right?
after the Cancel Async command is executed the cancellation pending goes to True and your thread stops.
VB.NET:
CommsReader.CancelAsync()
So, yeah, it can be a cancel button, I suggest you to also do it on form close to make sure everything stops.
 
Sorry i didnt see the code Insert button but i guess you only get that with the advanced reply not the quick reply.

So if I add all the codes in manuly and not call them from the class it has no problems running and in fact its running better then i was expecting.

Im still very new to backgroundworkers and serial ports. Im used to working with GPIB setups and normaly i can just steal the global codes from the NI automation software.

The thing about the .close is i dont have any code to auto turn it off unless i close the program. I have a button i use to close the port when needed. The thing about my app is its for automation bench testing with a handler. so the way my SW is set up is i turn the ports on run a demo test to make sure all four sites work and then i push start and it tells the handler to place the first set of devices and then it runs them and bins them according to the test results.
 
Back
Top