LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Reading serial port when some character has appeared

Solved!
Go to solution

How does one wait until some specific character has appeared at the serial port (eg COM1 RS232 port on PC), and then retrieve everything at the port?

 

I want to communicate back and forth with a motor controller that uses ASCII strings as commands and replies. It formulates a reply to any command sent, and the reply contains exactly one termination character (which I get to specify during setup) at the very end of the reply string. It also sometimes sends a message when there was no command issued, for example a drive fault message. There is no simple and reliable way to know when the controller will talk, when it will not, and exactly how long the message will be, but we do know every message will have this termination character at the end only. I would like to interpret the entire message in my code, that is, I would like to retrieve the string of all the characters since the previous termination character up to and including the most recent termination character. I think this means I would like to have a VI that returns this message string and does not pass dataflow out until the termination character has appeared and been added to this reply string. Or, alternatively, a loop that adds entire messages to a queue of strings.

 

All the example VIs I have found seem to rely on waiting some number of milliseconds and/or knowing how many bytes to read, in order to use VISA Read.

 

So far, I am using a loop that looks for bytes in the buffer, retrieves any to append to a shift register string, and tests if there is a termination character in the string, extracting everything up to and including the termination character if so. This feels very clumsy and expensive for what must be a common task. Is this the right general approach or am I missing something way simpler?

 

I am reading about Message Based communications and Termination Characters, which approach sounds functionally similar to this, but it seems based around SCPI standards and my motor controller does not support this. In any case the Example Finder doesn't get a single hit on "Message Based".

 

Thanks!!

 

 

0 Kudos
Message 1 of 9
(4,233 Views)

I doubt that your motor controller supports "Message Based" communication, so it is useless to try to implement that solution.

 

It appears that you are on the right track with the approach you have implemented. 


cebailey wrote:

So far, I am using a loop that looks for bytes in the buffer, retrieves any to append to a shift register string, and tests if there is a termination character in the string, extracting everything up to and including the termination character if so. This feels very clumsy and expensive for what must be a common task. Is this the right general approach or am I missing something way simpler?


I'm not sure what you mean by expensive..  or clumsy... Maybe you are referring to the CPU useage, and there are tricks to reduce CPU useage..  We'd have so see your code to determine if and how to optimize it.

 

I recently posted some examples for other application, but might be useful.  I will look for it.

 

R

 

Message 2 of 9
(4,231 Views)
Solution
Accepted by topic author cebailey
It really sounds like you are making things much more difficult than it needs to be. Look at the VISA Configure Serial Port. It has an Enable Termination Character and termination Character inputs. If you wire a true (or leave it unwired) to the Enable input, a VISA Read will automatically terminate when the termination character you specify is detected. As long as the number of bytes to read is larger than the biggest string you expect to read, there is nothing else you need to do. This is how the shipping examples are set up and the discussions on termination characters. There should be nothing related to SCPI. If you don't get a terminated message in your specified timeout period, you get a timeout error.
0 Kudos
Message 3 of 9
(4,208 Views)

Dennis, thanks, this is great!

 

I see some of the examples do have inputs to termination character terminals on Configure. The detailed help on Read should say reading behavior depends on these, but I see the detailed help on Configure does say Read behavior depends on these. I didn't figure this out on my own!

 

Like I said, I thought there must be an easier way!

0 Kudos
Message 4 of 9
(4,180 Views)

Wait, if the termination character hasn't appeared yet (if the LV read happens between the start and finish of a Motor Controller write) I still have to hold the partial string and concatenate it with what gets read the next time around, so I still need much of this logic, right? I am not even sure there couldn't be TWO or more reads before the termination character appears; this could be tested with a particular setup but there don't seem to be any guarantees in the controller docs.

 

...continuing to try both using termination characters and not using them...

0 Kudos
Message 5 of 9
(4,173 Views)

You are correct.  The typical way to store the characters to concatenate them is using a shift register (and of course a While Loop).

 

You

0 Kudos
Message 6 of 9
(4,163 Views)

You are correct.  The typical way to store the characters to concatenate them is using a shift register (and of course a While Loop).

 

You could have a while loop that continues to query the serial port for data every x - ms and do so until the termination character is read.  Or to time out after an acceptable amount of time has elapsed..  Then you can decide to process the data or to re-try.

 

R

0 Kudos
Message 7 of 9
(4,163 Views)

Maybe. The VISA Read will not return until the number of specified bytes is read, the termination character is detected, or the timeout is reached. If you specify 1000 bytes when you expect 100 and the VISA timeout is 10 seconds, you will either get a complete string or the timeout. If there is data available every 1 second, you will always get a complete string - no need to concantanate. So, for the simple case of where you send a command and expect a single response, the program flow is pretty simple - a VISA Write followed by a VISA Read with some large byte count specified.

 

If you have a parallel loop where you are doing a read to check for messages that are sent by the instrument, you will have to do some synchronization with the rest of your code. You do not want this parallel read to run when another part of the program has done a write and you expect a response from this.

0 Kudos
Message 8 of 9
(4,155 Views)

>The VISA Read will not return until the number of specified bytes is read, the termination character is detected, or the timeout is reached.

 

Dennis, this sounds very useable. Is there a "LabVIEW Serial 101" lesson I missed somewhere? Though, if not, you said enough to get me started.

 

FWIW I attached the version I was working on. I only now have a controller available to test it with because PCs are treacherous, and was about to try it, but am rethinking based on your post and hope to simplify.

 

This test VI is complicated partly to be consistent with the larger application it will be part of. But it is still a huge improvement over the system as it is today, with responsibility for reading from and writing to the port buffer scattered all over the project. If you can imagine this, I actually had it working with TWO controllers daisy chained off of one COM port, but even minor changes are becoming too troublesome.

0 Kudos
Message 9 of 9
(4,147 Views)