05-03-2010 11:50 AM
Attached is an example of serial data viewed with HyperTerminal. This ASCII data is asynchronously sent via RS23 by a torque and tension sensor. The baud rate is 19,200 and the data is updated at about 52 Hz. There are no termination characters, line feeds, etc. There are two fields of data within the serial data. Where there is a “T”, tension data is in the following 5 digits. (The data is hex.) Similarly where there is a “Q”, torque data is in the following 5 digits. Usually the T’s and Q’s alternate, but not always. Sometimes depending on the activity within the sensor, there will be a number of “T” data fields before the “Q” data fields will reappear. Vice versa for the “Q” data fields.
In short, how do I manipulate the serial buffer to gather all the serial data? (I don’t know the proper serial jargon.) A fellow programmer (using CVI) tells me that I need to run the buffer so that when the system sees the leading character (T or Q) it pulls that data field out from the buffer and then it strips out the next data field, which could be T or Q data.
I’ve viewed and experimented with the various serial data examples but cannot see how they can apply to my need. Maybe I’m missing the point. In the past I’ve created serial data projects with a slower running loop in order to gather an adequate number of the ASCII data string. I then strip out the data that I want, which means that some of the serial data will be lost. However, for this project I’m tasked to not lose any of the serial data.
I need to port this project into a cRIO-9012 controller and use the controller’s serial port to acquire the serial data. I’m currently using Win-7 and LV 2009 with SP1.
Please advise how I should approach this project using LabVIEW.
Thanks,
Dave05-03-2010 12:06 PM
In the VISA Configure Serial Port vi, set the Enable Termination Char to False. Wait for 6 bytes at port, then read them. Process the data. Repeat. See snippet:
05-03-2010 12:08 PM
05-03-2010 12:41 PM
I might read all available bytes in one loop and pass the string to an analysis loop via a queue. Discard up to the first five characters until you find the Q or T character. Then break the string into data words. When you get to the end of the string you may have a partial data set. Put those remaining characters into a shift register and append the next string read from the port to them and continue with the analysis.
The use of one loop to read the bytes at the port and push them into a queue and a second loop to analyze the results allows each process to be run at the speed which works best and should prevent any loss of data. Look at the many examples and postings on Producer/Consumer.
Lynn
05-03-2010 04:18 PM
05-03-2010 04:41 PM
The problem is in your inner most for loop in the upper loop.
You get the bytes at port. Let's say you get 12Q345. Well you go through the loop and take string subset starting at 0 and length of 0. so nothing. Then starting at 0 length of 1 = "1". Starting at 0 length of 2 = "12". Starting at 0 length of 3 = "12Q". That is not equal to "Q" nor is it equal to "T". The only way you get lucky is if the Q ( or T) happens to come first.
You've made this way too complicated. You should really be using Seach String.
Read 6 bytes at port. Now you know it has a Q or a T, you just don't know where. Search the string for the Q or the T. Find the position. Discard the earlier bytes. Read x more bytes. Now concatenate the end of the first string with the x more bytes you just read and analyze that.
Right now your producer/consumer architecture isn't really doing anything. I wouldn't used the timed while loops or the Abort Loop function either.
05-03-2010 04:53 PM
Ok I'll rethink the For Loop. Do I need to use the Flush Buffer function or does the VISA Read handle the buffer?
For the sake of learning, why not use Timed While Loops?
05-03-2010 04:57 PM
No need to flush the buffer. Because once you get your bytes in synch, you shouldn't lose any bytes or messages. And flushing the buffer might accidentally cause you to lose bytes of the next message. The VISA read pulls the bytes out of the buffer as they are read.
I have seen some message threads where there are concerns about timed loops working properly on Windows based systems. The timed loops are really more intended for real-time targets.
A while loop should work just fine. The waiting for 6 bytes on every iteration will adequately throttle your loop. And if you need to pass data off to another loop for further processing, then the producer/consumer architecture will handle that timing just fine.
05-06-2010 11:04 AM
I appreciate everyone’s response. After spending more time on this that I should have, I’ve come to the conclusion that I will not be able to catch all the data; at least not with my limited skills. I think the primary problem is that the number of bytes received widely varies and I don’t think I have any control over it. For example, the number of bytes received will radically vary between 12 and 34 bytes. It’s all over the place…
I kept the timed loops because this application will use a cRIO controller. The controller crashes when I attempt to use regular while loops.
In case anyone is interested, attached are the results of this effort. This is an example of what I did to use producer/consumer architecture and the receiving of asynchronous and unstable serial data. The purpose of the string shift registers in the producer loop is to issue that last valid string when a partial string was received. Please note this was prepared using LV 2009 with SP1.
Thanks,
Dave05-06-2010 11:16 AM
Hi Dave,
I would use a state machine to parse the data as it arrives..... See this thread.....
http://forums.ni.com/ni/board/message?board.id=170&thread.id=314821&view=by_date_ascending&page=1